fix theme
This commit is contained in:
parent
d502a059b9
commit
8cc44b06cf
@ -173,9 +173,6 @@
|
||||
},
|
||||
"Заглушка: Обратная связь" : {
|
||||
|
||||
},
|
||||
"Заглушка: Сменить пароль" : {
|
||||
|
||||
},
|
||||
"Заглушка: Хранилище данных" : {
|
||||
|
||||
@ -354,9 +351,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Мой профиль" : {
|
||||
|
||||
},
|
||||
"Мы планируем заменить вкладку. Поделитесь, что бы вы хотели видеть здесь чаще всего." : {
|
||||
|
||||
@ -431,6 +425,9 @@
|
||||
},
|
||||
"Нет сообщений" : {
|
||||
|
||||
},
|
||||
"Новый пароль" : {
|
||||
"comment" : "Новый пароль"
|
||||
},
|
||||
"О приложении" : {
|
||||
|
||||
@ -523,9 +520,6 @@
|
||||
},
|
||||
"Произошла ошибка." : {
|
||||
|
||||
},
|
||||
"Профиль" : {
|
||||
|
||||
},
|
||||
"Публичная информация" : {
|
||||
|
||||
@ -576,6 +570,9 @@
|
||||
},
|
||||
"Спасибо!" : {
|
||||
|
||||
},
|
||||
"Старый пароль" : {
|
||||
"comment" : "Старый пароль"
|
||||
},
|
||||
"Темы" : {
|
||||
|
||||
|
||||
@ -4,9 +4,9 @@ import SwiftUI
|
||||
enum Theme: String, CaseIterable {
|
||||
case system = "System"
|
||||
case light = "Light"
|
||||
case oledDark = "Oled"
|
||||
case oledDark = "Oleg"
|
||||
// case dark = "Dark" // TODO
|
||||
|
||||
|
||||
var colorScheme: ColorScheme? {
|
||||
switch self {
|
||||
case .system:
|
||||
|
||||
74
yobble/Services/ThemeOption.swift
Normal file
74
yobble/Services/ThemeOption.swift
Normal file
@ -0,0 +1,74 @@
|
||||
import Foundation
|
||||
|
||||
enum ThemeOption: String, CaseIterable, Identifiable {
|
||||
case system
|
||||
case oledDark
|
||||
case lightTest
|
||||
case dark
|
||||
case custom
|
||||
|
||||
var id: String { rawValue }
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .system:
|
||||
return "Системная"
|
||||
case .oledDark:
|
||||
return "OLEG тёмный"
|
||||
case .dark:
|
||||
return "Тёмная"
|
||||
case .lightTest:
|
||||
return "Светлая"
|
||||
case .custom:
|
||||
return "Кастомная"
|
||||
}
|
||||
}
|
||||
|
||||
var note: String? {
|
||||
switch self {
|
||||
case .lightTest:
|
||||
return "Тестовая версия"
|
||||
case .dark, .custom:
|
||||
return "Недоступна"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var isEnabled: Bool {
|
||||
switch self {
|
||||
case .dark, .custom:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var mappedTheme: Theme? {
|
||||
switch self {
|
||||
case .system:
|
||||
return .system
|
||||
case .oledDark:
|
||||
return .oledDark
|
||||
case .lightTest:
|
||||
return .light
|
||||
case .dark, .custom:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
static var ordered: [ThemeOption] {
|
||||
[.system, .oledDark, .lightTest, .dark, .custom]
|
||||
}
|
||||
|
||||
static func option(for theme: Theme) -> ThemeOption {
|
||||
switch theme {
|
||||
case .system:
|
||||
return .system
|
||||
case .light:
|
||||
return .lightTest
|
||||
case .oledDark:
|
||||
return .oledDark
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ struct LoginView: View {
|
||||
@ObservedObject var viewModel: LoginViewModel
|
||||
@EnvironmentObject private var themeManager: ThemeManager
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
private let themeOptions = ThemeOption.ordered
|
||||
|
||||
@State private var isShowingRegistration = false
|
||||
@FocusState private var focusedField: Field?
|
||||
@ -46,7 +47,15 @@ struct LoginView: View {
|
||||
.padding()
|
||||
}
|
||||
Spacer()
|
||||
Button(action: toggleTheme) {
|
||||
Menu {
|
||||
ForEach(themeOptions) { option in
|
||||
Button(action: { selectTheme(option) }) {
|
||||
themeMenuContent(for: option)
|
||||
.opacity(option.isEnabled ? 1.0 : 0.5)
|
||||
}
|
||||
.disabled(!option.isEnabled)
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: themeIconName)
|
||||
.padding()
|
||||
}
|
||||
@ -152,11 +161,6 @@ struct LoginView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private var themeIconName: String {
|
||||
switch themeManager.theme {
|
||||
case .system:
|
||||
@ -168,14 +172,36 @@ struct LoginView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func toggleTheme() {
|
||||
themeManager.toggleTheme(from: colorScheme)
|
||||
}
|
||||
|
||||
private func openLanguageSettings() {
|
||||
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
|
||||
private var selectedThemeOption: ThemeOption {
|
||||
ThemeOption.option(for: themeManager.theme)
|
||||
}
|
||||
|
||||
private func themeMenuContent(for option: ThemeOption) -> some View {
|
||||
let isSelected = option == selectedThemeOption
|
||||
|
||||
return HStack(spacing: 8) {
|
||||
Image(systemName: isSelected ? "checkmark.circle.fill" : "circle")
|
||||
.foregroundColor(isSelected ? .accentColor : .secondary)
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(option.title)
|
||||
if let note = option.note {
|
||||
Text(note)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func selectTheme(_ option: ThemeOption) {
|
||||
guard let mappedTheme = option.mappedTheme else { return }
|
||||
themeManager.setTheme(mappedTheme)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -101,8 +101,8 @@ struct RegistrationView: View {
|
||||
.cornerRadius(8)
|
||||
.autocapitalization(.none)
|
||||
.onChange(of: password) { newValue in
|
||||
if newValue.count > 32 {
|
||||
password = String(newValue.prefix(32))
|
||||
if newValue.count > 128 {
|
||||
password = String(newValue.prefix(128))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
80
yobble/Views/Tab/Settings/ChangePasswordView.swift
Normal file
80
yobble/Views/Tab/Settings/ChangePasswordView.swift
Normal file
@ -0,0 +1,80 @@
|
||||
import SwiftUI
|
||||
|
||||
|
||||
|
||||
struct ChangePasswordView: View {
|
||||
@State private var oldPassword = ""
|
||||
@State private var newPassword = ""
|
||||
@State private var confirmPassword = ""
|
||||
|
||||
private var isOldPasswordValid: Bool {
|
||||
return oldPassword.count >= 8 && oldPassword.count <= 128
|
||||
}
|
||||
|
||||
private var isOldPasswordSame: Bool {
|
||||
return oldPassword == newPassword
|
||||
}
|
||||
|
||||
private var isNewPasswordValid: Bool {
|
||||
return newPassword.count >= 8 && newPassword.count <= 128
|
||||
}
|
||||
|
||||
private var isPasswordConfirmValid: Bool {
|
||||
return newPassword == confirmPassword
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
|
||||
HStack {
|
||||
SecureField(NSLocalizedString("Старый пароль", comment: "Старый пароль"), text: $oldPassword)
|
||||
.autocapitalization(.none)
|
||||
|
||||
if !oldPassword.isEmpty {
|
||||
Image(systemName: isOldPasswordValid ? "checkmark.circle" : "xmark.circle")
|
||||
.foregroundColor(isOldPasswordValid ? .green : .red)
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
SecureField(NSLocalizedString("Новый пароль", comment: "Новый пароль"), text: $newPassword)
|
||||
.autocapitalization(.none)
|
||||
|
||||
if !newPassword.isEmpty {
|
||||
let isAllValid = isNewPasswordValid && !isOldPasswordSame
|
||||
|
||||
Image(systemName: isAllValid ? "checkmark.circle" : "xmark.circle")
|
||||
.foregroundColor(isAllValid ? .green : .red)
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
SecureField(NSLocalizedString("Подтверждение пароля", comment: "Подтверждение пароля"), text: $confirmPassword)
|
||||
.autocapitalization(.none)
|
||||
|
||||
if !confirmPassword.isEmpty {
|
||||
Image(systemName: isPasswordConfirmValid ? "checkmark.circle" : "xmark.circle")
|
||||
.foregroundColor(isPasswordConfirmValid ? .green : .red)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isButtonEnabled: Bool {
|
||||
isPasswordConfirmValid && !isOldPasswordSame && isNewPasswordValid && isOldPasswordValid
|
||||
}
|
||||
|
||||
Button(action: {
|
||||
// Действие для сохранения профиля
|
||||
print("oldPassword: \(oldPassword)")
|
||||
print("newPassword: \(newPassword)")
|
||||
print("confirmPassword: \(confirmPassword)")
|
||||
}) {
|
||||
Text(NSLocalizedString("Применить", comment: ""))
|
||||
.background(isButtonEnabled ? Color.blue : Color.gray)
|
||||
}
|
||||
.disabled(!isButtonEnabled)
|
||||
}
|
||||
.navigationTitle(NSLocalizedString("Изменение пароля", comment: ""))
|
||||
}
|
||||
}
|
||||
@ -5,89 +5,24 @@ struct SettingsView: View {
|
||||
@EnvironmentObject private var themeManager: ThemeManager
|
||||
@AppStorage("isDarkMode") private var isDarkMode: Bool = true
|
||||
@State private var isThemeExpanded = false
|
||||
private let themeOptions: [ThemeOption] = [.system, .dark, .oledDark, .lightTest, .custom]
|
||||
|
||||
private enum ThemeOption: String, CaseIterable, Identifiable {
|
||||
case system
|
||||
case dark
|
||||
case oledDark
|
||||
case lightTest
|
||||
case custom
|
||||
|
||||
var id: String { rawValue }
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
case .system:
|
||||
return "Системная"
|
||||
case .oledDark:
|
||||
return "OLED тёмная"
|
||||
case .lightTest:
|
||||
return "Светлая"
|
||||
case .custom:
|
||||
return "Кастомная"
|
||||
case .dark:
|
||||
return "Тёмная"
|
||||
}
|
||||
}
|
||||
|
||||
var note: String? {
|
||||
switch self {
|
||||
case .lightTest:
|
||||
return "Тестовая версия"
|
||||
case .custom, .dark:
|
||||
return "Недоступна"
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var isEnabled: Bool {
|
||||
switch self {
|
||||
case .custom, .dark:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var mappedTheme: Theme? {
|
||||
switch self {
|
||||
case .system:
|
||||
return .system
|
||||
case .lightTest:
|
||||
return .light
|
||||
case .oledDark:
|
||||
return .oledDark
|
||||
case .custom, .dark:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
private let themeOptions = ThemeOption.ordered
|
||||
|
||||
private var selectedThemeOption: ThemeOption {
|
||||
switch themeManager.theme {
|
||||
case .system:
|
||||
return .system
|
||||
case .light:
|
||||
return .lightTest
|
||||
case .oledDark:
|
||||
return .oledDark
|
||||
}
|
||||
ThemeOption.option(for: themeManager.theme)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
// MARK: - Профиль
|
||||
Section(header: Text("Профиль")) {
|
||||
NavigationLink(destination: EditProfileView()) {
|
||||
Label("Мой профиль", systemImage: "person.crop.circle")
|
||||
}
|
||||
}
|
||||
// // MARK: - Профиль
|
||||
// Section(header: Text("Профиль")) {
|
||||
// NavigationLink(destination: EditProfileView()) {
|
||||
// Label("Мой профиль", systemImage: "person.crop.circle")
|
||||
// }
|
||||
// }
|
||||
|
||||
// MARK: - Безопасность
|
||||
Section(header: Text("Безопасность")) {
|
||||
NavigationLink(destination: Text("Заглушка: Сменить пароль")) {
|
||||
NavigationLink(destination: ChangePasswordView()) {
|
||||
Label("Сменить пароль", systemImage: "key")
|
||||
}
|
||||
NavigationLink(destination: Text("Заглушка: Двухфакторная аутентификация")) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user