commit 44ea233b2ea4f63938a6b234cad0ec717f1b5e8f parent 241f614407fa92a3fa3e8447310fa2b2dadcb661 Author: Marc Stibane <marc@taler.net> Date: Sun, 10 Sep 2023 11:45:33 +0200 AccessibleFont Diffstat:
35 files changed, 346 insertions(+), 206 deletions(-)
diff --git a/TalerWallet1/Helper/Font+Taler.swift b/TalerWallet1/Helper/Font+Taler.swift @@ -6,108 +6,250 @@ import SwiftUI // Use enums for multiple font types and functions for the set custom font. -fileprivate let ATKINSON = "AtkinsonHyperlegible-" -fileprivate let NUNITO = "Nunito-" - -fileprivate let REGULAR = "Regular" -fileprivate let BOLD = "Bold" -fileprivate let BOLDITALIC = "BoldItalic" -fileprivate let ITALIC = "Italic" - -extension Font { - enum TalerFont { - case regular - case bold - case boldItalic - case italic - case custom(String) - - var value: String { - switch self { - case .regular: return REGULAR - case .bold: return BOLD - case .boldItalic: return BOLDITALIC - case .italic: return ITALIC - - case .custom(let name): - return name - } +fileprivate let ATKINSON = "AtkinsonHyperlegible-" +fileprivate let NUNITO = "Nunito-" + +fileprivate let REGULAR = "Regular" +fileprivate let BOLD = "Bold" +fileprivate let BLACK = "Black" +fileprivate let BLACKITALIC = "BlackItalic" +fileprivate let BOLDITALIC = "BoldItalic" +fileprivate let ITALIC = "Italic" + +struct TalerFont { + static var atkinson: Font { + Font.custom(ATKINSON + REGULAR, size: 24, relativeTo: .title2) + } + static var nunito: Font { + Font.custom(NUNITO + REGULAR, size: 24, relativeTo: .title2) + } + static var nunitoItalic: Font { + Font.custom(NUNITO + ITALIC, size: 24, relativeTo: .title2) + } + + static func atkinson(size: CGFloat, relativeTo style: UIFont.TextStyle) -> UIFont { + if let font = UIFont(name: ATKINSON + REGULAR, size: size) { + let fontMetrics = UIFontMetrics(forTextStyle: style) + return fontMetrics.scaledFont(for: font) + } else { + return UIFont.preferredFont(forTextStyle: style) + } + } + static func nunito(size: CGFloat, relativeTo: UIFont.TextStyle) -> UIFont { + if let font = UIFont(name: NUNITO + REGULAR, size: size) { + let fontMetrics = UIFontMetrics(forTextStyle: relativeTo) + return fontMetrics.scaledFont(for: font) + } else { + return UIFont.preferredFont(forTextStyle: relativeTo) + } + } + static func nunitoItalic(size: CGFloat, relativeTo: UIFont.TextStyle) -> UIFont { + if let font = UIFont(name: NUNITO + ITALIC, size: size) { + let fontMetrics = UIFontMetrics(forTextStyle: relativeTo) + return fontMetrics.scaledFont(for: font) + } else { + return UIFont.preferredFont(forTextStyle: relativeTo) + } + } + + static func talerFont(_ talerFont: Int, size: CGFloat, relativeTo style: UIFont.TextStyle) -> UIFont { + if talerFont != 0 { + let uiFont: UIFont = (talerFont == 1) ? TalerFont.atkinson(size: size, relativeTo: style) + : (talerFont == 2) ? TalerFont.nunito(size: size, relativeTo: style) + : TalerFont.nunitoItalic(size: size, relativeTo: style) + return uiFont + } else { + return UIFont.preferredFont(forTextStyle: style) } } +} - static func talerFont(_ type: TalerFont, size: CGFloat = 17) -> Font { - return .custom(type.value, size: size) +struct AccessibleFont { + var regular: Font + var bold: Font + static var talerFont: Int { + if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" { + 3 + } else { + Controller.shared.talerFont + } } - static func talerFontName(_ index: Int) -> String { - if index == 1 { - return ATKINSON + init(_ base: String, size: CGFloat, relativeTo: Font.TextStyle, isBold: Bool = false) { + if AccessibleFont.talerFont == 0 { + self.regular = .system(relativeTo) + self.bold = .system(relativeTo).bold() // why is this allowed here (iOS-15) ??? should give compiler error + // bold() for Font needs iOS-16 + // Text has a function bold(), needs iOS-13, but that shouldn't matter here + } else if isBold && AccessibleFont.talerFont >= 2 { + // Nunito has Black Variants, but AtkinsonHyperlegible doesn't + self.regular = Font.custom(base + (AccessibleFont.talerFont == 2 ? BOLD : BOLDITALIC), size: size, relativeTo: relativeTo) + self.bold = Font.custom(base + (AccessibleFont.talerFont == 2 ? BLACK : BLACKITALIC), size: size, relativeTo: relativeTo) } else { - return NUNITO + self.regular = Font.custom(base + (AccessibleFont.talerFont > 2 ? ITALIC : REGULAR), size: size, relativeTo: relativeTo) + self.bold = Font.custom(base + (AccessibleFont.talerFont > 2 ? BOLDITALIC : BOLD), size: size, relativeTo: relativeTo) + } + } + + init(regular: Font, bold: Font) { + self.regular = regular + self.bold = bold + } + + func value(_ legibilityWeight: LegibilityWeight?) -> Font { + switch legibilityWeight { + case .bold: // should increase Font.Weight by 2 + // ultraLight => light + // thin => regular + // light => medium + // regular => semibold + // medium => bold + // semibold => heavy + // bold => black + return bold + default: + return regular } } +} + +extension AccessibleFont { + static var fontName: String { + (talerFont == 1) ? ATKINSON + : NUNITO + } - static var talerLargeTitle: Font { - Controller.shared.talerFont == 0 ? .largeTitle : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 38, relativeTo: .largeTitle) - } // 34 -> 38 - static var talerTitle: Font { - Controller.shared.talerFont == 0 ? .title : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 31, relativeTo: .title) - } // 28 -> 31 - static var talerTitle2: Font { - Controller.shared.talerFont == 0 ? .title2 : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 25, relativeTo: .title2) - } // 22 -> 25 - static var talerTitle3: Font { - Controller.shared.talerFont == 0 ? .title3 : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 23, relativeTo: .title3) - } // 20 -> 23 - static var talerHeadline: Font { - Controller.shared.talerFont == 0 ? .headline : - .custom(talerFontName(Controller.shared.talerFont) + BOLD, size: 19, relativeTo: .headline) - } // 17 bold -> 19 bold - static var talerBody: Font { - Controller.shared.talerFont == 0 ? .body : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 19, relativeTo: .body) - } // 17 -> 19 - static var talerCallout: Font { - Controller.shared.talerFont == 0 ? .callout : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 18, relativeTo: .callout) - } // 16 -> 18 - static var talerSubheadline: Font { - Controller.shared.talerFont == 0 ? .subheadline : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 17, relativeTo: .subheadline) - } // 15 -> 17 - static var talerFootnote: Font { - Controller.shared.talerFont == 0 ? .footnote : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 15, relativeTo: .footnote) - } // 13 -> 15 - static var talerCaption: Font { - Controller.shared.talerFont == 0 ? .caption : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 13, relativeTo: .caption) - } // 12 -> 13 - static var talerCaption2: Font { - Controller.shared.talerFont == 0 ? .caption2 : - .custom(talerFontName(Controller.shared.talerFont) + REGULAR, size: 12, relativeTo: .caption2) - } // 11 -> 12 + static var largeTitle: AccessibleFont { AccessibleFont(fontName, size: 38, relativeTo: .largeTitle) } // 34 -> 38 + static var title: AccessibleFont { AccessibleFont(fontName, size: 31, relativeTo: .title) } // 28 -> 31 + static var title2: AccessibleFont { AccessibleFont(fontName, size: 25, relativeTo: .title2) } // 22 -> 25 + static var title3: AccessibleFont { AccessibleFont(fontName, size: 23, relativeTo: .title3) } // 20 -> 23 + static var headline: AccessibleFont { AccessibleFont(fontName, size: 19, relativeTo: .headline, isBold: true) } // 17 bold -> 19 bold + static var body: AccessibleFont { AccessibleFont(fontName, size: 19, relativeTo: .body) } // 17 -> 19 + static var callout: AccessibleFont { AccessibleFont(fontName, size: 18, relativeTo: .callout) } // 16 -> 18 + static var subheadline: AccessibleFont { AccessibleFont(fontName, size: 17, relativeTo: .subheadline) } // 15 -> 17 + static var footnote: AccessibleFont { AccessibleFont(fontName, size: 15, relativeTo: .footnote) } // 13 -> 15 + static var caption: AccessibleFont { AccessibleFont(fontName, size: 13, relativeTo: .caption) } // 12 -> 13 +// static var caption2: AccessibleFont { AccessibleFont(fontName, size: 12, relativeTo: .caption2) } // 11 -> 12 } +struct AccessibilityFontViewModifier: ViewModifier { + @Environment(\.legibilityWeight) private var legibilityWeight + + var font: AccessibleFont + + func body(content: Content) -> some View { + content.font(font.value(legibilityWeight)) + } +} + +extension View { + func accessibilityFont(_ font: AccessibleFont) -> some View { + return self.modifier(AccessibilityFontViewModifier(font: font)) + } +} +// MARK: - +/// This works on-the-fly to update NavigationTitles when you change the font +struct NavigationBarBuilder: UIViewControllerRepresentable { + var build: (UINavigationController) -> Void = { _ in } + + func makeUIViewController(context: UIViewControllerRepresentableContext<NavigationBarBuilder>) -> UIViewController { + UIViewController() + } + + func updateUIViewController(_ uiViewController: UIViewController, + context: UIViewControllerRepresentableContext<NavigationBarBuilder>) { + if let navigationController = uiViewController.navigationController { + self.build(navigationController) + } + } +} + +/// This works only once. Each following call does nothing - including (re-)setting to nil +struct TalerNavBar: ViewModifier { + let talerFont: Int + + static func setNavBarFonts(talerFont: Int) -> Void { + let navBarAppearance = UINavigationBar.appearance() + navBarAppearance.titleTextAttributes = nil + navBarAppearance.largeTitleTextAttributes = nil + if talerFont != 0 { + navBarAppearance.titleTextAttributes = [.font: TalerFont.talerFont(talerFont, size: 24, relativeTo: .title2)] + navBarAppearance.largeTitleTextAttributes = [.font: TalerFont.talerFont(talerFont, size: 38, relativeTo: .largeTitle)] + } + } + + init(_ talerFont: Int) { + self.talerFont = talerFont + TalerNavBar.setNavBarFonts(talerFont: talerFont) + } + + func body(content: Content) -> some View { + let _ = TalerNavBar.setNavBarFonts(talerFont: talerFont) + content + } + +} + +extension View { + func talerNavBar(talerFont: Int) -> some View { + self.modifier(TalerNavBar(talerFont)) + } +} + + +#if false +//init() { +// NavigationBarConfigurator.configureTitles() +//} +struct NavigationBarConfigurator { + static func configureTitles() { + let appearance = UINavigationBarAppearance() + let design = UIFontDescriptor.SystemDesign.rounded + if let descriptorWithDesign = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .largeTitle) + .withDesign(design), + let descriptorWithTraits = descriptorWithDesign.withSymbolicTraits(.traitBold) { + let font = UIFont(descriptor: descriptorWithTraits, size: 34) + appearance.largeTitleTextAttributes = [.font: font, .foregroundColor: UIColor.label] + } + if let smallTitleDescriptorWithDesign = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .headline) .withDesign(design) { + let smallTitleFont = UIFont(descriptor: smallTitleDescriptorWithDesign, size: 24) + appearance.titleTextAttributes = [.font:smallTitleFont, .foregroundColor: UIColor.label] + } + UINavigationBar.appearance().standardAppearance = appearance + } +} +#endif +// MARK: - struct ContentViewFonts: View { + // let myWeight: Font.Weight var body: some View { VStack { - Text("Text demo") - .font(.talerFont(.regular)) - Text("Text demo") - .font(.talerFont(.italic)) - Text("Text demo") - .font(.talerFont(.bold)) - Text("Text demo") - .font(.talerFont(.boldItalic)) - - Text("Text demo") - .font(.talerBody) + HStack { + Text("title a") + Text("bold").bold() + } + .accessibilityFont(.title) + .padding() + HStack { + Text("title2 a") + Text("italic").italic() + Text("bold").bold() + } + .accessibilityFont(.title2) + .padding() + Text("headline") + .accessibilityFont(.headline) + .padding(.top) + Text("headline bold") + .bold() + .accessibilityFont(.headline) + .padding(.bottom) + Text("title2 bold italic") + .bold() + .italic() + .accessibilityFont(.title2) + .padding() } } } diff --git a/TalerWallet1/Views/Balances/BalanceRowView.swift b/TalerWallet1/Views/Balances/BalanceRowView.swift @@ -15,16 +15,13 @@ struct BalanceButton: View { var body: some View { Button(action: rowAction) { VStack(alignment: .trailing, spacing: 0) { - HStack(alignment: .firstTextBaseline, spacing: 0) { - Text("B", comment: "the first letter of Balance - or leave empty") - .font(.title2) - Text("alance", comment: "the remaining letters of Balance - or all if you left B empty") - .font(.footnote).bold() - } + Text("Balance", comment: "Balance in main view") + .bold() // in iOS-15 defined for Text, but not for Font (only iOS-16) Text(verbatim: "\(amount.valueStr)") // TODO: CurrencyFormatter? - .font(.talerTitle) + .accessibilityFont(.title) .monospacedDigit() } + .accessibilityFont(.subheadline) } .disabled(false) .accessibilityElement(children: /*@START_MENU_TOKEN@*/.ignore/*@END_MENU_TOKEN@*/) .accessibilityLabel("Balance \(amount.readableDescription)") // TODO: CurrencyFormatter! diff --git a/TalerWallet1/Views/Balances/BalancesSectionView.swift b/TalerWallet1/Views/Balances/BalancesSectionView.swift @@ -83,7 +83,7 @@ struct BalancesSectionView: View { Section { if "KUDOS" == currency && !balance.available.isZero { Text("You can spend these KUDOS in the [Demo Shop](https://shop.demo.taler.net), or send them to another wallet.") - .font(.talerBody) + .accessibilityFont(.body) .multilineTextAlignment(.leading) } NavigationLinksView(balance: balance, @@ -119,7 +119,7 @@ struct BalancesSectionView: View { } if rows == 0 { Text("Some pending transactions") - .font(.talerBody) + .accessibilityFont(.body) } } } @@ -143,7 +143,7 @@ struct BalancesSectionView: View { } } header: { Text(currency) - .font(.talerTitle) + .accessibilityFont(.title2) }.id(sectionID) .task { // if shownSectionID != sectionID { @@ -179,7 +179,7 @@ struct BalancesSectionView: View { reloadOneAction: reloadOneAction) } header: { Text("Recent transactions") - .font(.talerCallout) + .accessibilityFont(.callout) } } } // body diff --git a/TalerWallet1/Views/Balances/PendingRowView.swift b/TalerWallet1/Views/Balances/PendingRowView.swift @@ -12,27 +12,24 @@ struct PendingRowView: View { var body: some View { HStack { + let pendingColor = WalletColors().pendingColor(incoming) Image(systemName: incoming ? "text.badge.plus" : "text.badge.minus") - .font(.largeTitle) -// .foregroundColor(WalletColors().pendingColor) // pending is always gray - .foregroundColor(WalletColors().pendingColor(incoming)) + .foregroundColor(pendingColor) + .accessibilityFont(.largeTitle) .accessibility(hidden: true) Spacer() Text("pending\n" + (incoming ? "incoming" : "outgoing")) - .font(.talerBody) + .accessibilityFont(.body) Spacer() VStack(alignment: .trailing) { let sign = incoming ? "+" : "-" let valueStr = sign + amount.valueStr Text(valueStr) - .font(.talerTitle) - .foregroundColor(WalletColors().pendingColor(incoming)) + .foregroundColor(pendingColor) + .accessibilityFont(.title) .monospacedDigit() -// Text("PENDING") -// .font(.talerCallout) -// .foregroundColor(WalletColors().pendingColor(incoming)) } } .accessibilityElement(children: .combine) diff --git a/TalerWallet1/Views/Balances/UncompletedRowView.swift b/TalerWallet1/Views/Balances/UncompletedRowView.swift @@ -14,7 +14,7 @@ struct UncompletedRowView: View { HStack { Spacer() Text("\(count) uncompleted transactions") - .font(.talerTitle2) + .accessibilityFont(.title2) .foregroundColor(WalletColors().uncompletedColor) Spacer() } diff --git a/TalerWallet1/Views/Exchange/ExchangeListView.swift b/TalerWallet1/Views/Exchange/ExchangeListView.swift @@ -60,7 +60,7 @@ struct ExchangeListView: View { .overlay { if exchanges.isEmpty { Text("No Exchanges yet...") - .font(.talerBody) + .accessibilityFont(.body) } } .task { diff --git a/TalerWallet1/Views/Exchange/ExchangeSectionView.swift b/TalerWallet1/Views/Exchange/ExchangeSectionView.swift @@ -16,6 +16,7 @@ struct ExchangeRowView: View { HStack(spacing: 0) { // can't use the built in Label because it adds the accessory arrow Text(baseURL.trimURL()) + .accessibilityFont(.body) NavigationLink(destination: LazyView { EmptyView() // TODO: Deposit @@ -63,7 +64,7 @@ struct ExchangeSectionView: View { .accessibilityElement(children: .combine) } header: { Text(currency) - .font(.title) + .accessibilityFont(.title) } } } diff --git a/TalerWallet1/Views/Exchange/ManualWithdraw.swift b/TalerWallet1/Views/Exchange/ManualWithdraw.swift @@ -39,7 +39,7 @@ struct ManualWithdraw: View { currency: currency, amountEffective: withdrawalAmountDetails?.amountEffective) Text(exchange.exchangeBaseUrl.trimURL()) .multilineTextAlignment(.center) - .font(.talerBody) + .accessibilityFont(.body) let disabled = (centsToTransfer == 0) || someCoins.invalid || someCoins.tooMany if !disabled { diff --git a/TalerWallet1/Views/Exchange/QuiteSomeCoins.swift b/TalerWallet1/Views/Exchange/QuiteSomeCoins.swift @@ -59,10 +59,10 @@ struct QuiteSomeCoins: View { if someCoins.manyCoins { Text(someCoins.quiteSome ? "Warning: It will take quite some time to encrypt this amount!" : "Warning: It will take some time to encrypt this amount.") - .font(.talerBody) + .foregroundColor(someCoins.quiteSome ? .red : .primary) + .accessibilityFont(.body) .multilineTextAlignment(.leading) .padding(.vertical, 6) - .foregroundColor(someCoins.quiteSome ? .red : .primary) } // warnings } } @@ -71,8 +71,8 @@ struct QuiteSomeCoins: View { : someCoins.tooMany ? "Amount too big for a single withdrawal!" : someCoins.hasFee ? "- \(someCoins.fee) fee" : "No withdrawal fee") - .font(.talerBody) .foregroundColor((someCoins.invalid || someCoins.tooMany || someCoins.hasFee) ? .red : .primary) + .accessibilityFont(.body) // .padding(4) } } diff --git a/TalerWallet1/Views/HelperViews/AgePicker.swift b/TalerWallet1/Views/HelperViews/AgePicker.swift @@ -32,7 +32,7 @@ struct AgePicker: View { HStack { Text("If this wallet belongs to a child or teenager, the generated electronic cash should be age-restricted:") .multilineTextAlignment(.leading) - .font(.talerFootnote) + .accessibilityFont(.footnote) Spacer() }.padding(.top) Picker("Select age", selection: $selectedAge) { @@ -42,7 +42,7 @@ struct AgePicker: View { : "\(index) years").tag(index) } } - .font(.talerBody) + .accessibilityFont(.body) } } } diff --git a/TalerWallet1/Views/HelperViews/AmountView.swift b/TalerWallet1/Views/HelperViews/AmountView.swift @@ -15,15 +15,15 @@ struct AmountView: View { Text(title) .fixedSize(horizontal: false, vertical: true) // wrap in scrollview .multilineTextAlignment(.leading) - .font(.talerBody) + .accessibilityFont(.body) HStack { Spacer() Text(value) .fixedSize(horizontal: false, vertical: true) // wrap in scrollview .multilineTextAlignment(.center) - .font(large ? .talerTitle : .talerTitle2) -// .fontWeight(large ? .medium : .regular) // @available(iOS 16.0, *) .foregroundColor(color) + .accessibilityFont(large ? .title : .title2) +// .fontWeight(large ? .medium : .regular) // @available(iOS 16.0, *) .monospacedDigit() Spacer() } diff --git a/TalerWallet1/Views/HelperViews/Buttons.swift b/TalerWallet1/Views/HelperViews/Buttons.swift @@ -18,77 +18,76 @@ extension ShapeStyle where Self == Color { } struct HamburgerButton : View { - var font: Font? let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "line.3.horizontal") } - .font(font ?? .talerTitle) + .accessibilityFont(.title) + .accessibilityLabel("Main Menu") } } struct QRButton : View { - var font: Font? let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "qrcode.viewfinder") } - .font(font ?? .talerTitle) + .accessibilityFont(.title) .accessibilityLabel("Scan QR codes") } } struct PlusButton : View { - var font: Font? let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "plus") } - .font(font ?? .talerTitle) + .accessibilityFont(.title) + .accessibilityLabel("Add...") } } struct ArrowUpButton : View { - var font: Font? let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "arrow.up.to.line") } - .font(font ?? .talerTitle3) + .accessibilityFont(.title2) + .accessibilityLabel("Scroll up") } } struct ArrowDownButton : View { - var font: Font? let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "arrow.down.to.line") } - .font(font ?? .talerTitle3) + .accessibilityFont(.title2) + .accessibilityLabel("Scroll down") } } struct ReloadButton : View { let disabled: Bool - var font: Font? let action: () -> Void var body: some View { Button(action: action) { Image(systemName: "arrow.clockwise") } - .font(font ?? .talerTitle) - .disabled(disabled) + .accessibilityFont(.title) + .accessibilityLabel("Reload") + .disabled(disabled) } } @@ -172,8 +171,8 @@ struct TalerButtonStyle: ButtonStyle { : Alignment.trailing configuration.label .multilineTextAlignment(aligned) - .font(.talerTitle3) -// .font(narrow ? .talerTitle3 : .talerTitle2) + .accessibilityFont(.title3) +// narrow ? .title3 : .title2 .frame(minWidth: 0, maxWidth: narrow ? nil : .infinity, alignment: aligned2) .padding(.vertical, 10) .padding(.horizontal, 6) diff --git a/TalerWallet1/Views/HelperViews/CopyShare.swift b/TalerWallet1/Views/HelperViews/CopyShare.swift @@ -32,7 +32,7 @@ struct CopyButton: View { } } } - .font(.talerBody) + .accessibilityFont(.body) .disabled(!isEnabled) } } @@ -55,7 +55,7 @@ struct ShareButton: View { Text("Share") } } - .font(.talerBody) + .accessibilityFont(.body) .disabled(!isEnabled) } } diff --git a/TalerWallet1/Views/HelperViews/CurrencyInputView.swift b/TalerWallet1/Views/HelperViews/CurrencyInputView.swift @@ -16,12 +16,12 @@ struct CurrencyInputView: View { VStack (alignment: .leading) { Text(title) // .padding(.top) - .font(.talerTitle3) + .accessibilityFont(.title3) currencyField .frame(maxWidth: .infinity, alignment: .trailing) .foregroundColor(WalletColors().fieldForeground) // text color .background(WalletColors().fieldBackground) - .font(.talerTitle2) + .accessibilityFont(.title2) .textFieldStyle(.roundedBorder) }.onAppear { // make CurrencyField show the keyboard after 0.4 seconds if hasBeenShown { diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift @@ -17,11 +17,11 @@ struct QRCodeDetailView: View { VStack (alignment: .leading) { Text("Either copy and send this link:") .multilineTextAlignment(.leading) - .font(.talerTitle3) + .accessibilityFont(.title3) .padding(.vertical) Text(talerURI) - .font(.talerTitle3) + .accessibilityFont(.title3) .multilineTextAlignment(.center) .fixedSize(horizontal: false, vertical: true) // wrap in scrollview .padding(.bottom) @@ -41,7 +41,7 @@ struct QRCodeDetailView: View { Text(amountStr) .fixedSize(horizontal: false, vertical: true) // wrap in scrollview // .padding(.top, 30) - .font(.talerTitle3) + .accessibilityFont(.title3) HStack { Spacer() QRGeneratorView(text: talerURI) diff --git a/TalerWallet1/Views/HelperViews/TextFieldAlert.swift b/TalerWallet1/Views/HelperViews/TextFieldAlert.swift @@ -17,7 +17,9 @@ struct TextFieldAlert: ViewModifier { .disabled(isPresented) if isPresented { VStack { - Text(title).font(.talerHeadline).padding() + Text(title) + .accessibilityFont(.headline) + .padding() TextField(placeholder, text: $text).textFieldStyle(.roundedBorder).padding() Divider() HStack { @@ -34,7 +36,7 @@ struct TextFieldAlert: ViewModifier { action(text) withAnimation { isPresented.toggle() } } -// .font(.talerBody) TODO: check +// .accessibilityFont(.talerBody) TODO: check Spacer() } } diff --git a/TalerWallet1/Views/HelperViews/TransactionButton.swift b/TalerWallet1/Views/HelperViews/TransactionButton.swift @@ -69,7 +69,7 @@ struct TransactionButton: View { } } } - .font(.talerTitle2) + .accessibilityFont(.title2) .frame(maxWidth: .infinity) }) .buttonStyle(.bordered) diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -20,6 +20,7 @@ struct MainView: View { @State private var sheetPresented = false @State private var urlToOpen: URL? = nil @Binding var soundPlayed: Bool + @AppStorage("talerFont") var talerFont: Int = 0 // extension mustn't define this, so it must be here func sheetDismissed() -> Void { symLog.log("sheet dismiss") @@ -31,7 +32,7 @@ struct MainView: View { #endif Group { if controller.backendState == .ready { - Content(symLog: symLog) + Content(symLog: symLog, talerFont: $talerFont) // any change to rootViewId triggers popToRootView behaviour .id(viewState.rootViewId) .onAppear() { @@ -67,7 +68,7 @@ struct MainView: View { extension MainView { struct Content: View { let symLog: SymLogV? - + @Binding var talerFont: Int @State var sidebarVisible: Bool = false func hamburgerAction() { sidebarVisible = !sidebarVisible diff --git a/TalerWallet1/Views/Main/SideBarView.swift b/TalerWallet1/Views/Main/SideBarView.swift @@ -26,7 +26,7 @@ struct SideBarView: View { VStack(spacing: 10) { let gnuTaler = String("GNU Taler") // this should NOT be translated Link(gnuTaler, destination: URL(string:"https://taler.net")!) - .font(.talerLargeTitle) //.bold() iOS 16 + .accessibilityFont(.largeTitle) .padding(.top, 30) RotatingTaler(size: 100, rotationEnabled: $rotationEnabled) .onTapGesture { @@ -48,7 +48,7 @@ struct SideBarView: View { } .padding() .buttonStyle(.borderless) - .font(.talerTitle2) + .accessibilityFont(.title2) .disabled(i == currentView) .accessibilityHidden(i == currentView) // don't suggest the current item } diff --git a/TalerWallet1/Views/Main/WalletEmptyView.swift b/TalerWallet1/Views/Main/WalletEmptyView.swift @@ -28,7 +28,7 @@ struct WalletEmptyView: View { } } .listStyle(myListStyle.style).anyView - .font(.talerTitle2) + .accessibilityFont(.title2) .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.all)) .onAppear() { DebugViewC.shared.setViewID(VIEW_EMPTY) // 10 diff --git a/TalerWallet1/Views/Payment/PayTemplateView.swift b/TalerWallet1/Views/Payment/PayTemplateView.swift @@ -67,7 +67,7 @@ struct PayTemplateView: View { // TODO: payment: popup with all possible exchanges, check fees } else if let balanceDetails = preparePayResult.balanceDetails { // Insufficient Text("You don't have enough \(currency)") - .font(.talerBody) + .accessibilityFont(.body) ThreeAmountsView(topTitle: topTitle, topAmount: raw, fee: nil, bottomTitle: String(localized: "\(currency) available:"), @@ -77,7 +77,7 @@ struct PayTemplateView: View { } else { // TODO: Error - neither effective nor balanceDetails Text("Error") - .font(.talerBody) + .accessibilityFont(.body) } } .listStyle(myListStyle.style).anyView diff --git a/TalerWallet1/Views/Payment/PaymentView.swift b/TalerWallet1/Views/Payment/PaymentView.swift @@ -60,7 +60,7 @@ struct PaymentView: View { // TODO: payment: popup with all possible exchanges, check fees } else if let balanceDetails = preparePayResult.balanceDetails { // Insufficient Text("You don't have enough \(currency)") - .font(.talerBody) + .accessibilityFont(.body) ThreeAmountsView(topTitle: topTitle, topAmount: raw, fee: nil, bottomTitle: String(localized: "\(currency) available:"), @@ -70,7 +70,7 @@ struct PaymentView: View { } else { // TODO: Error - neither effective nor balanceDetails Text("Error") - .font(.talerBody) + .accessibilityFont(.body) } } .listStyle(myListStyle.style).anyView diff --git a/TalerWallet1/Views/Peer2peer/PaymentPurpose.swift b/TalerWallet1/Views/Peer2peer/PaymentPurpose.swift @@ -19,7 +19,7 @@ struct PaymentPurpose: View { @FocusState private var isFocused: Bool let formatter = CurrencyFormatter.shared // TODO: based on currency - let buttonFont: Font = .title2 +// let buttonFont: Font = .talerTitle2 private var label: String { let mag = pow(10, formatter.maximumFractionDigits) @@ -36,10 +36,10 @@ struct PaymentPurpose: View { VStack(alignment: .leading, spacing: 6) { Text("Purpose:") .padding(.top) - .font(.title3) + .accessibilityFont(.title3) TextField("Purpose", text: $summary) - .font(.title) + .accessibilityFont(.title) .foregroundColor(WalletColors().fieldForeground) // text color .background(WalletColors().fieldBackground) .textFieldStyle(.roundedBorder) @@ -56,7 +56,7 @@ struct PaymentPurpose: View { } // maximum 100 characters Text("Expires in:") - .font(.title3) + .accessibilityFont(.title3) SelectDays(selected: $expireDays, maxExpiration: THIRTYDAYS) .disabled(false) @@ -70,7 +70,7 @@ struct PaymentPurpose: View { summary: summary, expireDays: expireDays) }) { Text("Request \(label) \(scopeInfo.currency)") - .font(buttonFont) +// .accessibilityFont(buttonFont) } .buttonStyle(TalerButtonStyle(type: .prominent)) .disabled(disabled) diff --git a/TalerWallet1/Views/Peer2peer/SendAmount.swift b/TalerWallet1/Views/Peer2peer/SendAmount.swift @@ -44,12 +44,12 @@ struct SendAmount: View { VStack(alignment: .trailing) { let available = amountAvailable.readableDescription Text("Available: \(available)") - .font(.talerTitle3) + .accessibilityFont(.title3) .padding(.bottom, 2) CurrencyInputView(currencyField: currencyField, title: String(localized: "Amount to send:")) Text("+ \(fee) payment fee") - .font(.talerBody) + .accessibilityFont(.body) .foregroundColor(.red) .padding(4) diff --git a/TalerWallet1/Views/Peer2peer/SendPurpose.swift b/TalerWallet1/Views/Peer2peer/SendPurpose.swift @@ -19,7 +19,6 @@ struct SendPurpose: View { let formatter = CurrencyFormatter.shared // TODO: based on currency - let buttonFont: Font = .title2 private var value: String { let mag = pow(10, formatter.maximumFractionDigits) return formatter.string(for: Decimal(centsToTransfer) / mag) ?? "" @@ -31,16 +30,16 @@ struct SendPurpose: View { VStack (spacing: 6) { Text(amount.readableDescription) Text("+ \(fee) payment fee") - .font(.talerBody) + .accessibilityFont(.body) .foregroundColor(.red) VStack(alignment: .leading, spacing: 6) { Text("Purpose:") - .font(.talerTitle2) + .accessibilityFont(.title2) .padding(.top) if #available(iOS 16.0, *) { TextField("Purpose", text: $summary, axis: .vertical) - .font(.talerTitle2) + .accessibilityFont(.title2) .lineLimit(2...) .foregroundColor(WalletColors().fieldForeground) // text color .background(WalletColors().fieldBackground) @@ -53,7 +52,7 @@ struct SendPurpose: View { } } else { TextField("Purpose", text: $summary) - .font(.talerTitle) + .accessibilityFont(.title) // .lineLimit(2...5) // lineLimit' is only available in iOS 16.0 or newer .foregroundColor(WalletColors().fieldForeground) // text color .background(WalletColors().fieldBackground) @@ -69,11 +68,11 @@ struct SendPurpose: View { HStack{ Spacer() Text(verbatim: "\(summary.count)/100") - .font(.talerBody) + .accessibilityFont(.body) } // maximum 100 characters Text("Expires in:") - .font(.talerTitle3) + .accessibilityFont(.title3) // TODO: compute max Expiration day from peerPushCheck to disable 30 (and even 7) SelectDays(selected: $expireDays, maxExpiration: THIRTYDAYS) @@ -87,8 +86,7 @@ struct SendPurpose: View { amountToReceive: nil, summary: summary, expireDays: expireDays) }) { - Text("Send \(label) \(amountAvailable.currencyStr) now", comment: "first is value, second currencyString") - .font(buttonFont) + Text("Send \(value) \(amountAvailable.currencyStr) now", comment: "first is value, second currencyString") // TODO: currency formatter } .buttonStyle(TalerButtonStyle(type: .prominent)) .disabled(disabled) diff --git a/TalerWallet1/Views/Settings/Pending/PendingOpView.swift b/TalerWallet1/Views/Settings/Pending/PendingOpView.swift @@ -18,7 +18,7 @@ struct PendingOpView: View { Text(baseURL) } Text(pendingOp.id) - .font(.talerCaption) + .accessibilityFont(.caption) let isLongPolling = "isLongPolling" Toggle(isLongPolling, isOn: $polling) .disabled(true) @@ -30,10 +30,11 @@ struct PendingOpView: View { .disabled(true) let dateString = TalerDater.dateString(from: pendingOp.timestampDue) Text(dateString) - }.font(.talerBody) + } + .accessibilityFont(.body) } header: { Text(pendingOp.type) - .font(.talerTitle2) + .accessibilityFont(.title2) } // .textCase(nil) // don't capitalize .onAppear { diff --git a/TalerWallet1/Views/Settings/SettingsItem.swift b/TalerWallet1/Views/Settings/SettingsItem.swift @@ -20,16 +20,16 @@ struct SettingsItem<Content: View>: View { VStack { Text(name) .frame(maxWidth: .infinity, alignment: .leading) - .font(.talerTitle2) + .accessibilityFont(.title2) .padding([.bottom], 0.01) if let desc = description { Text(desc) .frame(maxWidth: .infinity, alignment: .leading) - .font(.talerCaption) + .accessibilityFont(.caption) } } content() - .font(.talerBody) + .accessibilityFont(.body) }.padding([.bottom], 4) } } @@ -43,7 +43,7 @@ struct SettingsToggle: View { var body: some View { VStack { Toggle(name, isOn: $value.animation()) - .font(.talerTitle2) + .accessibilityFont(.title2) .onChange(of: value) { value in action() } @@ -51,7 +51,7 @@ struct SettingsToggle: View { if let desc = description { Text(desc) .frame(maxWidth: .infinity, alignment: .leading) - .font(.talerCaption) + .accessibilityFont(.caption) } }.padding([.bottom], 4) } @@ -71,7 +71,7 @@ struct SettingsFont: View { Text(fonts[index]).tag(index) }) }) - .font(.talerTitle2) + .accessibilityFont(.title2) .pickerStyle(.menu) .onAppear() { withAnimation { selected = value } @@ -89,12 +89,12 @@ struct SettingsStyle: View { var body: some View { HStack { Text(title) - .font(.talerTitle2) + .accessibilityFont(.title2) Spacer() Picker(selection: $myListStyle) { ForEach(MyListStyle.allCases, id: \.self) { Text($0.displayName.capitalized).tag($0) - .font(.talerTitle2) + .accessibilityFont(.title2) } } label: {} .pickerStyle(.menu) @@ -120,12 +120,12 @@ struct SettingsSpeaker: View { let image = imageName(value) HStack { Text(name) - .font(.talerTitle2) + .accessibilityFont(.title2) Text(" ") - .font(.talerLargeTitle) + .accessibilityFont(.largeTitle) Spacer() Image(systemName: image.0) - .font(.talerLargeTitle) + .accessibilityFont(.largeTitle) .accessibilityLabel(image.1) .onTapGesture { if value > 0 { @@ -144,7 +144,7 @@ struct SettingsSpeaker: View { if let desc = description { Text(desc) .frame(maxWidth: .infinity, alignment: .leading) - .font(.talerCaption) + .accessibilityFont(.caption) } }.padding([.bottom], 4) } diff --git a/TalerWallet1/Views/Sheets/URLSheet.swift b/TalerWallet1/Views/Sheets/URLSheet.swift @@ -31,7 +31,7 @@ struct URLSheet: View { default: // Error view VStack { Text("unknown command") - .font(.talerTitle) + .accessibilityFont(.title) Text(controller.messageForSheet ?? urlToOpen.absoluteString) } .navigationTitle(navTitle) diff --git a/TalerWallet1/Views/Transactions/ManualDetails.swift b/TalerWallet1/Views/Transactions/ManualDetails.swift @@ -59,7 +59,8 @@ struct ManualDetails: View { .disabled(false) Spacer() } .listRowSeparator(.automatic) - }.font(.talerBody) + } + .accessibilityFont(.body) } } } diff --git a/TalerWallet1/Views/Transactions/ThreeAmounts.swift b/TalerWallet1/Views/Transactions/ThreeAmounts.swift @@ -68,12 +68,12 @@ struct ThreeAmountsView: View { VStack(alignment: .leading) { Text("Using Exchange:") .multilineTextAlignment(.leading) - .font(.talerBody) + .accessibilityFont(.body) HStack { Spacer() Text(baseURL.trimURL()) .multilineTextAlignment(.center) - .font(large ? .talerTitle2 : .talerTitle3) + .accessibilityFont(large ? .title2 : .title3) // .fontWeight(large ? .medium : .regular) // @available(iOS 16.0, *) .foregroundColor(labelColor) Spacer() diff --git a/TalerWallet1/Views/Transactions/TransactionDetailView.swift b/TalerWallet1/Views/Transactions/TransactionDetailView.swift @@ -66,7 +66,7 @@ struct TransactionDetailView: View { } } } // Suspend + Resume buttons Text(dateString) - .font(.talerTitle2) + .accessibilityFont(.title2) .listRowSeparator(.hidden) HStack { Text(verbatim: "|") // only reason for this leading-aligned text is to get a nice full length listRowSeparator @@ -75,7 +75,7 @@ struct TransactionDetailView: View { Spacer() Text("Status: \(common.txState.major.localizedState)") } .listRowSeparator(.automatic) - .font(.talerTitle2) + .accessibilityFont(.title2) SwitchCase(transaction: $transaction, hasDone: doneAction != nil) if transaction.isAbortable { if let abortAction { @@ -174,8 +174,9 @@ struct TransactionDetailView: View { let pending = transaction.isPending Group { switch transaction { - case .dummy(let dummyTransaction): - Text("").font(.talerBody) + case .dummy(_): + Text("") + .accessibilityFont(.body) case .withdrawal(let withdrawalTransaction): let details = withdrawalTransaction.details if pending { @@ -208,7 +209,7 @@ struct TransactionDetailView: View { case .payment(let paymentTransaction): let details = paymentTransaction.details Text(details.info.summary) - .font(.talerTitle2) + .accessibilityFont(.title2) .lineLimit(4) .padding(.bottom) ThreeAmountsSheet(common: common, topTitle: String(localized: "Sum to be paid:"), @@ -228,7 +229,7 @@ struct TransactionDetailView: View { case .peer2peer(let p2pTransaction): let details = p2pTransaction.details // TODO: details Text(details.info.summary) - .font(.talerTitle2) + .accessibilityFont(.title2) .lineLimit(4) .padding(.bottom) // TODO: isSendCoins should show QR only while not expired @@ -237,7 +238,7 @@ struct TransactionDetailView: View { if hasDone { Text("QR code and link can also be scanned or copied / shared from Transactions later.") .multilineTextAlignment(.leading) - .font(.talerSubheadline) + .accessibilityFont(.subheadline) .padding(.top) } } @@ -264,7 +265,7 @@ struct TransactionDetailView: View { } else if keys.contains(EXCHANGEBASEURL) { if let baseURL = details[EXCHANGEBASEURL] { Text("from \(baseURL.trimURL())") - .font(.talerTitle2) + .accessibilityFont(.title2) .padding(.bottom) } } diff --git a/TalerWallet1/Views/Transactions/TransactionRowView.swift b/TalerWallet1/Views/Transactions/TransactionRowView.swift @@ -12,11 +12,11 @@ struct TransactionRowCenter: View { var body: some View { VStack(alignment: .leading) { Text(centerTop) - .font(.talerHeadline) - .fontWeight(.medium) + .accessibilityFont(.headline) +// .fontWeight(.medium) iOS 16 .padding(.bottom, -2.0) Text(centerBottom) - .font(.talerCallout) + .accessibilityFont(.callout) } } } @@ -41,7 +41,7 @@ struct TransactionRowView: View { HStack(spacing: 6) { Image(systemName: incoming ? "text.badge.plus" : "text.badge.minus") .foregroundColor(foreColor) - .font(.talerLargeTitle) + .accessibilityFont(.largeTitle) .accessibility(hidden: true) TransactionRowCenter(centerTop: transaction.localizedType, @@ -51,8 +51,8 @@ struct TransactionRowView: View { let sign = incoming ? "+" : "-" let valueStr = sign + amount.valueStr Text(valueStr) - .font(.talerTitle) .foregroundColor(foreColor) + .accessibilityFont(.title) .monospacedDigit() } } diff --git a/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift b/TalerWallet1/Views/Transactions/TransactionsEmptyView.swift @@ -19,7 +19,7 @@ struct TransactionsEmptyView: View { Section { Text("There are no transactions for \(currency).") } - .font(.talerTitle2) + .accessibilityFont(.title2) } .listStyle(myListStyle.style).anyView // .padding(.vertical) diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawProgressView.swift b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawProgressView.swift @@ -15,7 +15,7 @@ struct WithdrawProgressView: View { HStack { Spacer() Text(message) - .font(.talerTitle) + .accessibilityFont(.title) Spacer() } Spacer() diff --git a/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift b/TalerWallet1/Views/WithdrawBankIntegrated/WithdrawTOSView.swift @@ -95,18 +95,18 @@ extension WithdrawTOSView { if #available(iOS 16.0, *) { Section { Text(term5) - .font(.talerFootnote) + .accessibilityFont(.footnote) .foregroundColor(Color(UIColor.label)) } } else { Text(term5) - .font(.talerFootnote) + .accessibilityFont(.footnote) .foregroundColor(Color(UIColor.label)) } } else { Section { Text(term0) - .font(.talerBody) + .accessibilityFont(.body) } } }.safeAreaInset(edge: .bottom) {