From 92bdf58cded19edfa8432bccb852d5499db26b90 Mon Sep 17 00:00:00 2001 From: cheykrym Date: Wed, 10 Dec 2025 02:24:32 +0300 Subject: [PATCH] edit bio --- yobble/Network/ProfileModels.swift | 33 +++++++- yobble/Resources/Localizable.xcstrings | 6 ++ .../Views/Tab/Settings/EditProfileView.swift | 75 +++++++++++++++++-- 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/yobble/Network/ProfileModels.swift b/yobble/Network/ProfileModels.swift index 6e621d8..0e9b1a7 100644 --- a/yobble/Network/ProfileModels.swift +++ b/yobble/Network/ProfileModels.swift @@ -172,6 +172,35 @@ struct ProfilePermissionsRequestPayload: Encodable { } } -struct ProfileUpdateRequestPayload: Encodable { - let profilePermissions: ProfilePermissionsRequestPayload +extension ProfilePermissionsRequestPayload { + init(payload: ProfilePermissionsPayload) { + self.init( + isSearchable: payload.isSearchable, + allowMessageForwarding: payload.allowMessageForwarding, + allowMessagesFromNonContacts: payload.allowMessagesFromNonContacts, + showProfilePhotoToNonContacts: payload.showProfilePhotoToNonContacts, + lastSeenVisibility: payload.lastSeenVisibility, + showBioToNonContacts: payload.showBioToNonContacts, + showStoriesToNonContacts: payload.showStoriesToNonContacts, + allowServerChats: payload.allowServerChats, + publicInvitePermission: payload.publicInvitePermission, + groupInvitePermission: payload.groupInvitePermission, + callPermission: payload.callPermission, + forceAutoDeleteMessagesInPrivate: payload.forceAutoDeleteMessagesInPrivate, + maxMessageAutoDeleteSeconds: payload.maxMessageAutoDeleteSeconds, + autoDeleteAfterDays: payload.autoDeleteAfterDays + ) + } +} + +struct ProfileUpdateRequestPayload: Encodable { + let fullName: String? + let bio: String? + let profilePermissions: ProfilePermissionsRequestPayload + + init(fullName: String? = nil, bio: String? = nil, profilePermissions: ProfilePermissionsRequestPayload) { + self.fullName = fullName + self.bio = bio + self.profilePermissions = profilePermissions + } } diff --git a/yobble/Resources/Localizable.xcstrings b/yobble/Resources/Localizable.xcstrings index 349e631..9179d7f 100644 --- a/yobble/Resources/Localizable.xcstrings +++ b/yobble/Resources/Localizable.xcstrings @@ -2235,6 +2235,9 @@ } } }, + "Профиль пока не загружен. Попробуйте позже." : { + "comment" : "Profile not ready error" + }, "Прямого сброса пароля нет: сменить его можно только из настроек, уже будучи в аккаунте. Если привязана почта или другое 2FA-устройство, воспользуйтесь входом по коду - он подтвердит вашу личность и пустит в аккаунт. После входа откройте настройки → безопасность и задайте новый пароль." : { }, @@ -2540,6 +2543,9 @@ } } } + }, + "Сохранение..." : { + }, "Сохраните секретный ключ и введите код из приложения, чтобы завершить настройку." : { "comment" : "Сообщение после активации 2FA" diff --git a/yobble/Views/Tab/Settings/EditProfileView.swift b/yobble/Views/Tab/Settings/EditProfileView.swift index f7e2f61..25d600b 100644 --- a/yobble/Views/Tab/Settings/EditProfileView.swift +++ b/yobble/Views/Tab/Settings/EditProfileView.swift @@ -4,6 +4,8 @@ struct EditProfileView: View { // State for form fields @State private var displayName = "" @State private var description = "" + @State private var originalDisplayName = "" + @State private var originalDescription = "" // State for profile data and avatar @State private var profile: ProfileDataPayload? @@ -12,6 +14,7 @@ struct EditProfileView: View { // State for loading and errors @State private var isLoading = false + @State private var isSaving = false @State private var alertMessage: String? @State private var showAlert = false @@ -78,12 +81,19 @@ struct EditProfileView: View { } Button(action: { - // Действие для сохранения профиля - print("DisplayName: \(displayName)") - print("Description: \(description)") + Task { + await applyProfileChanges() + } }) { - Text("Применить") + if isSaving { + ProgressView() + .frame(maxWidth: .infinity, alignment: .center) + } else { + Text("Применить") + .frame(maxWidth: .infinity, alignment: .center) + } } + .disabled(!hasProfileChanges || isLoading || isSaving) } .navigationTitle("Профиль") .onAppear(perform: loadProfile) @@ -96,9 +106,9 @@ struct EditProfileView: View { Text(message) } - if isLoading { + if isLoading || isSaving { Color.black.opacity(0.4).ignoresSafeArea() - ProgressView("Загрузка...") + ProgressView(isLoading ? "Загрузка..." : "Сохранение...") .padding() .background(Color.secondary.colorInvert()) .cornerRadius(10) @@ -127,9 +137,13 @@ struct EditProfileView: View { do { let profile = try await profileService.fetchMyProfile() await MainActor.run { + let loadedName = profile.fullName ?? "" + let loadedBio = profile.bio ?? "" self.profile = profile - self.displayName = profile.fullName ?? "" - self.description = profile.bio ?? "" + self.displayName = loadedName + self.description = loadedBio + self.originalDisplayName = loadedName + self.originalDescription = loadedBio self.isLoading = false } } catch { @@ -141,6 +155,51 @@ struct EditProfileView: View { } } } + + private var hasProfileChanges: Bool { + displayName != originalDisplayName || description != originalDescription + } + + @MainActor + private func applyProfileChanges() async { + guard !isSaving else { return } + guard let currentProfile = profile else { + alertMessage = NSLocalizedString("Профиль пока не загружен. Попробуйте позже.", comment: "Profile not ready error") + showAlert = true + return + } + + isSaving = true + + let request = ProfileUpdateRequestPayload( + fullName: displayName, + bio: description, + profilePermissions: ProfilePermissionsRequestPayload(payload: currentProfile.profilePermissions) + ) + + do { + _ = try await profileService.updateProfile(request) + let refreshedProfile = try await profileService.fetchMyProfile() + let updatedName = refreshedProfile.fullName ?? "" + let updatedBio = refreshedProfile.bio ?? "" + profile = refreshedProfile + displayName = updatedName + description = updatedBio + originalDisplayName = updatedName + originalDescription = updatedBio + } catch { + let message: String + if let error = error as? LocalizedError, let description = error.errorDescription { + message = description + } else { + message = error.localizedDescription + } + alertMessage = message + showAlert = true + } + + isSaving = false + } } struct ImagePicker: UIViewControllerRepresentable {