From e3cf3748932566fb91601e4dabd2285d0594fd95 Mon Sep 17 00:00:00 2001 From: cheykrym Date: Fri, 24 Oct 2025 11:13:47 +0300 Subject: [PATCH] add secureview --- yobble/Resources/Localizable.xcstrings | 38 ++++++++++- .../Settings/EmailSecuritySettingsView.swift | 65 +++++++++++++++++++ .../Tab/Settings/SecuritySettingsView.swift | 50 ++++++++++++++ yobble/Views/Tab/Settings/SettingsView.swift | 11 ++-- 4 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 yobble/Views/Tab/Settings/EmailSecuritySettingsView.swift create mode 100644 yobble/Views/Tab/Settings/SecuritySettingsView.swift diff --git a/yobble/Resources/Localizable.xcstrings b/yobble/Resources/Localizable.xcstrings index 49d92e8..1d2a14c 100644 --- a/yobble/Resources/Localizable.xcstrings +++ b/yobble/Resources/Localizable.xcstrings @@ -89,6 +89,12 @@ } } }, + "Email" : { + "comment" : "Заголовок экрана настроек email\nРаздел настроек безопасности для email" + }, + "Email не подтверждён. Подтвердите, чтобы активировать дополнительные проверки." : { + "comment" : "Описание необходимости подтверждения email" + }, "Fun Fest" : { "comment" : "Fun Fest", "localizations" : { @@ -220,10 +226,14 @@ "Аудио" : { "comment" : "Audio message placeholder" }, + "Аутентификация" : { + "comment" : "Раздел настроек безопасности для аутентификации" + }, "Без звука (скоро)" : { }, "Безопасность" : { + "comment" : "Заголовок экрана настроек безопасности", "localizations" : { "en" : { "stringUnit" : { @@ -427,7 +437,7 @@ } }, "Двухфакторная аутентификация" : { - "comment" : "Заголовок экрана 2FA", + "comment" : "Заголовок экрана 2FA\nПереход к настройкам двухфакторной аутентификации", "localizations" : { "en" : { "stringUnit" : { @@ -598,6 +608,9 @@ } } }, + "Защита входа" : { + "comment" : "Раздел защиты входа через email" + }, "Здесь не будут чаты" : { "localizations" : { "en" : { @@ -907,6 +920,12 @@ } } }, + "Мы отправим код подтверждения на привязанный email каждый раз при входе." : { + "comment" : "Описание работы кодов при входе" + }, + "Мы отправим письмо, как только функция будет готова." : { + "comment" : "Сообщение при недоступной отправке письма" + }, "Мы постараемся всё исправить. Напишите, что смутило." : { "comment" : "feedback: rating description 2", "localizations" : { @@ -1012,6 +1031,9 @@ } } }, + "Настройки email" : { + "comment" : "Переход к настройкам безопасности email" + }, "Настройки приватности" : { "localizations" : { "en" : { @@ -1436,6 +1458,9 @@ } } }, + "Отправить письмо подтверждения" : { + "comment" : "Кнопка отправки письма подтверждения" + }, "Отправляем..." : { "comment" : "feedback: sending state", "localizations" : { @@ -1686,6 +1711,9 @@ "Подтвердить" : { "comment" : "Кнопка подтверждения кода 2FA" }, + "Подтверждение email" : { + "comment" : "Раздел подтверждения email" + }, "Подтверждение пароля" : { "comment" : "Подтверждение пароля", "localizations" : { @@ -1757,6 +1785,9 @@ } } }, + "Получать коды на email при входе" : { + "comment" : "Переключатель отправки кодов при входе" + }, "Получить ответ от команды" : { "comment" : "feedback: contact toggle", "localizations" : { @@ -2217,7 +2248,7 @@ "comment" : "Кнопка копирования кода восстановления" }, "Скоро" : { - "comment" : "Add blocked user placeholder title\nContacts placeholder title" + "comment" : "Add blocked user placeholder title\nContacts placeholder title\nЗаголовок заглушки" }, "Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : { "comment" : "Concept tab placeholder description" @@ -2445,6 +2476,9 @@ } } }, + "Функция пока недоступна." : { + "comment" : "Сообщение заглушки" + }, "Центр авторов" : { "comment" : "Creator Center", "localizations" : { diff --git a/yobble/Views/Tab/Settings/EmailSecuritySettingsView.swift b/yobble/Views/Tab/Settings/EmailSecuritySettingsView.swift new file mode 100644 index 0000000..f93bc0f --- /dev/null +++ b/yobble/Views/Tab/Settings/EmailSecuritySettingsView.swift @@ -0,0 +1,65 @@ +import SwiftUI + +struct EmailSecuritySettingsView: View { + @State private var isLoginCodesEnabled = false + @State private var activeAlert: EmailSecurityAlert? + + var body: some View { + Form { + Section(header: Text(NSLocalizedString("Защита входа", comment: "Раздел защиты входа через email"))) { + Toggle(NSLocalizedString("Получать коды на email при входе", comment: "Переключатель отправки кодов при входе"), isOn: Binding( + get: { isLoginCodesEnabled }, + set: { _ in + activeAlert = EmailSecurityAlert( + title: NSLocalizedString("Скоро", comment: "Заголовок заглушки"), + message: NSLocalizedString("Функция пока недоступна.", comment: "Сообщение заглушки") + ) + isLoginCodesEnabled = false + } + )) + + Text(NSLocalizedString("Мы отправим код подтверждения на привязанный email каждый раз при входе.", comment: "Описание работы кодов при входе")) + .font(.footnote) + .foregroundColor(.secondary) + } + + Section(header: Text(NSLocalizedString("Подтверждение email", comment: "Раздел подтверждения email"))) { + Text(NSLocalizedString("Email не подтверждён. Подтвердите, чтобы активировать дополнительные проверки.", comment: "Описание необходимости подтверждения email")) + .font(.callout) + .foregroundColor(.secondary) + + Button(NSLocalizedString("Отправить письмо подтверждения", comment: "Кнопка отправки письма подтверждения")) { + activeAlert = EmailSecurityAlert( + title: NSLocalizedString("Скоро", comment: "Заголовок заглушки"), + message: NSLocalizedString("Мы отправим письмо, как только функция будет готова.", comment: "Сообщение при недоступной отправке письма") + ) + } + } + } + .navigationTitle(NSLocalizedString("Email", comment: "Заголовок экрана настроек email")) + .navigationBarTitleDisplayMode(.inline) + .alert(item: $activeAlert) { alert in + Alert( + title: Text(alert.title), + message: Text(alert.message), + dismissButton: .default(Text(NSLocalizedString("OK", comment: "Общий текст кнопки OK"))) + ) + } + } +} + +private struct EmailSecurityAlert: Identifiable { + let id = UUID() + let title: String + let message: String +} + +#if DEBUG +struct EmailSecuritySettingsView_Previews: PreviewProvider { + static var previews: some View { + NavigationView { + EmailSecuritySettingsView() + } + } +} +#endif diff --git a/yobble/Views/Tab/Settings/SecuritySettingsView.swift b/yobble/Views/Tab/Settings/SecuritySettingsView.swift new file mode 100644 index 0000000..d3e5a4d --- /dev/null +++ b/yobble/Views/Tab/Settings/SecuritySettingsView.swift @@ -0,0 +1,50 @@ +import SwiftUI + +struct SecuritySettingsView: View { + @ObservedObject var viewModel: LoginViewModel + @State private var isTwoFactorActive = false + @State private var isEmailSettingsActive = false + + var body: some View { + List { + Section(header: Text(NSLocalizedString("Аутентификация", comment: "Раздел настроек безопасности для аутентификации"))) { + NavigationLink(isActive: $isTwoFactorActive) { + TwoFactorAuthView() + } label: { + Label(NSLocalizedString("Двухфакторная аутентификация", comment: "Переход к настройкам двухфакторной аутентификации"), systemImage: "lock.shield") + } + } + + Section(header: Text(NSLocalizedString("Email", comment: "Раздел настроек безопасности для email"))) { + NavigationLink(isActive: $isEmailSettingsActive) { + EmailSecuritySettingsView() + } label: { + Label(NSLocalizedString("Настройки email", comment: "Переход к настройкам безопасности email"), systemImage: "envelope") + } + } + } + .listStyle(.insetGrouped) + .navigationTitle(NSLocalizedString("Безопасность", comment: "Заголовок экрана настроек безопасности")) + .navigationBarTitleDisplayMode(.inline) + .onAppear { handleTwoFactorOnboardingIfNeeded() } + .onChange(of: viewModel.onboardingDestination) { _ in + handleTwoFactorOnboardingIfNeeded() + } + } + + private func handleTwoFactorOnboardingIfNeeded() { + guard viewModel.onboardingDestination == .twoFactor else { return } + isTwoFactorActive = true + viewModel.onboardingDestination = nil + } +} + +#if DEBUG +struct SecuritySettingsView_Previews: PreviewProvider { + static var previews: some View { + NavigationView { + SecuritySettingsView(viewModel: LoginViewModel()) + } + } +} +#endif diff --git a/yobble/Views/Tab/Settings/SettingsView.swift b/yobble/Views/Tab/Settings/SettingsView.swift index 2fc9f23..2b9a83f 100644 --- a/yobble/Views/Tab/Settings/SettingsView.swift +++ b/yobble/Views/Tab/Settings/SettingsView.swift @@ -4,7 +4,7 @@ struct SettingsView: View { @ObservedObject var viewModel: LoginViewModel @EnvironmentObject private var themeManager: ThemeManager @State private var isThemeExpanded = false - @State private var isTwoFactorActive = false + @State private var isSecurityActive = false private let themeOptions = ThemeOption.ordered private var selectedThemeOption: ThemeOption { @@ -33,10 +33,10 @@ struct SettingsView: View { NavigationLink(destination: ChangePasswordView()) { Label(NSLocalizedString("Сменить пароль", comment: ""), systemImage: "key") } - NavigationLink(isActive: $isTwoFactorActive) { - TwoFactorAuthView() + NavigationLink(isActive: $isSecurityActive) { + SecuritySettingsView(viewModel: viewModel) } label: { - Label(NSLocalizedString("Двухфакторная аутентификация", comment: ""), systemImage: "lock.shield") + Label(NSLocalizedString("Безопасность", comment: ""), systemImage: "lock.shield") } NavigationLink(destination: ActiveSessionsView()) { Label(NSLocalizedString("Активные сессии", comment: ""), systemImage: "iphone") @@ -178,7 +178,6 @@ struct SettingsView: View { private extension SettingsView { func handleTwoFactorOnboardingIfNeeded() { guard viewModel.onboardingDestination == .twoFactor else { return } - isTwoFactorActive = true - viewModel.onboardingDestination = nil + isSecurityActive = true } }