ios_app_v2/yobble/Views/Login/LoginView.swift

173 lines
6.0 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.

//
// LoginView.swift
// VolnahubApp
//
// Created by cheykrym on 09/06/2025.
//
import SwiftUI
struct LoginView: View {
@ObservedObject var viewModel: LoginViewModel
@AppStorage("isDarkMode") private var isDarkMode: Bool = true
@State private var isShowingRegistration = false
private var isUsernameValid: Bool {
let pattern = "^[A-Za-z0-9_]{3,32}$"
return viewModel.username.range(of: pattern, options: .regularExpression) != nil
}
private var isPasswordValid: Bool {
return viewModel.password.count >= 8 && viewModel.password.count <= 128
}
var body: some View {
ZStack {
Color.clear // чтобы поймать тап
.contentShape(Rectangle())
.onTapGesture {
hideKeyboard()
}
VStack {
HStack {
Button(action: openLanguageSettings) {
Text("🌍")
.padding()
}
Spacer()
Button(action: toggleTheme) {
Image(systemName: isDarkMode ? "moon.fill" : "sun.max.fill")
.padding()
}
}
.onTapGesture {
hideKeyboard()
}
Spacer()
TextField(NSLocalizedString("Логин", comment: ""), text: $viewModel.username)
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.disableAutocorrection(true)
.onChange(of: viewModel.username) { newValue in
if newValue.count > 32 {
viewModel.username = String(newValue.prefix(32))
}
}
// Показываем ошибку для логина
if !isUsernameValid && !viewModel.username.isEmpty {
Text(NSLocalizedString("Неверный логин", comment: "Неверный логин"))
.foregroundColor(.red)
.font(.caption)
}
// Показываем поле пароля
SecureField(NSLocalizedString("Пароль", comment: ""), text: $viewModel.password)
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.onChange(of: viewModel.password) { newValue in
if newValue.count > 32 {
viewModel.password = String(newValue.prefix(32))
}
}
// Показываем ошибку для пароля
if !isPasswordValid && !viewModel.password.isEmpty {
Text(NSLocalizedString("Неверный пароль", comment: "Неверный пароль"))
.foregroundColor(.red)
.font(.caption)
}
var isButtonEnabled: Bool {
!viewModel.isLoading && isUsernameValid && isPasswordValid
}
Button(action: {
viewModel.login()
}) {
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)
// Spacer()
// Кнопка регистрации
Button(action: {
isShowingRegistration = true
}) {
Text(NSLocalizedString("Нет аккаунта? Регистрация", comment: "Регистрация"))
.foregroundColor(.blue)
}
.padding(.top, 10)
.sheet(isPresented: $isShowingRegistration) {
RegistrationView(viewModel: viewModel)
}
Spacer()
}
.padding()
.alert(isPresented: $viewModel.showError) {
Alert(
title: Text(NSLocalizedString("Ошибка авторизации", comment: "")),
message: Text(viewModel.errorMessage),
dismissButton: .default(Text(NSLocalizedString("OK", comment: "")))
)
}
.onTapGesture {
hideKeyboard()
}
}
}
private func toggleTheme() {
isDarkMode.toggle()
}
private func openLanguageSettings() {
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
UIApplication.shared.open(url)
}
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
let viewModel = LoginViewModel()
viewModel.isLoading = false // чтобы убрать спиннер
return LoginView(viewModel: viewModel)
}
}