From 0f38536a17e616bdd1a1753a84a2d8efafff0a7e Mon Sep 17 00:00:00 2001 From: Damien Rivet Date: Tue, 7 Nov 2023 06:33:15 +0100 Subject: [PATCH 1/5] [#330] Add information tooltips to settings options Changed static data to constants to avoid unwanted modifications. Added localization catalog to the Scribe App. Added a shortDescription field to cell model. --- Scribe.xcodeproj/project.pbxproj | 21 ++- .../ParentTableViewCell.swift | 17 ++- Scribe/Localizable.xcstrings | 124 ++++++++++++++++++ Scribe/ParentTableCellModel.swift | 10 ++ Scribe/SettingsTab/SettingsTableData.swift | 30 +++-- Scribe/fr.lproj/AppScreen.strings | 27 ++++ Scribe/fr.lproj/LaunchScreen.strings | 1 + 7 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 Scribe/Localizable.xcstrings create mode 100644 Scribe/fr.lproj/AppScreen.strings create mode 100644 Scribe/fr.lproj/LaunchScreen.strings diff --git a/Scribe.xcodeproj/project.pbxproj b/Scribe.xcodeproj/project.pbxproj index de717464..a6eb0660 100644 --- a/Scribe.xcodeproj/project.pbxproj +++ b/Scribe.xcodeproj/project.pbxproj @@ -727,6 +727,7 @@ D1CDEDDC2A85AE9D00098546 /* NBInterfaceVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1CDED802A85A12400098546 /* NBInterfaceVariables.swift */; }; D1F0367227AAE12200CD7921 /* InterfaceVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2492741B31F00705659 /* InterfaceVariables.swift */; }; D1F0367327AAE1B400CD7921 /* CommandVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2462741B24F00705659 /* CommandVariables.swift */; }; + EDB4601B2AF9FD8200BEA967 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */; }; EDC364692AE408F20001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; EDC3646A2AE408FA0001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; EDC3646B2AE408FC0001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; @@ -967,13 +968,16 @@ D1CDED802A85A12400098546 /* NBInterfaceVariables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NBInterfaceVariables.swift; sourceTree = ""; }; D1CDED822A85A12C00098546 /* NBCommandVariables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NBCommandVariables.swift; sourceTree = ""; }; D1D8B2372AE4084D0070B817 /* Swedish.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Swedish.entitlements; sourceTree = ""; }; - EDC364682AE408F20001E456 /* InterfaceConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConstants.swift; sourceTree = ""; }; D1D8B2382AE408620070B817 /* Spanish.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Spanish.entitlements; sourceTree = ""; }; D1D8B2392AE408720070B817 /* Russian.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Russian.entitlements; sourceTree = ""; }; D1D8B23A2AE408850070B817 /* Portuguese.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Portuguese.entitlements; sourceTree = ""; }; D1D8B23B2AE4089C0070B817 /* Italian.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Italian.entitlements; sourceTree = ""; }; D1D8B23C2AE408AC0070B817 /* German.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = German.entitlements; sourceTree = ""; }; D1D8B23D2AE408C50070B817 /* French.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = French.entitlements; sourceTree = ""; }; + EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; + EDB4601C2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AppScreen.strings; sourceTree = ""; }; + EDB4601D2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = ""; }; + EDC364682AE408F20001E456 /* InterfaceConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConstants.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1213,6 +1217,7 @@ 38BD213222D5907F00C6795D /* Scribe */ = { isa = PBXGroup; children = ( + EDB4601E2AF9FFAA00BEA967 /* Utils */, 144B56F22A568AC200C2F447 /* Scribe.entitlements */, 1406B7882A2DFE4C001DF45B /* InstallationTab */, 147797B62A2CFB560044A53E /* SettingsTab */, @@ -1228,6 +1233,7 @@ 38BD213F22D5908100C6795D /* LaunchScreen.storyboard */, 38BD213D22D5908100C6795D /* Assets.xcassets */, 38BD214222D5908100C6795D /* Info.plist */, + EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */, ); path = Scribe; sourceTree = ""; @@ -1477,6 +1483,13 @@ path = Keyboards; sourceTree = ""; }; + EDB4601E2AF9FFAA00BEA967 /* Utils */ = { + isa = PBXGroup; + children = ( + ); + path = Utils; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1791,6 +1804,7 @@ knownRegions = ( en, Base, + fr, ); mainGroup = 38BD212722D5907E00C6795D; packageReferences = ( @@ -1825,6 +1839,7 @@ files = ( 38BD214122D5908100C6795D /* LaunchScreen.storyboard in Resources */, 147797B12A2CD3370044A53E /* InfoChildTableViewCell.xib in Resources */, + EDB4601B2AF9FD8200BEA967 /* Localizable.xcstrings in Resources */, 38BD213922D5907F00C6795D /* AppScreen.storyboard in Resources */, 147797AD2A2CD2F70044A53E /* ParentTableViewCell.xib in Resources */, 38BD213E22D5908100C6795D /* Assets.xcassets in Resources */, @@ -2776,6 +2791,7 @@ isa = PBXVariantGroup; children = ( 38BD213822D5907F00C6795D /* Base */, + EDB4601C2AF9FDD600BEA967 /* fr */, ); name = AppScreen.storyboard; sourceTree = ""; @@ -2784,6 +2800,7 @@ isa = PBXVariantGroup; children = ( 38BD214022D5908100C6795D /* Base */, + EDB4601D2AF9FDD600BEA967 /* fr */, ); name = LaunchScreen.storyboard; sourceTree = ""; @@ -2795,6 +2812,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -2857,6 +2875,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; diff --git a/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift b/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift index e2e1c9e7..6c41881a 100644 --- a/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift +++ b/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift @@ -144,26 +144,29 @@ extension ParentTableViewCell: UITableViewDelegate { case .specificLang: if let viewController = parentViewController?.storyboard?.instantiateViewController(identifier: "TableViewTemplateViewController") as? TableViewTemplateViewController { + // Copy base settings + var data = SettingsTableData.languageSettingsData + // Languages where we can disable accent keys. let accentKeyLanguages: [String] = ["Swedish", "German", "Spanish"] let accentKeyOptionIndex = SettingsTableData.languageSettingsData[0].section.firstIndex(where: { s in s.sectionTitle.elementsEqual("Disable accent characters") }) ?? -1 - if accentKeyLanguages.firstIndex(of: section.sectionTitle) == nil && accentKeyOptionIndex != -1 - { + + if accentKeyLanguages.firstIndex(of: section.sectionTitle) == nil && accentKeyOptionIndex != -1 { // As there are no accent keys we can remove the `Disable accent characters` option. - let accentKeySettings = SettingsTableData.languageSettingsData[0].section.remove(at: accentKeyOptionIndex) + let accentKeySettings = data[0].section.remove(at: accentKeyOptionIndex) print(accentKeySettings) - } else if accentKeyLanguages.firstIndex(of: section.sectionTitle) != nil && accentKeyOptionIndex == -1 - { - SettingsTableData.languageSettingsData[0].section.insert(Section( + } else if accentKeyLanguages.firstIndex(of: section.sectionTitle) != nil && accentKeyOptionIndex == -1 { + data[0].section.insert(Section( sectionTitle: "Disable accent characters", imageString: "info.circle", hasToggle: true, sectionState: .none(.toggleAccentCharacters) ), at: 1) } - viewController.configureTable(for: SettingsTableData.languageSettingsData, parentSection: section) + + viewController.configureTable(for: data, parentSection: section) parentViewController?.navigationController?.pushViewController(viewController, animated: true) } diff --git a/Scribe/Localizable.xcstrings b/Scribe/Localizable.xcstrings new file mode 100644 index 00000000..7b9fc7db --- /dev/null +++ b/Scribe/Localizable.xcstrings @@ -0,0 +1,124 @@ +{ + "sourceLanguage" : "en", + "strings" : { + "settings.appLanguage" : { + "comment" : "The title of the app language section", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "App language" + } + } + } + }, + "settings.appLanguage.system" : { + "comment" : "Use the system language", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "System language" + } + } + } + }, + "settings.functionality" : { + "comment" : "The title of the functionality section", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Functionality" + } + } + } + }, + "settings.functionality.autoSuggestEmoji" : { + "comment" : "Toggles the suggestion of Emoji", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Autosuggest emojis" + } + } + } + }, + "settings.installedKeyboards" : { + "comment" : "The title of the installed keyboards section", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Select installed keyboard" + } + } + } + }, + "settings.layout" : { + "comment" : "The title of the layout section", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Layout" + } + } + } + }, + "settings.layout.autoSuggestEmoji.description" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on emoji suggestions and completions for more expressive typing." + } + } + } + }, + "settings.layout.disableAccentCharacters" : { + "comment" : "Toggles accented characters for the selected keyboard", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Disable accent characters" + } + } + } + }, + "settings.layout.disableAccentCharacters.description" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Include accented letter keys on the primary keyboard layout." + } + } + } + }, + "settings.layout.periodAndComma" : { + "comment" : "Toggles period and commas for the selected keyboard", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Period and comma on ABC" + } + } + } + }, + "settings.layout.periodAndComma.description" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Include comma and period keys on the main keyboard for convenient typing." + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/Scribe/ParentTableCellModel.swift b/Scribe/ParentTableCellModel.swift index 99867cc9..6e6b17c5 100644 --- a/Scribe/ParentTableCellModel.swift +++ b/Scribe/ParentTableCellModel.swift @@ -12,10 +12,20 @@ struct ParentTableCellModel { } struct Section { + let sectionTitle: String let imageString: String let hasToggle: Bool let sectionState: SectionState + let shortDescription: String? + + init(sectionTitle: String, imageString: String, hasToggle: Bool, sectionState: SectionState, shortDescription: String? = nil) { + self.sectionTitle = sectionTitle + self.imageString = imageString + self.hasToggle = hasToggle + self.sectionState = sectionState + self.shortDescription = shortDescription + } } enum SectionState: Equatable { diff --git a/Scribe/SettingsTab/SettingsTableData.swift b/Scribe/SettingsTab/SettingsTableData.swift index 64e2fa27..fb226f1e 100644 --- a/Scribe/SettingsTab/SettingsTableData.swift +++ b/Scribe/SettingsTab/SettingsTableData.swift @@ -5,16 +5,17 @@ import Foundation struct SettingsTableData { - static var settingsTableData: [ParentTableCellModel] = [ + + static let settingsTableData: [ParentTableCellModel] = [ ParentTableCellModel( - headingTitle: "App language", + headingTitle: NSLocalizedString("settings.appLanguage", comment: "The title of the app language section"), section: [ - Section(sectionTitle: "System language", imageString: "globe", hasToggle: false, sectionState: .appLang), + Section(sectionTitle: NSLocalizedString("settings.appLanguage.system", comment: "Use the system language"), imageString: "globe", hasToggle: false, sectionState: .appLang), ], hasDynamicData: nil ), ParentTableCellModel( - headingTitle: "Select installed keyboard", + headingTitle: NSLocalizedString("settings.installedKeyboards", comment: "The title of the installed keyboards section"), section: [ // Section(sectionTitle: "All keyboards", imageString: "globe", hasToggle: false, sectionState: .specificLang("all")), ], @@ -22,33 +23,36 @@ struct SettingsTableData { ), ] - static var languageSettingsData: [ParentTableCellModel] = [ + static let languageSettingsData: [ParentTableCellModel] = [ ParentTableCellModel( - headingTitle: "Layout", + headingTitle: NSLocalizedString("settings.layout", comment: "The title of the layout section"), section: [ Section( - sectionTitle: "Period and comma on ABC", + sectionTitle: NSLocalizedString("settings.layout.periodAndComma", comment: "Toggles period and commas for the selected keyboard"), imageString: "info.circle", hasToggle: true, - sectionState: .none(.toggleCommaAndPeriod) + sectionState: .none(.toggleCommaAndPeriod), + shortDescription: NSLocalizedString("settings.layout.periodAndComma.description", comment: "") ), Section( - sectionTitle: "Disable accent characters", + sectionTitle: NSLocalizedString("settings.layout.disableAccentCharacters", comment: "Toggles accented characters for the selected keyboard"), imageString: "info.circle", hasToggle: true, - sectionState: .none(.toggleAccentCharacters) + sectionState: .none(.toggleAccentCharacters), + shortDescription: NSLocalizedString("settings.layout.disableAccentCharacters.description", comment: "") ), ], hasDynamicData: nil ), ParentTableCellModel( - headingTitle: "Functionality", + headingTitle: NSLocalizedString("settings.functionality", comment: "The title of the functionality section"), section: [ Section( - sectionTitle: "Autosuggest emojis", + sectionTitle: NSLocalizedString("settings.functionality.autoSuggestEmoji", comment: "Toggles the suggestion of Emoji"), imageString: "info.circle", hasToggle: true, - sectionState: .none(.autosuggestEmojis) + sectionState: .none(.autosuggestEmojis), + shortDescription: NSLocalizedString("settings.layout.autoSuggestEmoji.description", comment: "") ), ], hasDynamicData: nil diff --git a/Scribe/fr.lproj/AppScreen.strings b/Scribe/fr.lproj/AppScreen.strings new file mode 100644 index 00000000..d6ac91ee --- /dev/null +++ b/Scribe/fr.lproj/AppScreen.strings @@ -0,0 +1,27 @@ + +/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "3gB-ix-8Gq"; */ +"3gB-ix-8Gq.normalTitle" = "Button"; + +/* Class = "UITabBarItem"; title = "Installation"; ObjectID = "HNz-5D-1T0"; */ +"HNz-5D-1T0.title" = "Installation"; + +/* Class = "UITabBarItem"; title = "Settings"; ObjectID = "JtD-kc-GDx"; */ +"JtD-kc-GDx.title" = "Settings"; + +/* Class = "UITextView"; text = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."; ObjectID = "Q8I-Gg-Baj"; */ +"Q8I-Gg-Baj.text" = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."; + +/* Class = "UILabel"; text = "Label"; ObjectID = "QQb-Sb-zfQ"; */ +"QQb-Sb-zfQ.text" = "Label"; + +/* Class = "UITabBarItem"; title = "About"; ObjectID = "U3y-iM-H0G"; */ +"U3y-iM-H0G.title" = "About"; + +/* Class = "UITextView"; text = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."; ObjectID = "ZcW-Aa-aDz"; */ +"ZcW-Aa-aDz.text" = "Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda."; + +/* Class = "UIButton"; configuration.title = "Button"; ObjectID = "cWe-iO-9F6"; */ +"cWe-iO-9F6.configuration.title" = "Button"; + +/* Class = "UIButton"; normalTitle = "Button"; ObjectID = "cWe-iO-9F6"; */ +"cWe-iO-9F6.normalTitle" = "Button"; diff --git a/Scribe/fr.lproj/LaunchScreen.strings b/Scribe/fr.lproj/LaunchScreen.strings new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/Scribe/fr.lproj/LaunchScreen.strings @@ -0,0 +1 @@ + From 2bed3f19ecaa481a84d82ea2b2956485c83f56c0 Mon Sep 17 00:00:00 2001 From: Damien Rivet Date: Tue, 14 Nov 2023 16:14:00 +0100 Subject: [PATCH 2/5] [#330] Refactor cells and tableviews Add a base table view controller to implement similar logic between screens. --- Scribe.xcodeproj/project.pbxproj | 58 ++--- Scribe/AboutTab/AboutViewController.swift | 167 ++++++++++-- Scribe/Base.lproj/AppScreen.storyboard | 62 ++--- .../CustomChildTableView.swift | 26 -- .../InfoChildTableViewCell.swift | 42 ++- .../InfoChildTableViewCell.xib | 125 +++++---- .../ParentTableViewCell.swift | 244 ------------------ .../ParentTableViewCell.xib | 70 ----- .../TableViewTemplateViewController.swift | 53 ++-- Scribe/ParentTableCellModel.swift | 4 +- Scribe/{ => Resources}/Localizable.xcstrings | 22 ++ Scribe/SettingsTab/SettingsTableData.swift | 4 +- .../SettingsTab/SettingsViewController.swift | 107 ++++++-- Scribe/Views/BaseTableViewController.swift | 90 +++++++ 14 files changed, 550 insertions(+), 524 deletions(-) delete mode 100644 Scribe/Components/InfoChildTableViewCell/CustomChildTableView.swift delete mode 100644 Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift delete mode 100644 Scribe/Components/ParentTableViewCell/ParentTableViewCell.xib rename Scribe/{ => Resources}/Localizable.xcstrings (85%) create mode 100644 Scribe/Views/BaseTableViewController.swift diff --git a/Scribe.xcodeproj/project.pbxproj b/Scribe.xcodeproj/project.pbxproj index a6eb0660..2d8c5197 100644 --- a/Scribe.xcodeproj/project.pbxproj +++ b/Scribe.xcodeproj/project.pbxproj @@ -10,12 +10,9 @@ 140158992A430DD000D14E52 /* ENThirdPartyLicenses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140158982A430DD000D14E52 /* ENThirdPartyLicenses.swift */; }; 1401589B2A45A07200D14E52 /* ENWikimediaAndScribe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1401589A2A45A07200D14E52 /* ENWikimediaAndScribe.swift */; }; 140158A22A4EDB2200D14E52 /* TableViewTemplateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140158A12A4EDB2200D14E52 /* TableViewTemplateViewController.swift */; }; - 140158A42A4F06CA00D14E52 /* CustomChildTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140158A32A4F06CA00D14E52 /* CustomChildTableView.swift */; }; 1406B7872A2DFCDD001DF45B /* AboutTableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1406B7862A2DFCDD001DF45B /* AboutTableData.swift */; }; 1406B78C2A3209CF001DF45B /* AppExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1406B78B2A3209CF001DF45B /* AppExtensions.swift */; }; 146B70BD2A853A3800710BD4 /* SwipeableTabBarController in Frameworks */ = {isa = PBXBuildFile; productRef = 146B70BC2A853A3800710BD4 /* SwipeableTabBarController */; }; - 147797AC2A2CD2F70044A53E /* ParentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147797AA2A2CD2F70044A53E /* ParentTableViewCell.swift */; }; - 147797AD2A2CD2F70044A53E /* ParentTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 147797AB2A2CD2F70044A53E /* ParentTableViewCell.xib */; }; 147797B02A2CD3370044A53E /* InfoChildTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147797AE2A2CD3370044A53E /* InfoChildTableViewCell.swift */; }; 147797B12A2CD3370044A53E /* InfoChildTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 147797AF2A2CD3370044A53E /* InfoChildTableViewCell.xib */; }; 147797B32A2CD5AB0044A53E /* ParentTableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 147797B22A2CD5AB0044A53E /* ParentTableCellModel.swift */; }; @@ -728,6 +725,7 @@ D1F0367227AAE12200CD7921 /* InterfaceVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2492741B31F00705659 /* InterfaceVariables.swift */; }; D1F0367327AAE1B400CD7921 /* CommandVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2462741B24F00705659 /* CommandVariables.swift */; }; EDB4601B2AF9FD8200BEA967 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */; }; + EDB460212B03B3E400BEA967 /* BaseTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB460202B03B3E400BEA967 /* BaseTableViewController.swift */; }; EDC364692AE408F20001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; EDC3646A2AE408FA0001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; EDC3646B2AE408FC0001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; @@ -846,12 +844,9 @@ 140158982A430DD000D14E52 /* ENThirdPartyLicenses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ENThirdPartyLicenses.swift; sourceTree = ""; }; 1401589A2A45A07200D14E52 /* ENWikimediaAndScribe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ENWikimediaAndScribe.swift; sourceTree = ""; }; 140158A12A4EDB2200D14E52 /* TableViewTemplateViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewTemplateViewController.swift; sourceTree = ""; }; - 140158A32A4F06CA00D14E52 /* CustomChildTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomChildTableView.swift; sourceTree = ""; }; 1406B7862A2DFCDD001DF45B /* AboutTableData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutTableData.swift; sourceTree = ""; }; 1406B78B2A3209CF001DF45B /* AppExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppExtensions.swift; sourceTree = ""; }; 144B56F22A568AC200C2F447 /* Scribe.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Scribe.entitlements; sourceTree = ""; }; - 147797AA2A2CD2F70044A53E /* ParentTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentTableViewCell.swift; sourceTree = ""; }; - 147797AB2A2CD2F70044A53E /* ParentTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ParentTableViewCell.xib; sourceTree = ""; }; 147797AE2A2CD3370044A53E /* InfoChildTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoChildTableViewCell.swift; sourceTree = ""; }; 147797AF2A2CD3370044A53E /* InfoChildTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InfoChildTableViewCell.xib; sourceTree = ""; }; 147797B22A2CD5AB0044A53E /* ParentTableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentTableCellModel.swift; sourceTree = ""; }; @@ -977,6 +972,7 @@ EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; EDB4601C2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AppScreen.strings; sourceTree = ""; }; EDB4601D2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = ""; }; + EDB460202B03B3E400BEA967 /* BaseTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewController.swift; sourceTree = ""; }; EDC364682AE408F20001E456 /* InterfaceConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConstants.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1097,27 +1093,16 @@ isa = PBXGroup; children = ( 1406B7852A2DFCBE001DF45B /* InfoChildTableViewCell */, - 1406B7842A2DFCAB001DF45B /* ParentTableViewCell */, 140158A12A4EDB2200D14E52 /* TableViewTemplateViewController.swift */, ); path = Components; sourceTree = ""; }; - 1406B7842A2DFCAB001DF45B /* ParentTableViewCell */ = { - isa = PBXGroup; - children = ( - 147797AA2A2CD2F70044A53E /* ParentTableViewCell.swift */, - 147797AB2A2CD2F70044A53E /* ParentTableViewCell.xib */, - ); - path = ParentTableViewCell; - sourceTree = ""; - }; 1406B7852A2DFCBE001DF45B /* InfoChildTableViewCell */ = { isa = PBXGroup; children = ( 147797AE2A2CD3370044A53E /* InfoChildTableViewCell.swift */, 147797AF2A2CD3370044A53E /* InfoChildTableViewCell.xib */, - 140158A32A4F06CA00D14E52 /* CustomChildTableView.swift */, ); path = InfoChildTableViewCell; sourceTree = ""; @@ -1217,23 +1202,23 @@ 38BD213222D5907F00C6795D /* Scribe */ = { isa = PBXGroup; children = ( - EDB4601E2AF9FFAA00BEA967 /* Utils */, - 144B56F22A568AC200C2F447 /* Scribe.entitlements */, - 1406B7882A2DFE4C001DF45B /* InstallationTab */, - 147797B62A2CFB560044A53E /* SettingsTab */, 147797A92A2CD2B50044A53E /* AboutTab */, - D1A2DCAF27AD378F0057A10D /* AppTexts */, - 1406B7832A2DFCA2001DF45B /* Components */, - 147797B22A2CD5AB0044A53E /* ParentTableCellModel.swift */, 38BD213322D5907F00C6795D /* AppDelegate.swift */, - D17193C327AEAD7D0038660B /* AppStyling.swift */, - D1A2DCB327AD3EB50057A10D /* AppUISymbols.swift */, 1406B78B2A3209CF001DF45B /* AppExtensions.swift */, 38BD213722D5907F00C6795D /* AppScreen.storyboard */, - 38BD213F22D5908100C6795D /* LaunchScreen.storyboard */, + D17193C327AEAD7D0038660B /* AppStyling.swift */, + D1A2DCAF27AD378F0057A10D /* AppTexts */, + D1A2DCB327AD3EB50057A10D /* AppUISymbols.swift */, 38BD213D22D5908100C6795D /* Assets.xcassets */, + 1406B7832A2DFCA2001DF45B /* Components */, 38BD214222D5908100C6795D /* Info.plist */, - EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */, + 1406B7882A2DFE4C001DF45B /* InstallationTab */, + 38BD213F22D5908100C6795D /* LaunchScreen.storyboard */, + 147797B22A2CD5AB0044A53E /* ParentTableCellModel.swift */, + EDB460222B03BF7000BEA967 /* Resources */, + 144B56F22A568AC200C2F447 /* Scribe.entitlements */, + 147797B62A2CFB560044A53E /* SettingsTab */, + EDB4601F2B03B3B400BEA967 /* Views */, ); path = Scribe; sourceTree = ""; @@ -1483,11 +1468,20 @@ path = Keyboards; sourceTree = ""; }; - EDB4601E2AF9FFAA00BEA967 /* Utils */ = { + EDB4601F2B03B3B400BEA967 /* Views */ = { isa = PBXGroup; children = ( + EDB460202B03B3E400BEA967 /* BaseTableViewController.swift */, + ); + path = Views; + sourceTree = ""; + }; + EDB460222B03BF7000BEA967 /* Resources */ = { + isa = PBXGroup; + children = ( + EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */, ); - path = Utils; + path = Resources; sourceTree = ""; }; /* End PBXGroup section */ @@ -1841,7 +1835,6 @@ 147797B12A2CD3370044A53E /* InfoChildTableViewCell.xib in Resources */, EDB4601B2AF9FD8200BEA967 /* Localizable.xcstrings in Resources */, 38BD213922D5907F00C6795D /* AppScreen.storyboard in Resources */, - 147797AD2A2CD2F70044A53E /* ParentTableViewCell.xib in Resources */, 38BD213E22D5908100C6795D /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2015,12 +2008,12 @@ D1CDED792A859FB600098546 /* ENCommandVariables.swift in Sources */, 140158A22A4EDB2200D14E52 /* TableViewTemplateViewController.swift in Sources */, D1CDED7F2A85A05C00098546 /* HECommandVariables.swift in Sources */, - 147797AC2A2CD2F70044A53E /* ParentTableViewCell.swift in Sources */, 38BD213422D5907F00C6795D /* AppDelegate.swift in Sources */, 30489C1E2936DAB700B59393 /* ToolTipView.swift in Sources */, 3045396F293B9DF2003AE55B /* ToolTipViewTheme.swift in Sources */, D1F0367327AAE1B400CD7921 /* CommandVariables.swift in Sources */, D16DD3A529E78A1500FB9022 /* Utilities.swift in Sources */, + EDB460212B03B3E400BEA967 /* BaseTableViewController.swift in Sources */, D1CDED752A859DDD00098546 /* DAInterfaceVariables.swift in Sources */, D17193E827AECAE60038660B /* ESInterfaceVariables.swift in Sources */, D156BC0929CCDBE8007E7362 /* DEAppText.swift in Sources */, @@ -2042,7 +2035,6 @@ D171944927AEF7290038660B /* KeyboardKeys.swift in Sources */, 147797B32A2CD5AB0044A53E /* ParentTableCellModel.swift in Sources */, 1401589B2A45A07200D14E52 /* ENWikimediaAndScribe.swift in Sources */, - 140158A42A4F06CA00D14E52 /* CustomChildTableView.swift in Sources */, 3045396B293B9DC9003AE55B /* ToolTipViewDatasourceable.swift in Sources */, D156BC0829CCDBE8007E7362 /* DEPrivacyPolicy.swift in Sources */, D1B071A027C6A1AA00FD7DBD /* KeyAltChars.swift in Sources */, diff --git a/Scribe/AboutTab/AboutViewController.swift b/Scribe/AboutTab/AboutViewController.swift index ea52462b..d432e177 100644 --- a/Scribe/AboutTab/AboutViewController.swift +++ b/Scribe/AboutTab/AboutViewController.swift @@ -1,42 +1,45 @@ // -// AboutViewController.swift +// Copyright (C) 2023 Scribe +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . // import UIKit +import MessageUI +import StoreKit -class AboutViewController: UIViewController { - @IBOutlet var outerTable: UITableView! +final class AboutViewController: BaseTableViewController { - let tableData = AboutTableData.aboutTableData + override var dataSet: [ParentTableCellModel] { + AboutTableData.aboutTableData + } override func viewDidLoad() { super.viewDidLoad() title = "About" - - let nib = UINib(nibName: "ParentTableViewCell", bundle: nil) - outerTable.register(nib, forCellReuseIdentifier: "ParentTableViewCell") - - outerTable.dataSource = self - outerTable.delegate = self - - outerTable.separatorStyle = .none - outerTable.backgroundColor = .clear } } // MARK: UITableViewDataSource -/// Function implementation conforming to the UITableViewDataSource protocol. -extension AboutViewController: UITableViewDataSource { - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - return tableData.count - } +extension AboutViewController { - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "ParentTableViewCell", for: indexPath) as! ParentTableViewCell + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: InfoChildTableViewCell.reuseIdentifier, for: indexPath) as! InfoChildTableViewCell - cell.configureCell(for: tableData[indexPath.row]) + cell.configureCell(for: dataSet[indexPath.section].section[indexPath.row]) cell.backgroundColor = .clear cell.selectionStyle = .none @@ -47,5 +50,123 @@ extension AboutViewController: UITableViewDataSource { // MARK: UITableViewDelegate -/// Function implementation conforming to the UITableViewDelegate protocol. -extension AboutViewController: UITableViewDelegate {} +extension AboutViewController { + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let tableSection = dataSet[indexPath.section] + let section = tableSection.section[indexPath.row] + + switch section.sectionState { + case .github: + openURLString(urlString: "https://github.com/scribe-org/Scribe-iOS", withEncoding: false) + + case .matrix: + openURLString(urlString: "https://matrix.to/#/#scribe_community:matrix.org", withEncoding: true) + + case .wikimedia: + if let viewController = storyboard?.instantiateViewController(identifier: "InformationScreenVC") as? InformationScreenVC { + navigationController?.pushViewController(viewController, animated: true) + viewController.section = .wikimedia + } + + case .shareScribe: + showShareSheet() + + case .rateScribe: + showRateScribeUI() + + case .bugReport: + openURLString(urlString: "https://github.com/scribe-org/Scribe-iOS/issues", withEncoding: false) + + case .email: + showEmailUI() + + // case .appHints: + // // reset functionality + // print("Resets app hints") + + case .privacyPolicy: + if let viewController = storyboard?.instantiateViewController(identifier: "InformationScreenVC") as? InformationScreenVC { + navigationController?.pushViewController(viewController, animated: true) + viewController.section = .privacyPolicy + } + + case .licenses: + if let viewController = storyboard?.instantiateViewController(identifier: "InformationScreenVC") as? InformationScreenVC { + navigationController?.pushViewController(viewController, animated: true) + viewController.section = .licenses + } + + case .appLang: break + case .none: break + case .specificLang(_): break + } + + + if let selectedIndexPath = tableView.indexPathForSelectedRow { + tableView.deselectRow(at: selectedIndexPath, animated: false) + } + } + + private func openURLString(urlString: String, withEncoding: Bool) { + if withEncoding { + let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) + guard let encodedURLString = encodedString, let url = URL(string: encodedURLString) else { return } + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } else { + guard let url = URL(string: urlString) else { return } + UIApplication.shared.open(url, options: [:], completionHandler: nil) + } + } + + private func showRateScribeUI() { + if #available(iOS 14.0, *) { + guard let scene = UIApplication.shared.foregroundActiveScene else { return } + SKStoreReviewController.requestReview(in: scene) + } else { + let alert = UIAlertController(title: "Enjoying Scribe?", message: "Rate Scribe on the App Store.", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Continue", style: .default, handler: openScribeAppStore(alert:))) + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) + present(alert, animated: true) + } + } + + private func openScribeAppStore(alert _: UIAlertAction) { + openURLString(urlString: "itms-apps: //itunes.apple.com/app/id1596613886", withEncoding: true) + } + + private func showEmailUI() { + if MFMailComposeViewController.canSendMail() { + let mailComposeViewController = MFMailComposeViewController() + mailComposeViewController.mailComposeDelegate = self + mailComposeViewController.setToRecipients(["team@scri.be"]) + mailComposeViewController.setSubject("Hey Scribe!") + + present(mailComposeViewController, animated: true, completion: nil) + } else { + /// Show alert mentioning the email address + let alert = UIAlertController(title: "Send us an email?", message: "Reach out to us at team@scri.be", preferredStyle: .alert) + alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) + present(alert, animated: true) + } + } + + private func showShareSheet() { + let urlString = "itms-apps: //itunes.apple.com/app/id1596613886" + let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) + guard let encodedURLString = encodedString, let url = URL(string: encodedURLString) else { return } + + let shareSheetVC = UIActivityViewController(activityItems: [url], applicationActivities: nil) + + present(shareSheetVC, animated: true, completion: nil) + } +} + +// MARK: - MFMailComposeViewControllerDelegate + +extension AboutViewController: MFMailComposeViewControllerDelegate { + + func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) { + controller.dismiss(animated: true, completion: nil) + } +} diff --git a/Scribe/Base.lproj/AppScreen.storyboard b/Scribe/Base.lproj/AppScreen.storyboard index 237a5aa0..0eea8079 100644 --- a/Scribe/Base.lproj/AppScreen.storyboard +++ b/Scribe/Base.lproj/AppScreen.storyboard @@ -1,9 +1,9 @@ - + - + @@ -11,36 +11,24 @@ - + - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + - + @@ -51,7 +39,7 @@ - + @@ -171,11 +159,10 @@ - + - - + @@ -208,10 +195,10 @@ - + - + @@ -247,9 +234,8 @@ - + - @@ -420,7 +406,7 @@ - + @@ -472,13 +458,13 @@ - + - + diff --git a/Scribe/Components/InfoChildTableViewCell/CustomChildTableView.swift b/Scribe/Components/InfoChildTableViewCell/CustomChildTableView.swift deleted file mode 100644 index a0c27a75..00000000 --- a/Scribe/Components/InfoChildTableViewCell/CustomChildTableView.swift +++ /dev/null @@ -1,26 +0,0 @@ -// -// CustomChildTableView.swift -// - -import UIKit - -/// Need this class so that rows of the child table resize the parent table cell. -/// Works similar to extending the UITableView class. -/// Without this, the child table views will not be visible until we manually specify a height for parent table cell. -class CustomChildTableView: UITableView { - override var intrinsicContentSize: CGSize { - self.layoutIfNeeded() - return self.contentSize - } - - override var contentSize: CGSize { - didSet { - self.invalidateIntrinsicContentSize() - } - } - - override func reloadData() { - super.reloadData() - invalidateIntrinsicContentSize() - } -} diff --git a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift index 3b63bb90..0b71db67 100644 --- a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift +++ b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift @@ -4,10 +4,18 @@ import UIKit -class InfoChildTableViewCell: UITableViewCell { +final class InfoChildTableViewCell: UITableViewCell { + + // MARK: - Constants + + static let reuseIdentifier = String(describing: InfoChildTableViewCell.self) + + // MARK: - Properties + + @IBOutlet var containerView: UIView! @IBOutlet var titleLabel: UILabel! + @IBOutlet var descriptionLabel: UILabel! @IBOutlet var iconImageView: UIImageView! - @IBOutlet var chevronImgView: UIImageView! @IBOutlet var toggleSwitch: UISwitch! @@ -29,16 +37,42 @@ class InfoChildTableViewCell: UITableViewCell { return action } + + // MARK: - Functions func configureCell(for section: Section) { self.section = section + + selectionStyle = .none + titleLabel.text = section.sectionTitle - iconImageView.image = UIImage.availableIconImage(with: section.imageString) + + if let icon = section.imageString { + iconImageView.image = UIImage.availableIconImage(with: icon) + + containerView.addSubview(iconImageView) + + } else { + iconImageView.image = nil + + iconImageView.removeFromSuperview() + } + + if let shortDescription = section.shortDescription { + descriptionLabel.text = shortDescription + + containerView.addSubview(descriptionLabel) + } else { + descriptionLabel.text = nil + descriptionLabel.removeFromSuperview() + } if !section.hasToggle { + accessoryType = .disclosureIndicator toggleSwitch.isHidden = true } else { - chevronImgView.isHidden = true + accessoryType = .none +// chevronImgView.isHidden = true } fetchSwitchStateForCell() diff --git a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib index d22b8dfa..37516840 100644 --- a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib +++ b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib @@ -6,82 +6,105 @@ + - - - + + + - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - + + + + - + + - + - + + + + + + diff --git a/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift b/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift deleted file mode 100644 index 6c41881a..00000000 --- a/Scribe/Components/ParentTableViewCell/ParentTableViewCell.swift +++ /dev/null @@ -1,244 +0,0 @@ -// -// ParentTableViewCell.swift -// - -import MessageUI -import StoreKit -import UIKit - -class ParentTableViewCell: UITableViewCell { - @IBOutlet var titleLabel: UILabel! - @IBOutlet var innerTable: UITableView! - @IBOutlet var containerView: UIView! - - var data: ParentTableCellModel? - var parentSection: Section? - - override func awakeFromNib() { - super.awakeFromNib() - - let nib = UINib(nibName: "InfoChildTableViewCell", bundle: nil) - innerTable.register(nib, forCellReuseIdentifier: "InfoChildTableViewCell") - - innerTable.dataSource = self - innerTable.delegate = self - innerTable.rowHeight = UITableView.automaticDimension - innerTable.isScrollEnabled = false - innerTable.reloadData() - - setContainerViewUI() - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - } - - func configureCell(for data: ParentTableCellModel) { - self.data = data - titleLabel.text = data.headingTitle - - if let safeData = self.data { - if let _ = safeData.hasDynamicData { - NotificationCenter.default.addObserver(self, selector: #selector(reloadChildTable), name: .keyboardsUpdatedNotification, object: nil) - } - } - } - - func setContainerViewUI() { - containerView.layer.cornerRadius = containerView.frame.width * 0.05 - innerTable.layer.cornerRadius = innerTable.frame.width * 0.05 - innerTable.clipsToBounds = true - applyShadowEffects(elem: containerView) - } - - @objc func reloadChildTable() { - guard let data = data, - let dynamicDataState = data.hasDynamicData else { return } - - switch dynamicDataState { - case .installedKeyboards: - self.data?.section = SettingsTableData.getInstalledKeyboardsSections() - } - - DispatchQueue.main.async { - self.innerTable.reloadData() - } - } - - deinit { - NotificationCenter.default.removeObserver(self) - } -} - -// MARK: UITableViewDataSource - -/// Function implementation conforming to the UITableViewDataSource protocol. -extension ParentTableViewCell: UITableViewDataSource { - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - return data?.section.count ?? 0 - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "InfoChildTableViewCell", for: indexPath) as! InfoChildTableViewCell - - if let parentSection = parentSection { - cell.parentSection = parentSection - } - - if let data = data { - cell.configureCell(for: data.section[indexPath.row]) - } - - return cell - } -} - -// MARK: UITableViewDelegate - -/// Function implementation conforming to the UITableViewDelegate protocol. -extension ParentTableViewCell: UITableViewDelegate { - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if let section = data?.section[indexPath.row] { - switch section.sectionState { - case .github: - openURLString(urlString: "https://github.com/scribe-org/Scribe-iOS", withEncoding: false) - - case .matrix: - openURLString(urlString: "https://matrix.to/#/#scribe_community:matrix.org", withEncoding: true) - - case .wikimedia: - if let viewController = parentViewController?.storyboard?.instantiateViewController(identifier: "InformationScreenVC") as? InformationScreenVC { - parentViewController?.navigationController?.pushViewController(viewController, animated: true) - viewController.section = .wikimedia - } - - case .shareScribe: - showShareSheet() - - case .rateScribe: - showRateScribeUI() - - case .bugReport: - openURLString(urlString: "https://github.com/scribe-org/Scribe-iOS/issues", withEncoding: false) - - case .email: - showEmailUI() - -// case .appHints: -// // reset functionality -// print("Resets app hints") - - case .privacyPolicy: - if let viewController = parentViewController?.storyboard?.instantiateViewController(identifier: "InformationScreenVC") as? InformationScreenVC { - parentViewController?.navigationController?.pushViewController(viewController, animated: true) - viewController.section = .privacyPolicy - } - - case .licenses: - if let viewController = parentViewController?.storyboard?.instantiateViewController(identifier: "InformationScreenVC") as? InformationScreenVC { - parentViewController?.navigationController?.pushViewController(viewController, animated: true) - viewController.section = .licenses - } - - case .appLang: break - - case .specificLang: - if let viewController = parentViewController?.storyboard?.instantiateViewController(identifier: "TableViewTemplateViewController") as? TableViewTemplateViewController { - // Copy base settings - var data = SettingsTableData.languageSettingsData - - // Languages where we can disable accent keys. - let accentKeyLanguages: [String] = ["Swedish", "German", "Spanish"] - let accentKeyOptionIndex = SettingsTableData.languageSettingsData[0].section.firstIndex(where: { - s in s.sectionTitle.elementsEqual("Disable accent characters") - }) ?? -1 - - if accentKeyLanguages.firstIndex(of: section.sectionTitle) == nil && accentKeyOptionIndex != -1 { - // As there are no accent keys we can remove the `Disable accent characters` option. - let accentKeySettings = data[0].section.remove(at: accentKeyOptionIndex) - print(accentKeySettings) - } else if accentKeyLanguages.firstIndex(of: section.sectionTitle) != nil && accentKeyOptionIndex == -1 { - data[0].section.insert(Section( - sectionTitle: "Disable accent characters", - imageString: "info.circle", - hasToggle: true, - sectionState: .none(.toggleAccentCharacters) - ), at: 1) - } - - viewController.configureTable(for: data, parentSection: section) - - parentViewController?.navigationController?.pushViewController(viewController, animated: true) - } - - case .none: break - } - } - - if let selectedIndexPath = tableView.indexPathForSelectedRow { - tableView.deselectRow(at: selectedIndexPath, animated: false) - } - } - - func openURLString(urlString: String, withEncoding: Bool) { - if withEncoding { - let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) - guard let encodedURLString = encodedString, let url = URL(string: encodedURLString) else { return } - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } else { - guard let url = URL(string: urlString) else { return } - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - } - - func showRateScribeUI() { - if #available(iOS 14.0, *) { - guard let scene = UIApplication.shared.foregroundActiveScene else { return } - SKStoreReviewController.requestReview(in: scene) - } else { - let alert = UIAlertController(title: "Enjoying Scribe?", message: "Rate Scribe on the App Store.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Continue", style: .default, handler: openScribeAppStore(alert:))) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - parentViewController?.present(alert, animated: true) - } - } - - func openScribeAppStore(alert _: UIAlertAction) { - openURLString(urlString: "itms-apps: //itunes.apple.com/app/id1596613886", withEncoding: true) - } - - func showEmailUI() { - if MFMailComposeViewController.canSendMail() { - let mailComposeViewController = MFMailComposeViewController() - mailComposeViewController.mailComposeDelegate = self - mailComposeViewController.setToRecipients(["team@scri.be"]) - mailComposeViewController.setSubject("Hey Scribe!") - - parentViewController?.present(mailComposeViewController, animated: true, completion: nil) - } else { - /// Show alert mentioning the email address - let alert = UIAlertController(title: "Send us an email?", message: "Reach out to us at team@scri.be", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil)) - parentViewController?.present(alert, animated: true) - } - } - - func showShareSheet() { - let urlString = "itms-apps: //itunes.apple.com/app/id1596613886" - let encodedString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) - guard let encodedURLString = encodedString, let url = URL(string: encodedURLString) else { return } - - let shareSheetVC = UIActivityViewController(activityItems: [url], applicationActivities: nil) - - parentViewController?.present(shareSheetVC, animated: true, completion: nil) - } -} - -// MARK: MFMailComposeViewControllerDelegate - -/// Function implementation conforming to the MFMailComposeViewControllerDelegate protocol. -extension ParentTableViewCell: MFMailComposeViewControllerDelegate { - func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith _: MFMailComposeResult, error _: Error?) { - controller.dismiss(animated: true, completion: nil) - } -} diff --git a/Scribe/Components/ParentTableViewCell/ParentTableViewCell.xib b/Scribe/Components/ParentTableViewCell/ParentTableViewCell.xib deleted file mode 100644 index 242b0aa9..00000000 --- a/Scribe/Components/ParentTableViewCell/ParentTableViewCell.xib +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Scribe/Components/TableViewTemplateViewController.swift b/Scribe/Components/TableViewTemplateViewController.swift index 587ee0dd..171e47a5 100644 --- a/Scribe/Components/TableViewTemplateViewController.swift +++ b/Scribe/Components/TableViewTemplateViewController.swift @@ -4,7 +4,7 @@ import UIKit -class TableViewTemplateViewController: UIViewController { +final class TableViewTemplateViewController: UIViewController { @IBOutlet var mainTable: UITableView! var screenTitle: String = "" @@ -24,8 +24,6 @@ class TableViewTemplateViewController: UIViewController { func configureTable(for tableData: [ParentTableCellModel], parentSection: Section) { self.tableData = tableData self.parentSection = parentSection - - print("break") } override func viewDidLoad() { @@ -33,36 +31,61 @@ class TableViewTemplateViewController: UIViewController { title = parentSection?.sectionTitle ?? "Unknown" - let nib = UINib(nibName: "ParentTableViewCell", bundle: nil) - mainTable.register(nib, forCellReuseIdentifier: "ParentTableViewCell") - + mainTable.register(UINib(nibName: "InfoChildTableViewCell", bundle: nil), forCellReuseIdentifier: "InfoChildTableViewCell") mainTable.dataSource = self mainTable.delegate = self - + mainTable.rowHeight = UITableView.automaticDimension + mainTable.sectionHeaderHeight = 32 + mainTable.estimatedRowHeight = 250 mainTable.separatorStyle = .none mainTable.backgroundColor = .clear } } +// MARK: - UITableViewDataSource + extension TableViewTemplateViewController: UITableViewDataSource { - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - return tableData.count + + func numberOfSections(in tableView: UITableView) -> Int { + tableData.count + } + + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + tableData[section].section.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "ParentTableViewCell", for: indexPath) as! ParentTableViewCell + let cell = tableView.dequeueReusableCell(withIdentifier: "InfoChildTableViewCell", for: indexPath) as! InfoChildTableViewCell if let parentSection = parentSection { cell.parentSection = parentSection } - cell.configureCell(for: tableData[indexPath.row]) - - cell.backgroundColor = .clear - cell.selectionStyle = .none + cell.configureCell(for: tableData[indexPath.section].section[indexPath.row]) return cell } } -extension TableViewTemplateViewController: UITableViewDelegate {} +// MARK: - UITableViewDelegate + +extension TableViewTemplateViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView: UIView + + if let reusableHeaderView = tableView.headerView(forSection: section) { + headerView = reusableHeaderView + } else { + headerView = UIView(frame: CGRect(x: 0, y: 0, width: mainTable.bounds.width, height: 32)) + } + + let label = UILabel(frame: CGRect(x: 0, y: 0, width: headerView.bounds.width, height: 32)) + label.text = tableData[section].headingTitle + label.font = UIFont.preferredFont(forTextStyle: .headline) + label.textColor = .black + headerView.addSubview(label) + + return headerView + } +} diff --git a/Scribe/ParentTableCellModel.swift b/Scribe/ParentTableCellModel.swift index 6e6b17c5..b8505926 100644 --- a/Scribe/ParentTableCellModel.swift +++ b/Scribe/ParentTableCellModel.swift @@ -14,12 +14,12 @@ struct ParentTableCellModel { struct Section { let sectionTitle: String - let imageString: String + let imageString: String? let hasToggle: Bool let sectionState: SectionState let shortDescription: String? - init(sectionTitle: String, imageString: String, hasToggle: Bool, sectionState: SectionState, shortDescription: String? = nil) { + init(sectionTitle: String, imageString: String? = nil, hasToggle: Bool, sectionState: SectionState, shortDescription: String? = nil) { self.sectionTitle = sectionTitle self.imageString = imageString self.hasToggle = hasToggle diff --git a/Scribe/Localizable.xcstrings b/Scribe/Resources/Localizable.xcstrings similarity index 85% rename from Scribe/Localizable.xcstrings rename to Scribe/Resources/Localizable.xcstrings index 7b9fc7db..2560dc5e 100644 --- a/Scribe/Localizable.xcstrings +++ b/Scribe/Resources/Localizable.xcstrings @@ -118,6 +118,28 @@ } } } + }, + "settings.title" : { + "comment" : "The title for the settings screen", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + } + } + }, + "settings.title.backButton" : { + "comment" : "The back button's title for the settings screen", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" + } + } + } } }, "version" : "1.0" diff --git a/Scribe/SettingsTab/SettingsTableData.swift b/Scribe/SettingsTab/SettingsTableData.swift index fb226f1e..294d99f5 100644 --- a/Scribe/SettingsTab/SettingsTableData.swift +++ b/Scribe/SettingsTab/SettingsTableData.swift @@ -29,7 +29,6 @@ struct SettingsTableData { section: [ Section( sectionTitle: NSLocalizedString("settings.layout.periodAndComma", comment: "Toggles period and commas for the selected keyboard"), - imageString: "info.circle", hasToggle: true, sectionState: .none(.toggleCommaAndPeriod), shortDescription: NSLocalizedString("settings.layout.periodAndComma.description", comment: "") @@ -49,14 +48,13 @@ struct SettingsTableData { section: [ Section( sectionTitle: NSLocalizedString("settings.functionality.autoSuggestEmoji", comment: "Toggles the suggestion of Emoji"), - imageString: "info.circle", hasToggle: true, sectionState: .none(.autosuggestEmojis), shortDescription: NSLocalizedString("settings.layout.autoSuggestEmoji.description", comment: "") ), ], hasDynamicData: nil - ), + ) ] static func getInstalledKeyboardsSections() -> [Section] { diff --git a/Scribe/SettingsTab/SettingsViewController.swift b/Scribe/SettingsTab/SettingsViewController.swift index d32686cf..04ec052f 100644 --- a/Scribe/SettingsTab/SettingsViewController.swift +++ b/Scribe/SettingsTab/SettingsViewController.swift @@ -1,10 +1,23 @@ // -// SettingsViewController.swift +// Copyright (C) 2023 Scribe +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . // import UIKit -class SettingsViewController: UIViewController { +final class SettingsViewController: UIViewController { @IBOutlet var footerFrame: UIView! @IBOutlet var footerButton: UIButton! @@ -15,17 +28,15 @@ class SettingsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - title = "Settings" - navigationItem.backButtonTitle = "Settings" + title = NSLocalizedString("settings.title", comment: "The title for the settings screen") + navigationItem.backButtonTitle = NSLocalizedString("settings.title.backButton", comment: "The back button's title for the settings screen") - let nib = UINib(nibName: "ParentTableViewCell", bundle: nil) - parentTable.register(nib, forCellReuseIdentifier: "ParentTableViewCell") + parentTable.register(UINib(nibName: "InfoChildTableViewCell", bundle: nil), forCellReuseIdentifier: InfoChildTableViewCell.reuseIdentifier) parentTable.dataSource = self parentTable.delegate = self - - parentTable.separatorStyle = .none parentTable.backgroundColor = .clear + parentTable.sectionHeaderHeight = 32 setFooterButtonView() @@ -71,20 +82,86 @@ class SettingsViewController: UIViewController { } extension SettingsViewController: UITableViewDataSource { - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - return tableData.count + + func numberOfSections(in tableView: UITableView) -> Int { + tableData.count + } + + func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + tableData[section].section.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "ParentTableViewCell", for: indexPath) as! ParentTableViewCell + let cell = tableView.dequeueReusableCell(withIdentifier: InfoChildTableViewCell.reuseIdentifier, for: indexPath) as! InfoChildTableViewCell - cell.configureCell(for: tableData[indexPath.row]) + let section = tableData[indexPath.section] + let setting = section.section[indexPath.row] - cell.backgroundColor = .clear - cell.selectionStyle = .none + cell.configureCell(for: setting) return cell } } -extension SettingsViewController: UITableViewDelegate {} +extension SettingsViewController: UITableViewDelegate { + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + let tableSection = tableData[indexPath.section] + let section = tableSection.section[indexPath.row] + + switch section.sectionState { + case .specificLang: + if let viewController = storyboard?.instantiateViewController(identifier: "TableViewTemplateViewController") as? TableViewTemplateViewController { + // Copy base settings + var data = SettingsTableData.languageSettingsData + + // Languages where we can disable accent keys. + let accentKeyLanguages: [String] = ["Swedish", "German", "Spanish"] + let accentKeyOptionIndex = SettingsTableData.languageSettingsData[0].section.firstIndex(where: { + s in s.sectionTitle.elementsEqual("Disable accent characters") + }) ?? -1 + + if accentKeyLanguages.firstIndex(of: section.sectionTitle) == nil && accentKeyOptionIndex != -1 { + // As there are no accent keys we can remove the `Disable accent characters` option. + let accentKeySettings = data[0].section.remove(at: accentKeyOptionIndex) + print(accentKeySettings) + } else if accentKeyLanguages.firstIndex(of: section.sectionTitle) != nil && accentKeyOptionIndex == -1 { + data[0].section.insert(Section( + sectionTitle: "Disable accent characters", + imageString: "info.circle", + hasToggle: true, + sectionState: .none(.toggleAccentCharacters) + ), at: 1) + } + + viewController.configureTable(for: data, parentSection: section) + + navigationController?.pushViewController(viewController, animated: true) + } + + default: break + } + + if let selectedIndexPath = tableView.indexPathForSelectedRow { + tableView.deselectRow(at: selectedIndexPath, animated: false) + } + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + let headerView: UIView + + if let reusableHeaderView = tableView.headerView(forSection: section) { + headerView = reusableHeaderView + } else { + headerView = UIView(frame: CGRect(x: 0, y: 0, width: parentTable.bounds.width, height: 32)) + } + + let label = UILabel(frame: CGRect(x: 0, y: 0, width: headerView.bounds.width, height: 32)) + label.text = tableData[section].headingTitle + label.font = UIFont.preferredFont(forTextStyle: .headline) + label.textColor = .black + headerView.addSubview(label) + + return headerView + } +} diff --git a/Scribe/Views/BaseTableViewController.swift b/Scribe/Views/BaseTableViewController.swift new file mode 100644 index 00000000..7d219f27 --- /dev/null +++ b/Scribe/Views/BaseTableViewController.swift @@ -0,0 +1,90 @@ +// +// Copyright (C) 2023 Scribe +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import UIKit + +class BaseTableViewController: UITableViewController { + + // MARK: - Constants + + private let sectionHeaderHeight: CGFloat = 32 + + // MARK: - Properties + + var dataSet: [ParentTableCellModel] { + [] + } + + // MARK: - Initialisation + + override init(style: UITableView.Style) { + super.init(style: .insetGrouped) + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + + // MARK: - Functions + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.sectionHeaderHeight = sectionHeaderHeight + tableView.register(UINib(nibName: "InfoChildTableViewCell", bundle: nil), forCellReuseIdentifier: "InfoChildTableViewCell") + } +} + +// MARK: - UITableViewDataSource + +extension BaseTableViewController { + + override func numberOfSections(in tableView: UITableView) -> Int { + dataSet.count + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + dataSet[section].section.count + } +} + +// MARK: - UITableViewDelegate + +extension BaseTableViewController { + + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + headerView(for: section) + } + + private func headerView(for section: Int) -> UIView? { + let headerView: UIView + + if let reusableHeaderView = tableView.headerView(forSection: section) { + headerView = reusableHeaderView + } else { + headerView = UIView(frame: CGRect(x: 0, y: 0, width: tableView.bounds.width, height: sectionHeaderHeight)) + } + + let label = UILabel(frame: CGRect(x: 0, y: 0, width: headerView.bounds.width, height: sectionHeaderHeight)) + label.text = dataSet[section].headingTitle + label.font = UIFont.preferredFont(forTextStyle: .headline) + label.textColor = .black + headerView.addSubview(label) + + return headerView + } +} From 26a22b87d4867a1a1e803428b67b785451aaa364 Mon Sep 17 00:00:00 2001 From: Damien Rivet Date: Wed, 15 Nov 2023 13:37:41 +0100 Subject: [PATCH 3/5] [#330] Refactor TableViewTemplateVC to use BaseTableViewVC Additional clean up. --- Scribe/AboutTab/InformationScreenVC.swift | 1 - Scribe/Base.lproj/AppScreen.storyboard | 51 ++++------- .../TableViewTemplateViewController.swift | 91 ++++++------------- Scribe/Views/BaseTableViewController.swift | 10 -- 4 files changed, 50 insertions(+), 103 deletions(-) diff --git a/Scribe/AboutTab/InformationScreenVC.swift b/Scribe/AboutTab/InformationScreenVC.swift index d019da10..3f40d61f 100644 --- a/Scribe/AboutTab/InformationScreenVC.swift +++ b/Scribe/AboutTab/InformationScreenVC.swift @@ -15,7 +15,6 @@ class InformationScreenVC: UIViewController { @IBOutlet var iconImageView: UIImageView! var text: String = "" - var screenTitle: String = "" var section: SectionState = .privacyPolicy override func viewDidLoad() { diff --git a/Scribe/Base.lproj/AppScreen.storyboard b/Scribe/Base.lproj/AppScreen.storyboard index 0eea8079..15a5ec90 100644 --- a/Scribe/Base.lproj/AppScreen.storyboard +++ b/Scribe/Base.lproj/AppScreen.storyboard @@ -219,43 +219,13 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -434,6 +404,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Scribe/Components/TableViewTemplateViewController.swift b/Scribe/Components/TableViewTemplateViewController.swift index 171e47a5..b2b9d5c6 100644 --- a/Scribe/Components/TableViewTemplateViewController.swift +++ b/Scribe/Components/TableViewTemplateViewController.swift @@ -4,88 +4,57 @@ import UIKit -final class TableViewTemplateViewController: UIViewController { - @IBOutlet var mainTable: UITableView! +final class TableViewTemplateViewController: BaseTableViewController { - var screenTitle: String = "" - var tableData: [ParentTableCellModel] = [] - var parentSection: Section? + // MARK: - Properties - var langCode: String { - if let section = parentSection { - guard case let .specificLang(lang) = section.sectionState else { return "de" } + override var dataSet: [ParentTableCellModel] { + tableData + } + + private var tableData: [ParentTableCellModel] = [] + private var parentSection: Section? - return lang + private var langCode: String { + guard let parentSection else { + return "" } - return "" - } + guard case let .specificLang(lang) = parentSection.sectionState else { + return "de" + } - func configureTable(for tableData: [ParentTableCellModel], parentSection: Section) { - self.tableData = tableData - self.parentSection = parentSection + return lang } + // MARK: - Functions + override func viewDidLoad() { super.viewDidLoad() - title = parentSection?.sectionTitle ?? "Unknown" - - mainTable.register(UINib(nibName: "InfoChildTableViewCell", bundle: nil), forCellReuseIdentifier: "InfoChildTableViewCell") - mainTable.dataSource = self - mainTable.delegate = self - mainTable.rowHeight = UITableView.automaticDimension - mainTable.sectionHeaderHeight = 32 - mainTable.estimatedRowHeight = 250 - mainTable.separatorStyle = .none - mainTable.backgroundColor = .clear + tableView.rowHeight = UITableView.automaticDimension + tableView.estimatedRowHeight = 250 + tableView.separatorStyle = .none } -} -// MARK: - UITableViewDataSource - -extension TableViewTemplateViewController: UITableViewDataSource { + func configureTable(for tableData: [ParentTableCellModel], parentSection: Section) { + self.tableData = tableData + self.parentSection = parentSection - func numberOfSections(in tableView: UITableView) -> Int { - tableData.count + title = parentSection.sectionTitle } +} - func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { - tableData[section].section.count - } +// MARK: - UITableViewDataSource - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "InfoChildTableViewCell", for: indexPath) as! InfoChildTableViewCell +extension TableViewTemplateViewController { - if let parentSection = parentSection { - cell.parentSection = parentSection - } + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: InfoChildTableViewCell.reuseIdentifier, for: indexPath) as! InfoChildTableViewCell + cell.parentSection = parentSection cell.configureCell(for: tableData[indexPath.section].section[indexPath.row]) return cell } } - -// MARK: - UITableViewDelegate - -extension TableViewTemplateViewController: UITableViewDelegate { - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let headerView: UIView - - if let reusableHeaderView = tableView.headerView(forSection: section) { - headerView = reusableHeaderView - } else { - headerView = UIView(frame: CGRect(x: 0, y: 0, width: mainTable.bounds.width, height: 32)) - } - - let label = UILabel(frame: CGRect(x: 0, y: 0, width: headerView.bounds.width, height: 32)) - label.text = tableData[section].headingTitle - label.font = UIFont.preferredFont(forTextStyle: .headline) - label.textColor = .black - headerView.addSubview(label) - - return headerView - } -} diff --git a/Scribe/Views/BaseTableViewController.swift b/Scribe/Views/BaseTableViewController.swift index 7d219f27..a5191ca0 100644 --- a/Scribe/Views/BaseTableViewController.swift +++ b/Scribe/Views/BaseTableViewController.swift @@ -29,16 +29,6 @@ class BaseTableViewController: UITableViewController { [] } - // MARK: - Initialisation - - override init(style: UITableView.Style) { - super.init(style: .insetGrouped) - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - } - // MARK: - Functions override func viewDidLoad() { From 040dbd05cb62d88a975badfa79910092fa0ae139 Mon Sep 17 00:00:00 2001 From: Damien Rivet Date: Mon, 20 Nov 2023 09:35:49 +0100 Subject: [PATCH 4/5] [#330] Add a dedicated cell for About tab --- Scribe.xcodeproj/project.pbxproj | 16 +++ Scribe/AboutTab/AboutViewController.swift | 6 +- .../InfoChildTableViewCell.swift | 18 +--- .../InfoChildTableViewCell.xib | 101 ++++++------------ .../UITableViewCells/AboutTableViewCell.swift | 47 ++++++++ .../UITableViewCells/AboutTableViewCell.xib | 65 +++++++++++ Scribe/Resources/Localizable.xcstrings | 11 ++ Scribe/SettingsTab/SettingsTableData.swift | 1 - 8 files changed, 180 insertions(+), 85 deletions(-) create mode 100644 Scribe/Components/UITableViewCells/AboutTableViewCell.swift create mode 100644 Scribe/Components/UITableViewCells/AboutTableViewCell.xib diff --git a/Scribe.xcodeproj/project.pbxproj b/Scribe.xcodeproj/project.pbxproj index 2d8c5197..c50be3ac 100644 --- a/Scribe.xcodeproj/project.pbxproj +++ b/Scribe.xcodeproj/project.pbxproj @@ -724,6 +724,8 @@ D1CDEDDC2A85AE9D00098546 /* NBInterfaceVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1CDED802A85A12400098546 /* NBInterfaceVariables.swift */; }; D1F0367227AAE12200CD7921 /* InterfaceVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2492741B31F00705659 /* InterfaceVariables.swift */; }; D1F0367327AAE1B400CD7921 /* CommandVariables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D190B2462741B24F00705659 /* CommandVariables.swift */; }; + ED2486F32B0B4E8C0038AE6A /* AboutTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED2486F12B0B4E8C0038AE6A /* AboutTableViewCell.swift */; }; + ED2486F42B0B4E8C0038AE6A /* AboutTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = ED2486F22B0B4E8C0038AE6A /* AboutTableViewCell.xib */; }; EDB4601B2AF9FD8200BEA967 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */; }; EDB460212B03B3E400BEA967 /* BaseTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDB460202B03B3E400BEA967 /* BaseTableViewController.swift */; }; EDC364692AE408F20001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; @@ -969,6 +971,8 @@ D1D8B23B2AE4089C0070B817 /* Italian.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Italian.entitlements; sourceTree = ""; }; D1D8B23C2AE408AC0070B817 /* German.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = German.entitlements; sourceTree = ""; }; D1D8B23D2AE408C50070B817 /* French.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = French.entitlements; sourceTree = ""; }; + ED2486F12B0B4E8C0038AE6A /* AboutTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutTableViewCell.swift; sourceTree = ""; }; + ED2486F22B0B4E8C0038AE6A /* AboutTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AboutTableViewCell.xib; sourceTree = ""; }; EDB4601A2AF9FD8200BEA967 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = ""; }; EDB4601C2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/AppScreen.strings; sourceTree = ""; }; EDB4601D2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = ""; }; @@ -1092,6 +1096,7 @@ 1406B7832A2DFCA2001DF45B /* Components */ = { isa = PBXGroup; children = ( + ED2486F02B0B4E610038AE6A /* UITableViewCells */, 1406B7852A2DFCBE001DF45B /* InfoChildTableViewCell */, 140158A12A4EDB2200D14E52 /* TableViewTemplateViewController.swift */, ); @@ -1468,6 +1473,15 @@ path = Keyboards; sourceTree = ""; }; + ED2486F02B0B4E610038AE6A /* UITableViewCells */ = { + isa = PBXGroup; + children = ( + ED2486F12B0B4E8C0038AE6A /* AboutTableViewCell.swift */, + ED2486F22B0B4E8C0038AE6A /* AboutTableViewCell.xib */, + ); + path = UITableViewCells; + sourceTree = ""; + }; EDB4601F2B03B3B400BEA967 /* Views */ = { isa = PBXGroup; children = ( @@ -1834,6 +1848,7 @@ 38BD214122D5908100C6795D /* LaunchScreen.storyboard in Resources */, 147797B12A2CD3370044A53E /* InfoChildTableViewCell.xib in Resources */, EDB4601B2AF9FD8200BEA967 /* Localizable.xcstrings in Resources */, + ED2486F42B0B4E8C0038AE6A /* AboutTableViewCell.xib in Resources */, 38BD213922D5907F00C6795D /* AppScreen.storyboard in Resources */, 38BD213E22D5908100C6795D /* Assets.xcassets in Resources */, ); @@ -2030,6 +2045,7 @@ D171942027AECD170038660B /* SVCommandVariables.swift in Sources */, 30453967293B9D31003AE55B /* ViewThemeable.swift in Sources */, D1362A39274C106A00C00E48 /* ColorVariables.swift in Sources */, + ED2486F32B0B4E8C0038AE6A /* AboutTableViewCell.swift in Sources */, D1A2DCB127AD37BD0057A10D /* ENAppText.swift in Sources */, D1CDED832A85A12C00098546 /* NBCommandVariables.swift in Sources */, D171944927AEF7290038660B /* KeyboardKeys.swift in Sources */, diff --git a/Scribe/AboutTab/AboutViewController.swift b/Scribe/AboutTab/AboutViewController.swift index d432e177..41e61f47 100644 --- a/Scribe/AboutTab/AboutViewController.swift +++ b/Scribe/AboutTab/AboutViewController.swift @@ -28,7 +28,9 @@ final class AboutViewController: BaseTableViewController { override func viewDidLoad() { super.viewDidLoad() - title = "About" + title = NSLocalizedString("about.title", comment: "The title of the about tab") + + tableView.register(UINib(nibName: "AboutTableViewCell", bundle: nil), forCellReuseIdentifier: AboutTableViewCell.reuseIdentifier) } } @@ -37,7 +39,7 @@ final class AboutViewController: BaseTableViewController { extension AboutViewController { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: InfoChildTableViewCell.reuseIdentifier, for: indexPath) as! InfoChildTableViewCell + let cell = tableView.dequeueReusableCell(withIdentifier: AboutTableViewCell.reuseIdentifier, for: indexPath) as! AboutTableViewCell cell.configureCell(for: dataSet[indexPath.section].section[indexPath.row]) diff --git a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift index 0b71db67..350e5b9b 100644 --- a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift +++ b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.swift @@ -12,11 +12,8 @@ final class InfoChildTableViewCell: UITableViewCell { // MARK: - Properties - @IBOutlet var containerView: UIView! @IBOutlet var titleLabel: UILabel! @IBOutlet var descriptionLabel: UILabel! - @IBOutlet var iconImageView: UIImageView! - @IBOutlet var chevronImgView: UIImageView! @IBOutlet var toggleSwitch: UISwitch! var section: Section? @@ -47,21 +44,10 @@ final class InfoChildTableViewCell: UITableViewCell { titleLabel.text = section.sectionTitle - if let icon = section.imageString { - iconImageView.image = UIImage.availableIconImage(with: icon) - - containerView.addSubview(iconImageView) - - } else { - iconImageView.image = nil - - iconImageView.removeFromSuperview() - } - if let shortDescription = section.shortDescription { descriptionLabel.text = shortDescription - containerView.addSubview(descriptionLabel) + contentView.addSubview(descriptionLabel) } else { descriptionLabel.text = nil descriptionLabel.removeFromSuperview() @@ -72,7 +58,7 @@ final class InfoChildTableViewCell: UITableViewCell { toggleSwitch.isHidden = true } else { accessoryType = .none -// chevronImgView.isHidden = true + toggleSwitch.isHidden = false } fetchSwitchStateForCell() diff --git a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib index 37516840..a89771bf 100644 --- a/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib +++ b/Scribe/Components/InfoChildTableViewCell/InfoChildTableViewCell.xib @@ -19,77 +19,49 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - + - + + + + + + - - - - + + + + + + + + + - - @@ -101,10 +73,7 @@ - - - - + diff --git a/Scribe/Components/UITableViewCells/AboutTableViewCell.swift b/Scribe/Components/UITableViewCells/AboutTableViewCell.swift new file mode 100644 index 00000000..499abcec --- /dev/null +++ b/Scribe/Components/UITableViewCells/AboutTableViewCell.swift @@ -0,0 +1,47 @@ +// +// Copyright (C) 2023 Scribe +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import UIKit + +final class AboutTableViewCell: UITableViewCell { + + // MARK: - Constants + + static let reuseIdentifier = String(describing: InfoChildTableViewCell.self) + + // MARK: - Properties + + @IBOutlet var titleLabel: UILabel! + @IBOutlet var iconImageView: UIImageView! + + private var section: Section? + private var parentSection: Section? + + // MARK: - Functions + + func configureCell(for section: Section) { + selectionStyle = .none + + titleLabel.text = section.sectionTitle + + if let icon = section.imageString { + iconImageView.image = UIImage.availableIconImage(with: icon) + } else { + iconImageView.image = nil + } + } +} diff --git a/Scribe/Components/UITableViewCells/AboutTableViewCell.xib b/Scribe/Components/UITableViewCells/AboutTableViewCell.xib new file mode 100644 index 00000000..011920ea --- /dev/null +++ b/Scribe/Components/UITableViewCells/AboutTableViewCell.xib @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Scribe/Resources/Localizable.xcstrings b/Scribe/Resources/Localizable.xcstrings index 2560dc5e..19d4a518 100644 --- a/Scribe/Resources/Localizable.xcstrings +++ b/Scribe/Resources/Localizable.xcstrings @@ -1,6 +1,17 @@ { "sourceLanguage" : "en", "strings" : { + "about.title" : { + "comment" : "The title of the about tab", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "About" + } + } + } + }, "settings.appLanguage" : { "comment" : "The title of the app language section", "localizations" : { diff --git a/Scribe/SettingsTab/SettingsTableData.swift b/Scribe/SettingsTab/SettingsTableData.swift index 294d99f5..3d0cc020 100644 --- a/Scribe/SettingsTab/SettingsTableData.swift +++ b/Scribe/SettingsTab/SettingsTableData.swift @@ -77,7 +77,6 @@ struct SettingsTableData { for language in installedKeyboards { let newSection = Section( sectionTitle: language, - imageString: "globe", hasToggle: false, sectionState: .specificLang(languagesAbbrDict[language]!) ) From ac0979f1def6153ad2e048638db0b555ec47de43 Mon Sep 17 00:00:00 2001 From: Damien Rivet Date: Sat, 16 Dec 2023 21:41:51 +0100 Subject: [PATCH 5/5] [#330] Apply PR feedback Added separator insets to tableviews. Added disclosure indicators in About tabs to cells with nested navigation. Additional cleanups. --- Scribe.xcodeproj/project.pbxproj | 12 +++++++++ Scribe/AboutTab/AboutTableData.swift | 20 +++++++------- Scribe/AboutTab/AboutViewController.swift | 3 --- .../UITableViewCells/AboutTableViewCell.swift | 2 ++ .../Extensions/UIEdgeInsetsExtensions.swift | 27 +++++++++++++++++++ Scribe/ParentTableCellModel.swift | 4 ++- Scribe/Resources/Localizable.xcstrings | 14 +++++----- Scribe/SettingsTab/SettingsTableData.swift | 7 +++-- .../SettingsTab/SettingsViewController.swift | 19 ++++++++++--- Scribe/Views/BaseTableViewController.swift | 2 ++ 10 files changed, 82 insertions(+), 28 deletions(-) create mode 100644 Scribe/Extensions/UIEdgeInsetsExtensions.swift diff --git a/Scribe.xcodeproj/project.pbxproj b/Scribe.xcodeproj/project.pbxproj index c50be3ac..dd2feda4 100644 --- a/Scribe.xcodeproj/project.pbxproj +++ b/Scribe.xcodeproj/project.pbxproj @@ -740,6 +740,7 @@ EDC364722AE408FF0001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; EDC364732AE409000001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; EDC364742AE409000001E456 /* InterfaceConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDC364682AE408F20001E456 /* InterfaceConstants.swift */; }; + EDEE62252B2DE65A00A0B9C1 /* UIEdgeInsetsExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDEE62242B2DE65A00A0B9C1 /* UIEdgeInsetsExtensions.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -978,6 +979,7 @@ EDB4601D2AF9FDD600BEA967 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = ""; }; EDB460202B03B3E400BEA967 /* BaseTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseTableViewController.swift; sourceTree = ""; }; EDC364682AE408F20001E456 /* InterfaceConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceConstants.swift; sourceTree = ""; }; + EDEE62242B2DE65A00A0B9C1 /* UIEdgeInsetsExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIEdgeInsetsExtensions.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1207,6 +1209,7 @@ 38BD213222D5907F00C6795D /* Scribe */ = { isa = PBXGroup; children = ( + EDEE62232B2DE64A00A0B9C1 /* Extensions */, 147797A92A2CD2B50044A53E /* AboutTab */, 38BD213322D5907F00C6795D /* AppDelegate.swift */, 1406B78B2A3209CF001DF45B /* AppExtensions.swift */, @@ -1498,6 +1501,14 @@ path = Resources; sourceTree = ""; }; + EDEE62232B2DE64A00A0B9C1 /* Extensions */ = { + isa = PBXGroup; + children = ( + EDEE62242B2DE65A00A0B9C1 /* UIEdgeInsetsExtensions.swift */, + ); + path = Extensions; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -2015,6 +2026,7 @@ 147797B02A2CD3370044A53E /* InfoChildTableViewCell.swift in Sources */, D1A2DCB427AD3EB50057A10D /* AppUISymbols.swift in Sources */, D171945427AF04E50038660B /* KeyboardViewController.swift in Sources */, + EDEE62252B2DE65A00A0B9C1 /* UIEdgeInsetsExtensions.swift in Sources */, D1CDED772A859E4800098546 /* DACommandVariables.swift in Sources */, D171943827AEF0560038660B /* KeyboardStyling.swift in Sources */, D111E9BA27AFE7B200746F92 /* Annotate.swift in Sources */, diff --git a/Scribe/AboutTab/AboutTableData.swift b/Scribe/AboutTab/AboutTableData.swift index a395f598..fa2dd593 100644 --- a/Scribe/AboutTab/AboutTableData.swift +++ b/Scribe/AboutTab/AboutTableData.swift @@ -9,28 +9,28 @@ struct AboutTableData { ParentTableCellModel( headingTitle: "Community", section: [ - Section(sectionTitle: "See the code on GitHub", imageString: "github", hasToggle: false, sectionState: .github), - Section(sectionTitle: "Chat with the team on Matrix", imageString: "matrix", hasToggle: false, sectionState: .matrix), - Section(sectionTitle: "Wikimedia and Scribe", imageString: "wikimedia", hasToggle: false, sectionState: .wikimedia), - Section(sectionTitle: "Share Scribe", imageString: "square.and.arrow.up", hasToggle: false, sectionState: .shareScribe), + Section(sectionTitle: "See the code on GitHub", imageString: "github", sectionState: .github), + Section(sectionTitle: "Chat with the team on Matrix", imageString: "matrix", sectionState: .matrix), + Section(sectionTitle: "Wikimedia and Scribe", imageString: "wikimedia", sectionState: .wikimedia), + Section(sectionTitle: "Share Scribe", imageString: "square.and.arrow.up", sectionState: .shareScribe), ], hasDynamicData: nil ), ParentTableCellModel( headingTitle: "Feedback and support", section: [ - Section(sectionTitle: "Rate Scribe", imageString: "star", hasToggle: false, sectionState: .rateScribe), - Section(sectionTitle: "Report a bug", imageString: "ant", hasToggle: false, sectionState: .bugReport), - Section(sectionTitle: "Send us an email", imageString: "envelope", hasToggle: false, sectionState: .email), -// Section(sectionTitle: "Reset app hints", imageString: "lightbulb", hasToggle: false, sectionState: .appHints) + Section(sectionTitle: "Rate Scribe", imageString: "star", sectionState: .rateScribe), + Section(sectionTitle: "Report a bug", imageString: "ant", sectionState: .bugReport), + Section(sectionTitle: "Send us an email", imageString: "envelope", sectionState: .email), +// Section(sectionTitle: "Reset app hints", imageString: "lightbulb", sectionState: .appHints) ], hasDynamicData: nil ), ParentTableCellModel( headingTitle: "Legal", section: [ - Section(sectionTitle: "Privacy policy", imageString: "lock.shield", hasToggle: false, sectionState: .privacyPolicy), - Section(sectionTitle: "Third-party licenses", imageString: "thirdPartyLicenses", hasToggle: false, sectionState: .licenses), + Section(sectionTitle: "Privacy policy", imageString: "lock.shield", hasNestedNavigation: true, sectionState: .privacyPolicy), + Section(sectionTitle: "Third-party licenses", imageString: "thirdPartyLicenses", hasNestedNavigation: true, sectionState: .licenses), ], hasDynamicData: nil ), diff --git a/Scribe/AboutTab/AboutViewController.swift b/Scribe/AboutTab/AboutViewController.swift index 41e61f47..89326f72 100644 --- a/Scribe/AboutTab/AboutViewController.swift +++ b/Scribe/AboutTab/AboutViewController.swift @@ -43,9 +43,6 @@ extension AboutViewController { cell.configureCell(for: dataSet[indexPath.section].section[indexPath.row]) - cell.backgroundColor = .clear - cell.selectionStyle = .none - return cell } } diff --git a/Scribe/Components/UITableViewCells/AboutTableViewCell.swift b/Scribe/Components/UITableViewCells/AboutTableViewCell.swift index 499abcec..7f84a81f 100644 --- a/Scribe/Components/UITableViewCells/AboutTableViewCell.swift +++ b/Scribe/Components/UITableViewCells/AboutTableViewCell.swift @@ -43,5 +43,7 @@ final class AboutTableViewCell: UITableViewCell { } else { iconImageView.image = nil } + + accessoryType = section.hasNestedNavigation ? .disclosureIndicator : .none } } diff --git a/Scribe/Extensions/UIEdgeInsetsExtensions.swift b/Scribe/Extensions/UIEdgeInsetsExtensions.swift new file mode 100644 index 00000000..f3dc76e3 --- /dev/null +++ b/Scribe/Extensions/UIEdgeInsetsExtensions.swift @@ -0,0 +1,27 @@ +// +// Copyright (C) 2023 Scribe +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import UIKit + +extension UIEdgeInsets { + + // MARK: - Initialisation + + init(vertical: CGFloat, horizontal: CGFloat) { + self.init(top: vertical, left: horizontal, bottom: vertical, right: horizontal) + } +} diff --git a/Scribe/ParentTableCellModel.swift b/Scribe/ParentTableCellModel.swift index b8505926..036f6c87 100644 --- a/Scribe/ParentTableCellModel.swift +++ b/Scribe/ParentTableCellModel.swift @@ -16,13 +16,15 @@ struct Section { let sectionTitle: String let imageString: String? let hasToggle: Bool + let hasNestedNavigation: Bool let sectionState: SectionState let shortDescription: String? - init(sectionTitle: String, imageString: String? = nil, hasToggle: Bool, sectionState: SectionState, shortDescription: String? = nil) { + init(sectionTitle: String, imageString: String? = nil, hasToggle: Bool = false, hasNestedNavigation: Bool = false, sectionState: SectionState, shortDescription: String? = nil) { self.sectionTitle = sectionTitle self.imageString = imageString self.hasToggle = hasToggle + self.hasNestedNavigation = hasNestedNavigation self.sectionState = sectionState self.shortDescription = shortDescription } diff --git a/Scribe/Resources/Localizable.xcstrings b/Scribe/Resources/Localizable.xcstrings index 19d4a518..bd30f59d 100644 --- a/Scribe/Resources/Localizable.xcstrings +++ b/Scribe/Resources/Localizable.xcstrings @@ -12,24 +12,24 @@ } } }, - "settings.appLanguage" : { - "comment" : "The title of the app language section", + "settings.appSettings" : { + "comment" : "The title of the app settings section", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "App language" + "value" : "App settings" } } } }, - "settings.appLanguage.system" : { - "comment" : "Use the system language", + "settings.appSettings.appLanguage" : { + "comment" : "Change the language of the Scribe App", "localizations" : { "en" : { "stringUnit" : { "state" : "translated", - "value" : "System language" + "value" : "App language" } } } @@ -136,7 +136,7 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Settings" + "value" : "Scribe Settings" } } } diff --git a/Scribe/SettingsTab/SettingsTableData.swift b/Scribe/SettingsTab/SettingsTableData.swift index 3d0cc020..e702bfeb 100644 --- a/Scribe/SettingsTab/SettingsTableData.swift +++ b/Scribe/SettingsTab/SettingsTableData.swift @@ -8,16 +8,16 @@ struct SettingsTableData { static let settingsTableData: [ParentTableCellModel] = [ ParentTableCellModel( - headingTitle: NSLocalizedString("settings.appLanguage", comment: "The title of the app language section"), + headingTitle: NSLocalizedString("settings.appSettings", comment: "The title of the app settings section"), section: [ - Section(sectionTitle: NSLocalizedString("settings.appLanguage.system", comment: "Use the system language"), imageString: "globe", hasToggle: false, sectionState: .appLang), + Section(sectionTitle: NSLocalizedString("settings.appSettings.appLanguage", comment: "Change the language of the Scribe App"), imageString: "globe", hasToggle: false, sectionState: .appLang), ], hasDynamicData: nil ), ParentTableCellModel( headingTitle: NSLocalizedString("settings.installedKeyboards", comment: "The title of the installed keyboards section"), section: [ - // Section(sectionTitle: "All keyboards", imageString: "globe", hasToggle: false, sectionState: .specificLang("all")), + // Section(sectionTitle: "All keyboards", imageString: "globe", sectionState: .specificLang("all")), ], hasDynamicData: .installedKeyboards ), @@ -77,7 +77,6 @@ struct SettingsTableData { for language in installedKeyboards { let newSection = Section( sectionTitle: language, - hasToggle: false, sectionState: .specificLang(languagesAbbrDict[language]!) ) diff --git a/Scribe/SettingsTab/SettingsViewController.swift b/Scribe/SettingsTab/SettingsViewController.swift index 04ec052f..956e525e 100644 --- a/Scribe/SettingsTab/SettingsViewController.swift +++ b/Scribe/SettingsTab/SettingsViewController.swift @@ -18,13 +18,22 @@ import UIKit final class SettingsViewController: UIViewController { + + // MARK: - Constants + + private let sectionHeaderHeight: CGFloat = 32 + private let separatorInset = UIEdgeInsets(vertical: 16, horizontal: 16) + + // MARK: - Properties + @IBOutlet var footerFrame: UIView! @IBOutlet var footerButton: UIButton! - @IBOutlet var parentTable: UITableView! var tableData = SettingsTableData.settingsTableData + // MARK: - Functions + override func viewDidLoad() { super.viewDidLoad() @@ -32,11 +41,11 @@ final class SettingsViewController: UIViewController { navigationItem.backButtonTitle = NSLocalizedString("settings.title.backButton", comment: "The back button's title for the settings screen") parentTable.register(UINib(nibName: "InfoChildTableViewCell", bundle: nil), forCellReuseIdentifier: InfoChildTableViewCell.reuseIdentifier) - parentTable.dataSource = self parentTable.delegate = self parentTable.backgroundColor = .clear - parentTable.sectionHeaderHeight = 32 + parentTable.sectionHeaderHeight = sectionHeaderHeight + parentTable.separatorInset = separatorInset setFooterButtonView() @@ -81,6 +90,8 @@ final class SettingsViewController: UIViewController { } } +// MARK: - UITableViewDataSource + extension SettingsViewController: UITableViewDataSource { func numberOfSections(in tableView: UITableView) -> Int { @@ -103,6 +114,8 @@ extension SettingsViewController: UITableViewDataSource { } } +// MARK: - UITableViewDelegate + extension SettingsViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { diff --git a/Scribe/Views/BaseTableViewController.swift b/Scribe/Views/BaseTableViewController.swift index a5191ca0..f5e28340 100644 --- a/Scribe/Views/BaseTableViewController.swift +++ b/Scribe/Views/BaseTableViewController.swift @@ -22,6 +22,7 @@ class BaseTableViewController: UITableViewController { // MARK: - Constants private let sectionHeaderHeight: CGFloat = 32 + private let separatorInset = UIEdgeInsets(vertical: 16, horizontal: 16) // MARK: - Properties @@ -36,6 +37,7 @@ class BaseTableViewController: UITableViewController { tableView.sectionHeaderHeight = sectionHeaderHeight tableView.register(UINib(nibName: "InfoChildTableViewCell", bundle: nil), forCellReuseIdentifier: "InfoChildTableViewCell") + tableView.separatorInset = separatorInset } }