burger menu

This commit is contained in:
cheykrym 2025-10-05 06:00:54 +03:00
parent 5d74af5597
commit 102826ac8a
8 changed files with 46 additions and 27 deletions

View File

@ -7,7 +7,8 @@ struct TopBarView: View {
@Binding var selectedAccount: String
// @Binding var sheetType: ProfileTab.SheetType?
var accounts: [String]
var viewModel: LoginViewModel
// var viewModel: LoginViewModel
@ObservedObject var viewModel: LoginViewModel
// Привязка для управления боковым меню
@Binding var isSideMenuPresented: Bool
@ -45,7 +46,7 @@ struct TopBarView: View {
Spacer()
Button(action: { }) {
HStack(spacing: 4) {
Text(selectedAccount)
Text("@\(viewModel.username)")
.font(.headline)
.foregroundColor(.primary)
Image(systemName: "chevron.down")

View File

@ -104,7 +104,6 @@ class AuthService {
// Сохраняем токены в Keychain
KeychainService.shared.save(loginResponse.access_token, forKey: "access_token", service: username)
KeychainService.shared.save(loginResponse.refresh_token, forKey: "refresh_token", service: username)
print("loginResponse.user_id \(loginResponse.user_id)")
KeychainService.shared.save(loginResponse.user_id, forKey: "userId", service: username)
UserDefaults.standard.set(username, forKey: "currentUser")

View File

@ -1,6 +1,9 @@
{
"sourceLanguage" : "en",
"strings" : {
"@%@" : {
},
"@yourusername" : {
},

View File

@ -25,7 +25,7 @@ class LoginViewModel: ObservableObject {
}
init() {
loadStoredUser()
// loadStoredUser()
// Запускаем автологин
autoLogin()
@ -113,6 +113,6 @@ class LoginViewModel: ObservableObject {
username = defaults.string(forKey: DefaultsKeys.currentUser) ?? ""
userId = KeychainService.shared.get(forKey: DefaultsKeys.userId, service: username) ?? ""
print("username: \(username) | userId: \(userId)")
if AppConfig.DEBUG{ print("username: \(username) | userId: \(userId)")}
}
}

View File

@ -13,6 +13,12 @@ struct LoginView: View {
@Environment(\.colorScheme) private var colorScheme
@State private var isShowingRegistration = false
@FocusState private var focusedField: Field?
private enum Field: Hashable {
case username
case password
}
private var isUsernameValid: Bool {
let pattern = "^[A-Za-z0-9_]{3,32}$"
@ -29,7 +35,7 @@ struct LoginView: View {
Color.clear // чтобы поймать тап
.contentShape(Rectangle())
.onTapGesture {
hideKeyboard()
focusedField = nil
}
VStack {
@ -46,8 +52,8 @@ struct LoginView: View {
}
}
.onTapGesture {
hideKeyboard()
}
focusedField = nil
}
Spacer()
@ -57,6 +63,7 @@ struct LoginView: View {
.cornerRadius(8)
.autocapitalization(.none)
.disableAutocorrection(true)
.focused($focusedField, equals: .username)
.onChange(of: viewModel.username) { newValue in
if newValue.count > 32 {
viewModel.username = String(newValue.prefix(32))
@ -76,6 +83,7 @@ struct LoginView: View {
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.autocapitalization(.none)
.focused($focusedField, equals: .password)
.onChange(of: viewModel.password) { newValue in
if newValue.count > 32 {
viewModel.password = String(newValue.prefix(32))
@ -140,8 +148,8 @@ struct LoginView: View {
)
}
.onTapGesture {
hideKeyboard()
}
focusedField = nil
}
}
}
@ -169,10 +177,6 @@ struct LoginView: View {
UIApplication.shared.open(url)
}
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
struct LoginView_Previews: PreviewProvider {

View File

@ -22,6 +22,15 @@ struct RegistrationView: View {
@State private var showError: Bool = false
@State private var errorMessage: String = ""
@FocusState private var focusedField: Field?
private enum Field: Hashable {
case username
case password
case confirmPassword
case invite
}
private var isUsernameValid: Bool {
let pattern = "^[A-Za-z0-9_]{3,32}$"
return username.range(of: pattern, options: .regularExpression) != nil
@ -45,7 +54,7 @@ struct RegistrationView: View {
ZStack(alignment: .top) {
Color.clear
.contentShape(Rectangle())
.onTapGesture { hideKeyboard() }
.onTapGesture { focusedField = nil }
VStack(alignment: .leading, spacing: 16) {
Group {
@ -53,6 +62,7 @@ struct RegistrationView: View {
TextField(NSLocalizedString("Логин", comment: "Логин"), text: $username)
.autocapitalization(.none)
.disableAutocorrection(true)
.focused($focusedField, equals: .username)
Spacer()
if !username.isEmpty {
Image(systemName: isUsernameValid ? "checkmark.circle" : "xmark.circle")
@ -79,6 +89,7 @@ struct RegistrationView: View {
HStack {
SecureField(NSLocalizedString("Пароль", comment: "Пароль"), text: $password)
.autocapitalization(.none)
.focused($focusedField, equals: .password)
Spacer()
if !password.isEmpty {
Image(systemName: isPasswordValid ? "checkmark.circle" : "xmark.circle")
@ -104,6 +115,7 @@ struct RegistrationView: View {
HStack {
SecureField(NSLocalizedString("Подтверждение пароля", comment: "Подтверждение пароля"), text: $confirmPassword)
.autocapitalization(.none)
.focused($focusedField, equals: .confirmPassword)
Spacer()
if !confirmPassword.isEmpty {
Image(systemName: isConfirmPasswordValid ? "checkmark.circle" : "xmark.circle")
@ -132,6 +144,7 @@ struct RegistrationView: View {
.cornerRadius(8)
.autocapitalization(.none)
.disableAutocorrection(true)
.focused($focusedField, equals: .invite)
}
Button(action: registerUser) {
@ -189,14 +202,10 @@ struct RegistrationView: View {
}
private func dismissSheet() {
hideKeyboard()
focusedField = nil
isPresented = false
presentationMode.wrappedValue.dismiss()
}
private func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}

View File

@ -79,7 +79,7 @@ struct MainView: View {
.allowsHitTesting(menuOffset > 0)
// Боковое меню
SideMenuView(isPresented: $isSideMenuPresented)
SideMenuView(viewModel: viewModel, isPresented: $isSideMenuPresented)
.frame(width: menuWidth)
.offset(x: -menuWidth + menuOffset) // Новая логика смещения
.ignoresSafeArea(edges: .vertical)

View File

@ -62,6 +62,7 @@ struct SideMenuFooterButton: View {
// --- MAIN VIEW ---
struct SideMenuView: View {
@ObservedObject var viewModel: LoginViewModel
@EnvironmentObject var themeManager: ThemeManager
@Environment(\.colorScheme) var colorScheme
@Binding var isPresented: Bool
@ -132,10 +133,10 @@ struct SideMenuView: View {
}) {
HStack {
VStack(alignment: .leading) {
Text("Your Name")
Text("@\(viewModel.username)")
.font(.title3).bold()
Text("@yourusername")
.font(.footnote)
// Text("@yourusername")
// .font(.footnote)
}
.foregroundColor(.primary)
@ -172,8 +173,9 @@ struct SideMenuView: View {
}
VStack(alignment: .leading) {
Text(account.name).font(.footnote).bold() // Smaller text
Text(account.username).font(.caption2) // Smaller text
Text(account.username).font(.footnote).bold() // Smaller text
// Text(account.name).font(.footnote).bold() // Smaller text
// Text(account.username).font(.caption2) // Smaller text
}
.foregroundColor(.primary)
}
@ -253,7 +255,8 @@ struct SideMenuView: View {
struct SideMenuView_Previews: PreviewProvider {
static var previews: some View {
SideMenuView(isPresented: .constant(true))
let mockViewModel = LoginViewModel()
SideMenuView(viewModel: mockViewModel, isPresented: .constant(true))
.environmentObject(ThemeManager())
}
}