ios_app_v2/yobble/Views/Login/RegistrationView.swift

214 lines
9.1 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.

//
// RegistrationView.swift
// VolnahubApp
//
// Created by cheykrym on 09/06/2025.
//
import SwiftUI
struct RegistrationView: View {
@ObservedObject var viewModel: LoginViewModel
@Environment(\.presentationMode) private var presentationMode
@State private var username: String = ""
@State private var password: String = ""
@State private var confirmPassword: String = ""
@State private var inviteCode: String = ""
@AppStorage("isDarkMode") private var isDarkMode: Bool = true
@State private var isLoading: Bool = false
@State private var showError: Bool = false
@State private var errorMessage: String = ""
private var isUsernameValid: Bool {
let pattern = "^[A-Za-z0-9_]{3,32}$"
return username.range(of: pattern, options: .regularExpression) != nil
}
private var isPasswordValid: Bool {
password.count >= 8 && password.count <= 128
}
private var isConfirmPasswordValid: Bool {
confirmPassword == password && !confirmPassword.isEmpty
}
private var isFormValid: Bool {
isUsernameValid && isPasswordValid && isConfirmPasswordValid
}
var body: some View {
NavigationView {
ScrollView {
ZStack {
Color.clear
.contentShape(Rectangle())
.onTapGesture {
hideKeyboard()
}
VStack(alignment: .leading, spacing: 16) {
Group {
HStack {
TextField(NSLocalizedString("Логин", comment: "Логин"), text: $username)
.autocapitalization(.none)
.disableAutocorrection(true)
Spacer()
if !username.isEmpty {
Image(systemName: isUsernameValid ? "checkmark.circle" : "xmark.circle")
.foregroundColor(isUsernameValid ? .green : .red)
}
}
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.disableAutocorrection(true)
.onChange(of: username) { newValue in
if newValue.count > 32 {
username = String(newValue.prefix(32))
}
}
if !isUsernameValid && !username.isEmpty {
Text(NSLocalizedString("Логин должен быть от 3 до 32 символов (английские буквы, цифры, _)", comment: "Логин должен быть от 3 до 32 символов (английские буквы, цифры, _)"))
.foregroundColor(.red)
.font(.caption)
}
HStack {
SecureField(NSLocalizedString("Пароль", comment: "Пароль"), text: $password)
.autocapitalization(.none)
Spacer()
if !password.isEmpty {
Image(systemName: isPasswordValid ? "checkmark.circle" : "xmark.circle")
.foregroundColor(isPasswordValid ? .green : .red)
}
}
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.onChange(of: password) { newValue in
if newValue.count > 32 {
password = String(newValue.prefix(32))
}
}
if !isPasswordValid && !password.isEmpty {
Text(NSLocalizedString("Пароль должен быть от 8 до 128 символов", comment: "Пароль должен быть от 6 до 32 символов"))
.foregroundColor(.red)
.font(.caption)
}
HStack {
SecureField(NSLocalizedString("Подтверждение пароля", comment: "Подтверждение пароля"), text: $confirmPassword)
.autocapitalization(.none)
Spacer()
if !confirmPassword.isEmpty {
Image(systemName: isConfirmPasswordValid ? "checkmark.circle" : "xmark.circle")
.foregroundColor(isConfirmPasswordValid ? .green : .red)
}
}
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.onChange(of: confirmPassword) { newValue in
if newValue.count > 32 {
confirmPassword = String(newValue.prefix(32))
}
}
if !isConfirmPasswordValid && !confirmPassword.isEmpty {
Text(NSLocalizedString("Пароли не совпадают", comment: "Пароли не совпадают"))
.foregroundColor(.red)
.font(.caption)
}
TextField(NSLocalizedString("Инвайт-код (необязательно)", comment: "Инвайт-код"), text: $inviteCode)
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.disableAutocorrection(true)
}
Button(action: registerUser) {
if isLoading {
ProgressView()
.padding()
.frame(maxWidth: .infinity)
.background(Color.gray.opacity(0.6))
.cornerRadius(8)
} else {
Text(NSLocalizedString("Зарегистрироваться", comment: "Зарегистрироваться"))
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(isFormValid ? Color.blue : Color.gray.opacity(0.6))
.cornerRadius(8)
}
}
.disabled(!isFormValid)
.padding(.bottom)
}
.padding()
}
.navigationBarItems(trailing:
Button(action: {
presentationMode.wrappedValue.dismiss()
}) {
Text(NSLocalizedString("Закрыть", comment: "Закрыть"))
}
)
.navigationTitle(Text(NSLocalizedString("Регистрация", comment: "Регистрация")))
.alert(isPresented: $showError) {
Alert(
title: Text(NSLocalizedString("Ошибка регистрация", comment: "Ошибка")),
message: Text(errorMessage),
dismissButton: .default(Text(NSLocalizedString("OK", comment: "")))
)
}
}
.onTapGesture {
hideKeyboard()
}
}
.onTapGesture {
hideKeyboard()
}
}
private func registerUser() {
isLoading = true
errorMessage = ""
viewModel.registerUser(username: username, password: password, invite: inviteCode.isEmpty ? nil : inviteCode) { success, message in
isLoading = false
if success {
presentationMode.wrappedValue.dismiss()
} else {
errorMessage = message ?? NSLocalizedString("Неизвестная ошибка.", comment: "")
showError = true
}
}
}
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct RegistrationView_Previews: PreviewProvider {
static var previews: some View {
let viewModel = LoginViewModel()
viewModel.isLoading = false // чтобы убрать спиннер
return RegistrationView(viewModel: viewModel)
}
}