From ff2061f86e98f8314fcea8a9d87b6b5b8b27c9ff Mon Sep 17 00:00:00 2001 From: cheykrym Date: Tue, 9 Dec 2025 23:07:45 +0300 Subject: [PATCH] update profile edit --- yobble/Resources/Localizable.xcstrings | 13 +++ .../Views/Tab/Settings/EditProfileView.swift | 90 ++++++++++++++++++- 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/yobble/Resources/Localizable.xcstrings b/yobble/Resources/Localizable.xcstrings index b57af6d..258f17f 100644 --- a/yobble/Resources/Localizable.xcstrings +++ b/yobble/Resources/Localizable.xcstrings @@ -53,6 +53,16 @@ }, "%lld" : { + }, + "%lld / %lld" : { + "localizations" : { + "ru" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$lld / %2$lld" + } + } + } }, "© 2025 Yobble Org. %@" : { @@ -717,6 +727,9 @@ }, "Изменить способ входа" : { + }, + "Изменить фото" : { + }, "Изображение" : { "comment" : "Image message placeholder" diff --git a/yobble/Views/Tab/Settings/EditProfileView.swift b/yobble/Views/Tab/Settings/EditProfileView.swift index 8f869be..652820f 100644 --- a/yobble/Views/Tab/Settings/EditProfileView.swift +++ b/yobble/Views/Tab/Settings/EditProfileView.swift @@ -3,12 +3,65 @@ import SwiftUI struct EditProfileView: View { @State private var displayName = "" @State private var description = "" + + @State private var avatarImage: UIImage? + @State private var showImagePicker = false + + private let descriptionLimit = 1024 var body: some View { Form { + Section { + HStack { + Spacer() + VStack { + if let image = avatarImage { + Image(uiImage: image) + .resizable() + .scaledToFill() + .frame(width: 120, height: 120) + .clipShape(Circle()) + } else { + Circle() + .fill(Color.secondary.opacity(0.2)) + .frame(width: 120, height: 120) + .overlay( + Image(systemName: "person.fill") + .font(.system(size: 60)) + .foregroundColor(.gray) + ) + } + Button("Изменить фото") { + showImagePicker = true + } + .padding(.top, 8) + } + Spacer() + } + } + .listRowBackground(Color(UIColor.systemGroupedBackground)) + Section(header: Text("Публичная информация")) { TextField("Отображаемое имя", text: $displayName) - TextField("Описание", text: $description) + + VStack(alignment: .leading, spacing: 5) { + Text("Описание") + .font(.caption) + .foregroundColor(.secondary) + TextEditor(text: $description) + .frame(height: 150) + .onChange(of: description) { newValue in + if newValue.count > descriptionLimit { + description = String(newValue.prefix(descriptionLimit)) + } + } + HStack { + Spacer() + Text("\(description.count) / \(descriptionLimit)") + .font(.caption) + .foregroundColor(description.count > descriptionLimit ? .red : .secondary) + } + } } Button(action: { @@ -20,5 +73,40 @@ struct EditProfileView: View { } } .navigationTitle("Редактировать профиль") + .sheet(isPresented: $showImagePicker) { + ImagePicker(image: $avatarImage) + } } } + +struct ImagePicker: UIViewControllerRepresentable { + @Binding var image: UIImage? + @Environment(\.presentationMode) private var presentationMode + + func makeUIViewController(context: Context) -> UIImagePickerController { + let picker = UIImagePickerController() + picker.delegate = context.coordinator + return picker + } + + func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { + let parent: ImagePicker + + init(_ parent: ImagePicker) { + self.parent = parent + } + + func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + if let uiImage = info[.originalImage] as? UIImage { + parent.image = uiImage + } + parent.presentationMode.wrappedValue.dismiss() + } + } +} \ No newline at end of file