ios_app_v2/yobble/Views/Tab/Settings/EditPrivacyView.swift

248 lines
10 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
struct EditPrivacyView: View {
@State private var profilePermissions = ProfilePermissionsState()
@State private var isLoading = false
@State private var loadError: String?
private let profileService = ProfileService()
private var privacyScopeOptions: [PrivacyScope] { PrivacyScope.allCases }
private var forceAutoDeleteBinding: Binding<Int> {
Binding(
get: { profilePermissions.maxMessageAutoDeleteSeconds ?? 30 },
set: { profilePermissions.maxMessageAutoDeleteSeconds = $0 }
)
}
private var autoDeleteAccountEnabled: Binding<Bool> {
Binding(
get: { profilePermissions.autoDeleteAfterDays != nil },
set: { newValue in
profilePermissions.autoDeleteAfterDays = newValue ? (profilePermissions.autoDeleteAfterDays ?? 30) : nil
}
)
}
private var autoDeleteAccountBinding: Binding<Int> {
Binding(
get: { profilePermissions.autoDeleteAfterDays ?? 30 },
set: { profilePermissions.autoDeleteAfterDays = min(max($0, 1), 365) }
)
}
var body: some View {
Form {
if isLoading {
Section {
ProgressView()
.frame(maxWidth: .infinity, alignment: .center)
}
}
if let loadError {
Section {
Text(loadError)
.foregroundColor(.red)
.frame(maxWidth: .infinity, alignment: .center)
}
}
if !isLoading && loadError == nil {
Section(header: Text("Профиль и поиск")) {
Toggle("Разрешить поиск профиля", isOn: $profilePermissions.isSearchable)
Toggle("Разрешить пересылку сообщений", isOn: $profilePermissions.allowMessageForwarding)
Toggle("Принимать сообщения от незнакомцев", isOn: $profilePermissions.allowMessagesFromNonContacts)
}
Section(header: Text("Видимость и контент")) {
Toggle("Показывать фото не-контактам", isOn: $profilePermissions.showProfilePhotoToNonContacts)
Toggle("Показывать био не-контактам", isOn: $profilePermissions.showBioToNonContacts)
Toggle("Показывать сторисы не-контактам", isOn: $profilePermissions.showStoriesToNonContacts)
Picker("Видимость статуса 'был в сети'", selection: $profilePermissions.lastSeenVisibility) {
ForEach(privacyScopeOptions) { scope in
Text(scope.title).tag(scope.rawValue)
}
}
.pickerStyle(.segmented)
}
Section(header: Text("Приглашения и звонки")) {
Picker("Кто может приглашать в паблики", selection: $profilePermissions.publicInvitePermission) {
ForEach(privacyScopeOptions) { scope in
Text(scope.title).tag(scope.rawValue)
}
}
.pickerStyle(.segmented)
Picker("Кто может приглашать в беседы", selection: $profilePermissions.groupInvitePermission) {
ForEach(privacyScopeOptions) { scope in
Text(scope.title).tag(scope.rawValue)
}
}
.pickerStyle(.segmented)
Picker("Кто может звонить", selection: $profilePermissions.callPermission) {
ForEach(privacyScopeOptions) { scope in
Text(scope.title).tag(scope.rawValue)
}
}
.pickerStyle(.segmented)
}
Section(header: Text("Чаты и хранение")) {
Toggle("Разрешить хранить чаты на сервере (Обычный)", isOn: $profilePermissions.allowServerChats)
Toggle("Принудительное автоудаление в ЛС (Приватный)", isOn: $profilePermissions.forceAutoDeleteMessagesInPrivate)
if profilePermissions.forceAutoDeleteMessagesInPrivate {
Stepper(value: forceAutoDeleteBinding, in: 5...86400, step: 5) {
Text("Таймер автоудаления: \(formattedAutoDeleteSeconds(forceAutoDeleteBinding.wrappedValue))")
}
}
}
Section(header: Text("Автоудаление аккаунта")) {
Toggle("Включить автоудаление аккаунта", isOn: autoDeleteAccountEnabled)
if autoDeleteAccountEnabled.wrappedValue {
Stepper(value: autoDeleteAccountBinding, in: 1...365) {
Text("Удалять аккаунт через \(autoDeleteAccountBinding.wrappedValue) дн.")
}
}
}
Section {
Button("Сохранить изменения") {
print("Параметры приватности: \(profilePermissions)")
}
.frame(maxWidth: .infinity, alignment: .center)
.disabled(isLoading)
}
Section {
Button(role: .destructive) {
profilePermissions = ProfilePermissionsState()
print("Настройки приватности сброшены к значениям по умолчанию")
} label: {
Text("Сбросить по умолчанию")
.frame(maxWidth: .infinity, alignment: .center)
}
}
}
}
.navigationTitle("Настройки приватности")
.onChange(of: profilePermissions.forceAutoDeleteMessagesInPrivate) { newValue in
if newValue {
profilePermissions.maxMessageAutoDeleteSeconds = profilePermissions.maxMessageAutoDeleteSeconds ?? 30
} else {
profilePermissions.maxMessageAutoDeleteSeconds = nil
}
}
.task {
await loadProfile()
}
}
private func formattedAutoDeleteSeconds(_ value: Int) -> String {
switch value {
case ..<60:
return "\(value) сек."
case 60..<3600:
let minutes = value / 60
return "\(minutes) мин."
default:
let hours = Double(value) / 3600.0
return String(format: "%.1f ч.", hours)
}
}
}
private enum PrivacyScope: Int, CaseIterable, Identifiable {
case everyone = 0
case contacts = 1
case nobody = 2
var id: Int { rawValue }
var title: String {
switch self {
case .everyone:
return "Все"
case .contacts:
return "Контакты"
case .nobody:
return "Никто"
}
}
}
struct ProfilePermissionsState: Codable, Equatable {
var isSearchable: Bool = true
var allowMessageForwarding: Bool = true
var allowMessagesFromNonContacts: Bool = true
var showProfilePhotoToNonContacts: Bool = true
var lastSeenVisibility: Int = PrivacyScope.everyone.rawValue
var showBioToNonContacts: Bool = true
var showStoriesToNonContacts: Bool = true
var allowServerChats: Bool = true
var publicInvitePermission: Int = PrivacyScope.everyone.rawValue
var groupInvitePermission: Int = PrivacyScope.everyone.rawValue
var callPermission: Int = PrivacyScope.everyone.rawValue
var forceAutoDeleteMessagesInPrivate: Bool = false
var maxMessageAutoDeleteSeconds: Int? = nil
var autoDeleteAfterDays: Int? = nil
}
extension ProfilePermissionsState {
init(payload: ProfilePermissionsPayload) {
self.isSearchable = payload.isSearchable
self.allowMessageForwarding = payload.allowMessageForwarding
self.allowMessagesFromNonContacts = payload.allowMessagesFromNonContacts
self.showProfilePhotoToNonContacts = payload.showProfilePhotoToNonContacts
self.lastSeenVisibility = payload.lastSeenVisibility
self.showBioToNonContacts = payload.showBioToNonContacts
self.showStoriesToNonContacts = payload.showStoriesToNonContacts
self.allowServerChats = payload.allowServerChats
self.publicInvitePermission = payload.publicInvitePermission
self.groupInvitePermission = payload.groupInvitePermission
self.callPermission = payload.callPermission
self.forceAutoDeleteMessagesInPrivate = payload.forceAutoDeleteMessagesInPrivate
self.maxMessageAutoDeleteSeconds = payload.maxMessageAutoDeleteSeconds
self.autoDeleteAfterDays = payload.autoDeleteAfterDays
}
}
private extension EditPrivacyView {
func loadProfile() async {
await MainActor.run {
if !isLoading {
isLoading = true
loadError = nil
loadError = "oleg pidor"
}
}
do {
let profile = try await profileService.fetchMyProfile()
await MainActor.run {
profilePermissions = ProfilePermissionsState(payload: profile.profilePermissions)
isLoading = false
}
} catch {
let message: String
if let error = error as? LocalizedError, let description = error.errorDescription {
message = description
} else {
message = error.localizedDescription
}
await MainActor.run {
loadError = message
isLoading = false
}
}
}
}