diff --git a/Scribe/AppDelegate.swift b/Scribe/AppDelegate.swift index c7546e6f..5f7b51f5 100644 --- a/Scribe/AppDelegate.swift +++ b/Scribe/AppDelegate.swift @@ -15,6 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { _: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + initializeFontSize() // Override point for customization after application launch. if #available(iOS 13.0, *) { let appearance = UITabBarAppearance() diff --git a/Scribe/AppExtensions.swift b/Scribe/AppExtensions.swift index 2cd0596e..11360acb 100644 --- a/Scribe/AppExtensions.swift +++ b/Scribe/AppExtensions.swift @@ -53,4 +53,6 @@ extension Locale { extension Notification.Name { static let keyboardsUpdatedNotification = Notification.Name("keyboardsHaveUpdated") + static let fontSizeUpdatedNotification = Notification.Name("fontSizeHasUpdated") + } diff --git a/Scribe/AppTexts/AppTextStyling.swift b/Scribe/AppTexts/AppTextStyling.swift index 4edeb2fb..378d85f7 100644 --- a/Scribe/AppTexts/AppTextStyling.swift +++ b/Scribe/AppTexts/AppTextStyling.swift @@ -9,7 +9,22 @@ import UIKit let preferredLanguage = Locale.preferredLanguages[0] var fontSize = CGFloat(0) +func initializeFontSize() { + if DeviceType.isPhone { + if UIScreen.main.bounds.width > 413 || UIScreen.main.bounds.width <= 375 { + fontSize = UIScreen.main.bounds.height / 59 + } else { + fontSize = UIScreen.main.bounds.height / 50 + } + } else if DeviceType.isPad { + fontSize = UIScreen.main.bounds.height / 50 + } + let userDefaults = UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")! + if userDefaults.bool(forKey: "increaseTextSize") { + fontSize *= 1.25 + } +} /// Concatenates attributed strings. /// /// - Parameters diff --git a/Scribe/Button/CTAButton.swift b/Scribe/Button/CTAButton.swift index d97dfa2d..5df92f7d 100644 --- a/Scribe/Button/CTAButton.swift +++ b/Scribe/Button/CTAButton.swift @@ -7,6 +7,10 @@ import SwiftUI struct CTAButton: View { + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } + let title: String let action: () -> Void @Environment(\.colorScheme) var colorScheme @@ -14,7 +18,7 @@ struct CTAButton: View { var body: some View { Button(action: action) { Text(title) - .font(.system(size: 20, weight: .bold)) + .font(.system(size: 20 * textSizeMultiplier, weight: .bold)) .foregroundColor(Color("lightTextDarkCTA")) .frame(maxWidth: .infinity) .padding(.vertical, 16) diff --git a/Scribe/Button/DownloadButton.swift b/Scribe/Button/DownloadButton.swift index 802a5ee0..e37cf7b5 100644 --- a/Scribe/Button/DownloadButton.swift +++ b/Scribe/Button/DownloadButton.swift @@ -70,6 +70,10 @@ struct ButtonConfig { } struct DownloadButton: View { + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } + let state: ButtonState let action: () -> Void @Environment(\.colorScheme) var colorScheme @@ -86,7 +90,7 @@ struct DownloadButton: View { Image(systemName: state.config.icon) } } - .font(.system(size: 12, weight: .semibold)) + .font(.system(size: 12 * textSizeMultiplier, weight: .semibold)) .foregroundColor(state.config.foregroundColor) .frame(width: 120, height: 20) .padding(.vertical, 6) diff --git a/Scribe/ConfirmDialog/ConfirmDialogView.swift b/Scribe/ConfirmDialog/ConfirmDialogView.swift index 36d64f92..ff023170 100644 --- a/Scribe/ConfirmDialog/ConfirmDialogView.swift +++ b/Scribe/ConfirmDialog/ConfirmDialogView.swift @@ -7,6 +7,10 @@ import SwiftUI struct ConfirmDialogView: View { + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } + private let cardCornerRadius: CGFloat = 10 private let iconSize: CGFloat = 30.0 private let cardPadding: CGFloat = 16 @@ -35,7 +39,7 @@ struct ConfirmDialogView: View { .foregroundColor(Color.scribeCTA) Text(infoText) - .font(.system(size: DeviceType.isPad ? 22 : 0)) + .font(.system(size: DeviceType.isPad ? 22 * textSizeMultiplier : 17 * textSizeMultiplier)) .fixedSize(horizontal: false, vertical: true) } @@ -45,7 +49,7 @@ struct ConfirmDialogView: View { action: onChange, label: { Text(changeButtonText) - .font(.system(size: DeviceType.isPad ? 22 : 0)) + .font(.system(size: DeviceType.isPad ? 22 * textSizeMultiplier : 17 * textSizeMultiplier)) .foregroundColor(Color.keyChar) }) .buttonStyle(.borderedProminent) @@ -61,6 +65,7 @@ struct ConfirmDialogView: View { label: { Text(confirmButtonText) .font(.system(size: DeviceType.isPad ? 22 : 0)) + .font(.system(size: DeviceType.isPad ? 22 * textSizeMultiplier : 17 * textSizeMultiplier)) .foregroundColor(Color.keyChar) }) .buttonStyle(.borderedProminent) diff --git a/Scribe/InstallationTab/DownloadDataScreen.swift b/Scribe/InstallationTab/DownloadDataScreen.swift index 54717d41..b28be4fb 100644 --- a/Scribe/InstallationTab/DownloadDataScreen.swift +++ b/Scribe/InstallationTab/DownloadDataScreen.swift @@ -31,6 +31,10 @@ struct RadioCircle: View { } struct UpdateDataCardView: View { + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } + var languages: [Section] private let title = NSLocalizedString( "i18n.app.download.menu_ui.update_data", @@ -53,14 +57,14 @@ struct UpdateDataCardView: View { var body: some View { VStack(alignment: .leading, spacing: 6) { Text(title) - .font(.system(size: 19, weight: .semibold)) + .font(.system(size: 19 * textSizeMultiplier, weight: .semibold)) .foregroundColor(.primary) VStack(alignment: .leading, spacing: 12) { if !languages.isEmpty { HStack { Text(checkText) - .font(.body) + .font(.system(size: 17 * textSizeMultiplier)) .foregroundColor(.primary) Spacer() @@ -86,6 +90,9 @@ struct UpdateDataCardView: View { } struct LanguageDownloadCard: View { + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } let language: String let state: ButtonState let action: () -> Void @@ -94,7 +101,7 @@ struct LanguageDownloadCard: View { VStack(alignment: .leading, spacing: 12) { HStack { Text(language) - .font(.body) + .font(.system(size: 17 * textSizeMultiplier)) .foregroundColor(.primary) Spacer() @@ -145,6 +152,9 @@ struct EmptyStateView: View { struct LanguageListView: View { var onNavigateToTranslationSource: ((String, String) -> Void)? var languages: [Section] + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } @ObservedObject private var stateManager = DownloadStateManager.shared @@ -180,7 +190,7 @@ struct LanguageListView: View { ZStack { VStack(alignment: .leading, spacing: 6) { Text(title) - .font(.system(size: 19, weight: .semibold)) + .font(.system(size: 19 * textSizeMultiplier, weight: .semibold)) .foregroundColor(.primary) if languages.isEmpty { EmptyStateView() diff --git a/Scribe/InstallationTab/InstallationDownload.swift b/Scribe/InstallationTab/InstallationDownload.swift index 357376b9..47d5a4af 100644 --- a/Scribe/InstallationTab/InstallationDownload.swift +++ b/Scribe/InstallationTab/InstallationDownload.swift @@ -11,17 +11,23 @@ struct CardView: View { let mainText: String let subtitle: String let action: () -> Void + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + + var textSizeMultiplier: CGFloat { + increaseTextSize ? 1.25 : 1.0 + } var body: some View { VStack(alignment: .leading, spacing: 6) { Text(title) - .font(.system(size: 19, weight: .semibold)) + .font(.system(size: 19 * textSizeMultiplier, weight: .semibold)) .foregroundColor(.primary) VStack(alignment: .leading, spacing: 6) { HStack { Text(mainText) - .font(.body) + .font(.system(size: 17 * textSizeMultiplier)) .foregroundColor(.primary) Spacer() @@ -31,7 +37,7 @@ struct CardView: View { } Text(subtitle) - .font(.subheadline) + .font(.system(size: 15 * textSizeMultiplier)) .foregroundColor(.secondary) } .padding() diff --git a/Scribe/InstallationTab/InstallationVC.swift b/Scribe/InstallationTab/InstallationVC.swift index 5ae4ee6b..2d91ff7f 100644 --- a/Scribe/InstallationTab/InstallationVC.swift +++ b/Scribe/InstallationTab/InstallationVC.swift @@ -9,6 +9,7 @@ import SwiftUI /// A UIViewController that provides instructions on how to install Keyboards as well as information about Scribe. class InstallationVC: UIViewController { + // Variables linked to elements in AppScreen.storyboard. @IBOutlet var appTextViewPhone: UITextView! @IBOutlet var appTextViewPad: UITextView! @@ -106,7 +107,18 @@ class InstallationVC: UIViewController { name: NSNotification.Name("NavigateToDownloadScreen"), object: nil ) + NotificationCenter.default.addObserver( + self, + selector: #selector(handleFontSizeUpdate), + name: .fontSizeUpdatedNotification, + object: nil + ) } + @objc func handleFontSizeUpdate() { + DispatchQueue.main.async { + self.setCurrentUI() + } + } @objc private func handleNavigateToDownloadScreen() { navigateToDownloadDataScreen() @@ -246,17 +258,9 @@ class InstallationVC: UIViewController { /// Creates the current app UI by applying constraints and calling child UI functions. func setCurrentUI() { - // Sets the font size for the text in the app screen and corresponding UIImage icons. - if DeviceType.isPhone { - if UIScreen.main.bounds.width > 413 || UIScreen.main.bounds.width <= 375 { - fontSize = UIScreen.main.bounds.height / 59 - } else if UIScreen.main.bounds.width <= 413 && UIScreen.main.bounds.width > 375 { - fontSize = UIScreen.main.bounds.height / 50 - } - } else if DeviceType.isPad { - fontSize = UIScreen.main.bounds.height / 50 - } + // Sets the font size for the text in the app screen and corresponding UIImage icons + initializeFontSize() installationHeaderLabel.text = NSLocalizedString( "i18n.app.installation.keyboard.title", value: "Keyboard installation", comment: "" diff --git a/Scribe/ParentTableCellModel.swift b/Scribe/ParentTableCellModel.swift index 58d21d56..6fd18dcb 100644 --- a/Scribe/ParentTableCellModel.swift +++ b/Scribe/ParentTableCellModel.swift @@ -70,6 +70,7 @@ enum UserInteractiveState { case autosuggestEmojis case toggleAccentCharacters case toggleWordForWordDeletion + case increaseTextSize case none } diff --git a/Scribe/SettingsTab/SettingsTableData.swift b/Scribe/SettingsTab/SettingsTableData.swift index d6c0ba5b..32265e9f 100644 --- a/Scribe/SettingsTab/SettingsTableData.swift +++ b/Scribe/SettingsTab/SettingsTableData.swift @@ -16,7 +16,14 @@ enum SettingsTableData { hasToggle: false, sectionState: .appLang, shortDescription: NSLocalizedString("i18n.app.settings.keyboard.translation.select_source", value: "Select language for app texts.", comment: "") + ), + Section( + sectionTitle: NSLocalizedString("i18n.app.settings.menu.increase_text_size", value: "Increase app text size", comment: ""), + hasToggle: true, + sectionState: .none(.increaseTextSize), + shortDescription: NSLocalizedString("i18n.app.settings.menu.increase_text_size_description", value: "Increase text sizes for better readability", comment: "") ) + ], hasDynamicData: nil ), diff --git a/Scribe/SettingsTab/SettingsViewController.swift b/Scribe/SettingsTab/SettingsViewController.swift index 330086b4..12361da3 100644 --- a/Scribe/SettingsTab/SettingsViewController.swift +++ b/Scribe/SettingsTab/SettingsViewController.swift @@ -40,6 +40,7 @@ final class SettingsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + setHeaderHeight() showTipCardView() @@ -68,7 +69,23 @@ final class SettingsViewController: UIViewController { self.commonMethodToRefresh() } + NotificationCenter.default.addObserver( + self, + selector: #selector(handleFontSizeUpdate), + name: .fontSizeUpdatedNotification, + object: nil + ) } + @objc func handleFontSizeUpdate() { + DispatchQueue.main.async { + self.parentTable.reloadData() + self.setFooterButtonView() + } + } + + deinit { + NotificationCenter.default.removeObserver(self) + } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) diff --git a/Scribe/TipCard/TipCardView.swift b/Scribe/TipCard/TipCardView.swift index d4ccf6b8..d4d8529d 100644 --- a/Scribe/TipCard/TipCardView.swift +++ b/Scribe/TipCard/TipCardView.swift @@ -7,6 +7,10 @@ import SwiftUI struct TipCardView: View { + @AppStorage("increaseTextSize", store: UserDefaults(suiteName: "group.be.scri.userDefaultsContainer")) + var increaseTextSize: Bool = false + var textSizeMultiplier: CGFloat { increaseTextSize ? 1.25 : 1.0 } + private let buttonHeight = 70.0 private let multiplicityPadding = 0.5 private let leadingPadding = 40.0 @@ -26,7 +30,7 @@ struct TipCardView: View { .foregroundColor(Color.scribeCTA) .padding(.horizontal) Text(infoText) - .font(Font.system(size: DeviceType.isPad ? 22 : 0, weight: .medium)) + .font(Font.system(size: DeviceType.isPad ? 22 * textSizeMultiplier : 17 * textSizeMultiplier, weight: .medium)) Spacer() Button { tipCardState = false diff --git a/Scribe/Views/BaseTableViewController.swift b/Scribe/Views/BaseTableViewController.swift index 92404513..37fd4ad6 100644 --- a/Scribe/Views/BaseTableViewController.swift +++ b/Scribe/Views/BaseTableViewController.swift @@ -42,7 +42,25 @@ class BaseTableViewController: UITableViewController { if let tabBarController = tabBarController as? SwipeableTabBarController { tabBarController.isCyclingEnabled = true } + + NotificationCenter.default.addObserver( + self, + selector: #selector(handleFontSizeUpdate), + name: .fontSizeUpdatedNotification, + object: nil + ) + } + + @objc func handleFontSizeUpdate() { + DispatchQueue.main.async { + self.tableView.reloadData() + } + } + + deinit { + NotificationCenter.default.removeObserver(self) + } } // MARK: UITableViewDataSource diff --git a/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift b/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift index a27303fd..0587f456 100644 --- a/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift +++ b/Scribe/Views/Cells/InfoChildTableViewCell/InfoChildTableViewCell.swift @@ -88,6 +88,8 @@ final class InfoChildTableViewCell: UITableViewCell { selectionStyle = .none setTableView() + titleLabel.font = UIFont.systemFont(ofSize: fontSize, weight: .medium) + descriptionLabel.font = UIFont.systemFont(ofSize: fontSize * 0.9) titleLabel.text = section.sectionTitle if let shortDescription = section.shortDescription { @@ -151,6 +153,11 @@ final class InfoChildTableViewCell: UITableViewCell { let dictionaryKey = languageCode + "WordForWordDeletion" userDefaults.setValue(toggleSwitch.isOn, forKey: dictionaryKey) + case .increaseTextSize: + userDefaults.setValue(toggleSwitch.isOn, forKey: "increaseTextSize") + initializeFontSize() + NotificationCenter.default.post(name: .fontSizeUpdatedNotification, object: nil) + case .none: break } @@ -199,6 +206,13 @@ final class InfoChildTableViewCell: UITableViewCell { toggleSwitch.isOn = false // Default value } + case .increaseTextSize: + if let toggleValue = userDefaults.object(forKey: "increaseTextSize") as? Bool { + toggleSwitch.isOn = toggleValue + } else { + toggleSwitch.isOn = false // Default off + } + case .none: break } } diff --git a/Scribe/Views/Cells/UITableViewCells/AboutTableViewCell.swift b/Scribe/Views/Cells/UITableViewCells/AboutTableViewCell.swift index 5e30b601..0451e06d 100644 --- a/Scribe/Views/Cells/UITableViewCells/AboutTableViewCell.swift +++ b/Scribe/Views/Cells/UITableViewCells/AboutTableViewCell.swift @@ -55,6 +55,7 @@ final class AboutTableViewCell: UITableViewCell { selectionStyle = .none setTableView() + titleLabel.font = UIFont.systemFont(ofSize: fontSize, weight: .medium) titleLabel.text = section.sectionTitle if let icon = section.imageString { diff --git a/Scribe/Views/TableViewTemplateViewController.swift b/Scribe/Views/TableViewTemplateViewController.swift index 012d9493..1ed52602 100644 --- a/Scribe/Views/TableViewTemplateViewController.swift +++ b/Scribe/Views/TableViewTemplateViewController.swift @@ -115,11 +115,11 @@ extension TableViewTemplateViewController { let descFont: UIFont if DeviceType.isPad { - titleFont = UIFont.systemFont(ofSize: 24, weight: .medium) - descFont = UIFont.systemFont(ofSize: 18) + titleFont = UIFont.systemFont(ofSize: fontSize * 1.5, weight: .medium) + descFont = UIFont.systemFont(ofSize: fontSize * 1.1) } else { - titleFont = UIFont.systemFont(ofSize: 16, weight: .medium) - descFont = UIFont.systemFont(ofSize: 14) + titleFont = UIFont.systemFont(ofSize: fontSize, weight: .medium) + descFont = UIFont.systemFont(ofSize: fontSize * 0.9) } // Calculate actual height needed for title text.