import SwiftUI struct ChangePasswordView: View { @StateObject private var viewModel = ChangePasswordViewModel() @State private var oldPassword = "" @State private var newPassword = "" @State private var confirmPassword = "" @State private var isOldPasswordVisible = false @State private var isNewPasswordVisible = false @State private var isConfirmPasswordVisible = false @State private var alertData: AlertData? private var isOldPasswordValid: Bool { oldPassword.count >= 8 && oldPassword.count <= 128 } private var isOldPasswordSame: Bool { oldPassword == newPassword } private var isNewPasswordValid: Bool { newPassword.count >= 8 && newPassword.count <= 128 } private var isPasswordConfirmValid: Bool { newPassword == confirmPassword } private var isButtonEnabled: Bool { isPasswordConfirmValid && !isOldPasswordSame && isNewPasswordValid && isOldPasswordValid && !viewModel.isLoading } var body: some View { Form { Section { HStack { if isOldPasswordVisible { TextField(NSLocalizedString("Старый пароль", comment: "Старый пароль"), text: $oldPassword) .autocapitalization(.none) .disableAutocorrection(true) .textContentType(.password) .frame(maxWidth: .infinity, alignment: .leading) } else { SecureField(NSLocalizedString("Старый пароль", comment: "Старый пароль"), text: $oldPassword) .autocapitalization(.none) .disableAutocorrection(true) .textContentType(.password) .frame(maxWidth: .infinity, alignment: .leading) } Button(action: { isOldPasswordVisible.toggle() }) { Image(systemName: isOldPasswordVisible ? "eye.slash" : "eye") .foregroundColor(.gray) } .buttonStyle(PlainButtonStyle()) .padding(.horizontal, 4) if !oldPassword.isEmpty { Image(systemName: isOldPasswordValid ? "checkmark.circle" : "xmark.circle") .foregroundColor(isOldPasswordValid ? .green : .red) } } HStack { if isNewPasswordVisible { TextField(NSLocalizedString("Новый пароль", comment: "Новый пароль"), text: $newPassword) .autocapitalization(.none) .disableAutocorrection(true) .textContentType(.newPassword) .frame(maxWidth: .infinity, alignment: .leading) } else { SecureField(NSLocalizedString("Новый пароль", comment: "Новый пароль"), text: $newPassword) .autocapitalization(.none) .disableAutocorrection(true) .textContentType(.newPassword) .frame(maxWidth: .infinity, alignment: .leading) } Button(action: { isNewPasswordVisible.toggle() }) { Image(systemName: isNewPasswordVisible ? "eye.slash" : "eye") .foregroundColor(.gray) } .buttonStyle(PlainButtonStyle()) .padding(.horizontal, 4) if !newPassword.isEmpty { let isAllValid = isNewPasswordValid && !isOldPasswordSame Image(systemName: isAllValid ? "checkmark.circle" : "xmark.circle") .foregroundColor(isAllValid ? .green : .red) } } if isOldPasswordSame && !newPassword.isEmpty { Text(NSLocalizedString("Ты шо ебанутый? А ниче тот факт что новый пароль должен отличаться от старого.", comment: "")) .font(.caption) .foregroundColor(.red) } HStack { if isConfirmPasswordVisible { TextField(NSLocalizedString("Подтверждение пароля", comment: "Подтверждение пароля"), text: $confirmPassword) .autocapitalization(.none) .disableAutocorrection(true) .textContentType(.password) .frame(maxWidth: .infinity, alignment: .leading) } else { SecureField(NSLocalizedString("Подтверждение пароля", comment: "Подтверждение пароля"), text: $confirmPassword) .autocapitalization(.none) .disableAutocorrection(true) .textContentType(.password) .frame(maxWidth: .infinity, alignment: .leading) } Button(action: { isConfirmPasswordVisible.toggle() }) { Image(systemName: isConfirmPasswordVisible ? "eye.slash" : "eye") .foregroundColor(.gray) } .buttonStyle(PlainButtonStyle()) .padding(.horizontal, 4) if !confirmPassword.isEmpty { Image(systemName: isPasswordConfirmValid ? "checkmark.circle" : "xmark.circle") .foregroundColor(isPasswordConfirmValid ? .green : .red) } } if !confirmPassword.isEmpty && !isPasswordConfirmValid { Text(NSLocalizedString("Пароли не совпадают.", comment: "")) .font(.caption) .foregroundColor(.red) } } Button(action: { viewModel.changePassword(oldPassword: oldPassword, newPassword: newPassword) }) { if viewModel.isLoading { ProgressView() .progressViewStyle(CircularProgressViewStyle()) .padding() .frame(maxWidth: .infinity) .background(Color.gray.opacity(0.6)) .cornerRadius(8) } else { Text(NSLocalizedString("Применить", comment: "")) .foregroundColor(.white) .padding() .frame(maxWidth: .infinity) .background(isButtonEnabled ? Color.blue : Color.gray) .cornerRadius(8) } } .disabled(!isButtonEnabled) .buttonStyle(PlainButtonStyle()) .listRowInsets(EdgeInsets()) .listRowBackground(Color.clear) } .navigationTitle(NSLocalizedString("Изменение пароля", comment: "")) .onChange(of: viewModel.successMessage) { message in guard let message else { return } alertData = AlertData(kind: .success, message: message) } .onChange(of: viewModel.errorMessage) { message in guard let message else { return } alertData = AlertData(kind: .error, message: message) } .alert(item: $alertData) { data in Alert( title: Text(data.kind == .success ? NSLocalizedString("Пароль обновлен", comment: "") : NSLocalizedString("Ошибка", comment: "")), message: Text(data.message), dismissButton: .default(Text(NSLocalizedString("OK", comment: ""))) { switch data.kind { case .success: oldPassword = "" newPassword = "" confirmPassword = "" viewModel.successMessage = nil case .error: viewModel.errorMessage = nil } alertData = nil } ) } } } private struct AlertData: Identifiable { enum Kind { case success case error } let id = UUID() let kind: Kind let message: String }