diff --git a/Conjugate/ConjugateApp.swift b/Conjugate/ConjugateApp.swift index cba393de..9df509cd 100644 --- a/Conjugate/ConjugateApp.swift +++ b/Conjugate/ConjugateApp.swift @@ -4,9 +4,13 @@ import SwiftUI @main struct ConjugateApp: App { + @AppStorage("isDarkMode") private var isDarkMode = false + @AppStorage("increaseTextSize") private var increaseTextSize = false var body: some Scene { WindowGroup { ContentView() + .preferredColorScheme(isDarkMode ? .dark : .light) + .dynamicTypeSize(increaseTextSize ? .xLarge : .medium) } } } diff --git a/Conjugate/Views/Tabs/Settings/SettingsTab.swift b/Conjugate/Views/Tabs/Settings/SettingsTab.swift index 57468676..b052b18e 100644 --- a/Conjugate/Views/Tabs/Settings/SettingsTab.swift +++ b/Conjugate/Views/Tabs/Settings/SettingsTab.swift @@ -3,11 +3,168 @@ import SwiftUI struct SettingsTab: View { + @AppStorage("isDarkMode") private var isDarkMode = false + @AppStorage("increaseTextSize") private var increaseTextSize = false + @State private var isHighContrast = false + + var language: String { + let langId = Locale.preferredLanguages.first ?? "" + let langCode = langId.components(separatedBy: "-").first ?? "" + let langLocale = Locale(identifier: langCode) + + return langLocale.localizedString(forIdentifier: langCode)?.capitalized + ?? "" + } + var body: some View { AppNavigation { - Text("Settings") - .font(.largeTitle) - .navigationTitle("Settings") + ZStack(alignment: .top) { + Color.scribeBlue + .ignoresSafeArea() + VStack(alignment: .leading) { + Text( + NSLocalizedString( + "i18n.app.settings.menu.title", + value: "App settings", + comment: "" + ), + ) + .padding(.horizontal) + .padding(.top, 20) + .font(.title3.weight(.semibold)) + VStack(spacing: 20) { + SettingsNavigationRow( + title: NSLocalizedString( + "i18n.app.settings.menu.app_language", + value: "App language", + comment: "", + ), + caption: NSLocalizedString( + "i18n.app.settings.menu.app_language_description", + value: "Change which language the Scribe app is in.", + comment: "", + ), + value: language + ) + .onTapGesture { + if let url = URL(string: UIApplication.openSettingsURLString) { + UIApplication.shared.open(url) + } + } + SettingsToggleRow( + title: NSLocalizedString( + "i18n.app.settings.menu.app_color_mode", + value: "Dark mode", + comment: "", + ), + caption: NSLocalizedString( + "i18n.app.settings.menu.app_color_mode_description", + value: "Change the application display to dark mode.", + comment: "", + ), + isOn: $isDarkMode, + ) + SettingsToggleRow( + title: NSLocalizedString( + "i18n.app.settings.menu.increase_text_size", + value: "Increase app text size", + comment: "" + ), + caption: NSLocalizedString( + "i18n.app.settings.menu.increase_text_size_description", + value: + "Increase the size of menu texts for better readability.", + comment: "" + ), + isOn: $increaseTextSize, + ) + SettingsToggleRow( + title: NSLocalizedString( + "i18n.app.settings.menu.high_color_contrast", + value: "High color contrast", + comment: "", + ), + caption: NSLocalizedString( + "i18n.app.settings.menu.high_color_contrast_description", + value: + "Increase color contrast for improved accessibility and a clearer viewing experience.", + comment: "" + ), + isOn: $isHighContrast, + ) + } + .padding() + .frame(maxWidth: .infinity) + .background(Color(.systemBackground)) + .cornerRadius(16) + .padding(.horizontal) + } + } + .navigationTitle( + NSLocalizedString( + "i18n.app.settings.title", + value: "Settings", + comment: "" + ), + ) + } + } +} + +struct SettingsNavigationRow: View { + let title: String + let caption: String + let value: String + + var body: some View { + VStack(alignment: .leading, spacing: 6) { + + HStack { + Text(title) + .font(.body) + + Spacer() + + HStack { + Text(value) + .font(.body) + .foregroundColor(.secondary) + + Image(systemName: "chevron.right") + .foregroundColor(.secondary) + } + } + + Text(caption) + .font(.caption) + .foregroundColor(.secondary) } } } + +struct SettingsToggleRow: View { + let title: String + let caption: String + @Binding var isOn: Bool + + var body: some View { + VStack(alignment: .leading, spacing: 6) { + + HStack { + Text(title) + .font(.body) + + Spacer() + + Toggle("", isOn: $isOn) + .labelsHidden() + .tint(Color.scribeCTA) + } + + Text(caption) + .font(.caption) + .foregroundColor(.secondary) + } + + } +} diff --git a/Scribe.xcodeproj/project.pbxproj b/Scribe.xcodeproj/project.pbxproj index 2ad3e9d9..6868221e 100644 --- a/Scribe.xcodeproj/project.pbxproj +++ b/Scribe.xcodeproj/project.pbxproj @@ -673,7 +673,6 @@ E98034DE2F45AE1F006C1CDC /* LanguageData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F727382F4468960060B92D /* LanguageData.swift */; }; E98034DF2F45AE1F006C1CDC /* LanguageData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F727382F4468960060B92D /* LanguageData.swift */; }; E98034E42F45B88C006C1CDC /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98034E32F45B88C006C1CDC /* ToastView.swift */; }; - E98034E52F45B88C006C1CDC /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E98034E32F45B88C006C1CDC /* ToastView.swift */; }; E996495A2E98A12100200F53 /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = E99649592E98A12100200F53 /* GRDB */; }; E996495B2E98A31B00200F53 /* KeyboardProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 198369CB2C7980BA00C1B583 /* KeyboardProvider.swift */; }; E996495C2E98A32900200F53 /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2592742565500705659 /* KeyboardViewController.swift */; }; @@ -739,7 +738,6 @@ E9ED93872F2A3C45008D7451 /* DynamicConjugationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9ED937C2F2A3C32008D7451 /* DynamicConjugationViewController.swift */; }; E9ED93882F2A3C45008D7451 /* DynamicConjugationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9ED937C2F2A3C32008D7451 /* DynamicConjugationViewController.swift */; }; E9ED93892F2A3C45008D7451 /* DynamicConjugationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9ED937C2F2A3C32008D7451 /* DynamicConjugationViewController.swift */; }; - E9ED938A2F2A3C45008D7451 /* DynamicConjugationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9ED937C2F2A3C32008D7451 /* DynamicConjugationViewController.swift */; }; E9F7273D2F45A6CE0060B92D /* LanguageData.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F727382F4468960060B92D /* LanguageData.swift */; }; E9F7273E2F45A6DE0060B92D /* LanguageDataService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F7273C2F45856C0060B92D /* LanguageDataService.swift */; }; E9F7273F2F45A6E60060B92D /* APIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9F7273A2F457A7E0060B92D /* APIClient.swift */; }; @@ -1363,7 +1361,6 @@ /* Begin PBXFileSystemSynchronizedRootGroup section */ E943457E2F05638700DFDB20 /* Button */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (F7A17EA92F6A8BC90040B09B /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Button; sourceTree = ""; }; - E98E73BE2F20D8AA005EEDA3 /* Data */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (E98E74352F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E74362F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E74372F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E74382F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E74392F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E743A2F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E743B2F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E743C2F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E743D2F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E743E2F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E743F2F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E98E74402F20EA5E005EEDA3 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Data; sourceTree = ""; }; E98E73BF2F20D8C3005EEDA3 /* DataContracts */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = DataContracts; sourceTree = ""; }; E9B89DCD2F226757003E396F /* DataManager */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (E9B89DCE2F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DCF2F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD02F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD12F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD22F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD32F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD42F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD52F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD62F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD72F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD82F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DD92F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, E9B89DDA2F22676B003E396F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = DataManager; sourceTree = ""; }; E9DADB332EF3CF9B00702783 /* ConfirmDialog */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (F7A17EAA2F6A8BE30040B09B /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = ConfirmDialog; sourceTree = ""; }; @@ -1954,7 +1951,6 @@ D1FECBC9270E1A1500C8BC60 /* Keyboards */ = { isa = PBXGroup; children = ( - E90EF8AD2F485B91007D967C /* Data */, D190B2452741B1FE00705659 /* KeyboardsBase */, D1CCA15B2742B9F700902744 /* LanguageKeyboards */, EDC364682AE408F20001E456 /* InterfaceConstants.swift */, @@ -2192,7 +2188,6 @@ 5A8FFB6D2C5A9D9C00F4B571 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E943457E2F05638700DFDB20 /* Button */, E9DADB332EF3CF9B00702783 /* ConfirmDialog */, ); @@ -2220,7 +2215,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = German; @@ -2246,7 +2240,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = French; @@ -2272,7 +2265,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Portuguese; @@ -2316,7 +2308,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Spanish; @@ -2342,7 +2333,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Russian; @@ -2368,7 +2358,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Swedish; @@ -2394,7 +2383,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Norwegian; @@ -2420,7 +2408,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = English; @@ -2446,7 +2433,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Danish; @@ -2472,7 +2458,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Hebrew; @@ -2498,7 +2483,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Italian; @@ -2524,7 +2508,6 @@ dependencies = ( ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E98E73BF2F20D8C3005EEDA3 /* DataContracts */, ); name = Indonesian; @@ -2564,7 +2547,6 @@ F786BAC92F1E8F70003F7505 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - E90EF8AD2F485B91007D967C /* Data */, E943457E2F05638700DFDB20 /* Button */, E9DADB332EF3CF9B00702783 /* ConfirmDialog */, ); @@ -3631,81 +3613,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E97E65172F2CDD730070810A /* ESInterfaceVariables.swift in Sources */, - E9ED938A2F2A3C45008D7451 /* DynamicConjugationViewController.swift in Sources */, - F786BAD42F1E8F70003F7505 /* ThirdPartyLicense.swift in Sources */, - F786BAD52F1E8F70003F7505 /* (null) in Sources */, - F786BAD62F1E8F70003F7505 /* AppTextStyling.swift in Sources */, - E91980BE2F2F540A00B5852F /* NavigationStructure.swift in Sources */, - F786BAD72F1E8F70003F7505 /* ScribeColor.swift in Sources */, - F786BAD82F1E8F70003F7505 /* Conjugate.swift in Sources */, - F786BAD92F1E8F70003F7505 /* SettingsViewController.swift in Sources */, - F786BADA2F1E8F70003F7505 /* AboutTableData.swift in Sources */, - F786BADB2F1E8F70003F7505 /* DownloadStateManager.swift in Sources */, - F786BADC2F1E8F70003F7505 /* IDInterfaceVariables.swift in Sources */, - F786BADE2F1E8F70003F7505 /* ToolTipViewDatasource.swift in Sources */, - F786BADF2F1E8F70003F7505 /* Translate.swift in Sources */, - F786BAE32F1E8F70003F7505 /* ScribeKey.swift in Sources */, - F786BAE42F1E8F70003F7505 /* AppExtensions.swift in Sources */, - F786BAE62F1E8F70003F7505 /* FR-AZERTYInterfaceVariables.swift in Sources */, - F786BAE72F1E8F70003F7505 /* ENInterfaceVariables.swift in Sources */, - F786BAE82F1E8F70003F7505 /* InstallationVC.swift in Sources */, - F786BAE92F1E8F70003F7505 /* DEInterfaceVariables.swift in Sources */, - F786BAEA2F1E8F70003F7505 /* SettingsTableData.swift in Sources */, - F786BAEB2F1E8F70003F7505 /* InformationScreenVC.swift in Sources */, - F786BAEC2F1E8F70003F7505 /* InfoChildTableViewCell.swift in Sources */, - F786BAED2F1E8F70003F7505 /* AppUISymbols.swift in Sources */, - F786BAEE2F1E8F70003F7505 /* KeyboardViewController.swift in Sources */, - F786BAEF2F1E8F70003F7505 /* InstallationDownload.swift in Sources */, - F786BAF02F1E8F70003F7505 /* UIEdgeInsetsExtensions.swift in Sources */, - F786BAF12F1E8F70003F7505 /* (null) in Sources */, - F786BAF22F1E8F70003F7505 /* KeyboardStyling.swift in Sources */, - F786BAF32F1E8F70003F7505 /* Annotate.swift in Sources */, - F786BAF42F1E8F70003F7505 /* KeyboardBuilder.swift in Sources */, - F786BAF52F1E8F70003F7505 /* KeyboardProvider.swift in Sources */, - F786BAF62F1E8F70003F7505 /* UIColor+ScribeColors.swift in Sources */, - F786BAF72F1E8F70003F7505 /* SVInterfaceVariables.swift in Sources */, - F786BAF92F1E8F70003F7505 /* TableViewTemplateViewController.swift in Sources */, - F786BAFB2F1E8F70003F7505 /* AppDelegate.swift in Sources */, - F786BAFC2F1E8F70003F7505 /* ToolTipView.swift in Sources */, - F786BAFD2F1E8F70003F7505 /* ToolTipViewTheme.swift in Sources */, - F786BAFE2F1E8F70003F7505 /* RadioTableViewCell.swift in Sources */, - F786BAFF2F1E8F70003F7505 /* CommandVariables.swift in Sources */, - F786BB002F1E8F70003F7505 /* DownloadDataScreen.swift in Sources */, - F786BB012F1E8F70003F7505 /* Utilities.swift in Sources */, - F786BB022F1E8F70003F7505 /* BaseTableViewController.swift in Sources */, - E98034E52F45B88C006C1CDC /* ToastView.swift in Sources */, - F786BB032F1E8F70003F7505 /* DAInterfaceVariables.swift in Sources */, - F786BB052F1E8F70003F7505 /* UIDeviceExtensions.swift in Sources */, - E97E65222F2CDEC50070810A /* ESCommandVariables.swift in Sources */, - F786BB062F1E8F70003F7505 /* TipCardView.swift in Sources */, - F786BB072F1E8F70003F7505 /* InformationToolTipData.swift in Sources */, - F786BB082F1E8F70003F7505 /* ToolTipViewUpdatable.swift in Sources */, - F786BB092F1E8F70003F7505 /* RUInterfaceVariables.swift in Sources */, - F786BB0A2F1E8F70003F7505 /* ITInterfaceVariables.swift in Sources */, - F786BB0B2F1E8F70003F7505 /* PTInterfaceVariables.swift in Sources */, - F786BB0C2F1E8F70003F7505 /* HEInterfaceVariables.swift in Sources */, - F786BB0D2F1E8F70003F7505 /* AppStyling.swift in Sources */, - F786BB0E2F1E8F70003F7505 /* Plural.swift in Sources */, - F786BB0F2F1E8F70003F7505 /* InterfaceVariables.swift in Sources */, - F786BB102F1E8F70003F7505 /* CommandBar.swift in Sources */, - F786BB122F1E8F70003F7505 /* ViewThemeable.swift in Sources */, - F786BB132F1E8F70003F7505 /* ColorVariables.swift in Sources */, - F786BB142F1E8F70003F7505 /* SelectionViewTemplateViewController.swift in Sources */, - F786BB152F1E8F70003F7505 /* AboutTableViewCell.swift in Sources */, - F786BB162F1E8F70003F7505 /* InstallScreen.swift in Sources */, - F786BB182F1E8F70003F7505 /* KeyboardKeys.swift in Sources */, - F786BB192F1E8F70003F7505 /* ParentTableCellModel.swift in Sources */, - F786BB1A2F1E8F70003F7505 /* WrapperCell.swift in Sources */, - F786BB1B2F1E8F70003F7505 /* WikimediaAndScribe.swift in Sources */, - F786BB1C2F1E8F70003F7505 /* ToolTipViewDatasourceable.swift in Sources */, - F786BB1D2F1E8F70003F7505 /* KeyAltChars.swift in Sources */, - F786BB1E2F1E8F70003F7505 /* NBInterfaceVariables.swift in Sources */, - F786BB1F2F1E8F70003F7505 /* FR-QWERTYInterfaceVariables.swift in Sources */, - F786BB202F1E8F70003F7505 /* KeyAnimation.swift in Sources */, - F786BB212F1E8F70003F7505 /* AboutViewController.swift in Sources */, - F786BB222F1E8F70003F7505 /* Extensions.swift in Sources */, - F786BB232F1E8F70003F7505 /* InterfaceConstants.swift in Sources */, F7A17EBD2F6A8C230040B09B /* ContentView.swift in Sources */, F7A17EBC2F6A8C200040B09B /* ConjugateTab.swift in Sources */, F7A17EBB2F6A8C1C0040B09B /* AboutTab.swift in Sources */,