From c6bf8df24f65ce1cd992358d814cc7af0ec42a37 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 21 Feb 2022 12:47:32 +0000 Subject: [PATCH] Add a `SharedFont` type to `ElementFonts`. Using iOS 13 as availability so the properties can be simplified when support for iOS 12 is dropped. --- DesignKit/Source/FontsSwiftUI.swift | 44 ++-- DesignKit/Source/FontsUIkit.swift | 40 ++-- DesignKit/Variants/Fonts/ElementFonts.swift | 246 ++++++++++++++++---- changelog.d/5027.bugfix | 1 + 4 files changed, 247 insertions(+), 84 deletions(-) create mode 100644 changelog.d/5027.bugfix diff --git a/DesignKit/Source/FontsSwiftUI.swift b/DesignKit/Source/FontsSwiftUI.swift index ddf6a17542..a12a537ff4 100644 --- a/DesignKit/Source/FontsSwiftUI.swift +++ b/DesignKit/Source/FontsSwiftUI.swift @@ -23,7 +23,7 @@ import SwiftUI @available(iOS 14.0, *) public struct FontSwiftUI: Fonts { - public let uiFonts: ElementFonts + public let uiFonts: FontsUIKit public var largeTitle: Font @@ -66,27 +66,27 @@ public struct FontSwiftUI: Fonts { public var caption2SB: Font public init(values: ElementFonts) { - self.uiFonts = values + self.uiFonts = FontsUIKit(values: values) - self.largeTitle = Font(values.largeTitle) - self.largeTitleB = Font(values.largeTitleB) - self.title1 = Font(values.title1) - self.title1B = Font(values.title1B) - self.title2 = Font(values.title2) - self.title2B = Font(values.title2B) - self.title3 = Font(values.title3) - self.title3SB = Font(values.title3SB) - self.headline = Font(values.headline) - self.subheadline = Font(values.subheadline) - self.body = Font(values.body) - self.bodySB = Font(values.bodySB) - self.callout = Font(values.callout) - self.calloutSB = Font(values.calloutSB) - self.footnote = Font(values.footnote) - self.footnoteSB = Font(values.footnoteSB) - self.caption1 = Font(values.caption1) - self.caption1SB = Font(values.caption1SB) - self.caption2 = Font(values.caption2) - self.caption2SB = Font(values.caption2SB) + self.largeTitle = values.largeTitle.font + self.largeTitleB = values.largeTitleB.font + self.title1 = values.title1.font + self.title1B = values.title1B.font + self.title2 = values.title2.font + self.title2B = values.title2B.font + self.title3 = values.title3.font + self.title3SB = values.title3SB.font + self.headline = values.headline.font + self.subheadline = values.subheadline.font + self.body = values.body.font + self.bodySB = values.bodySB.font + self.callout = values.callout.font + self.calloutSB = values.calloutSB.font + self.footnote = values.footnote.font + self.footnoteSB = values.footnoteSB.font + self.caption1 = values.caption1.font + self.caption1SB = values.caption1SB.font + self.caption2 = values.caption2.font + self.caption2SB = values.caption2SB.font } } diff --git a/DesignKit/Source/FontsUIkit.swift b/DesignKit/Source/FontsUIkit.swift index 3067d03a1d..ec65cdaa66 100644 --- a/DesignKit/Source/FontsUIkit.swift +++ b/DesignKit/Source/FontsUIkit.swift @@ -63,25 +63,25 @@ import UIKit public var caption2SB: UIFont public init(values: ElementFonts) { - self.largeTitle = values.largeTitle - self.largeTitleB = values.largeTitleB - self.title1 = values.title1 - self.title1B = values.title1B - self.title2 = values.title2 - self.title2B = values.title2B - self.title3 = values.title3 - self.title3SB = values.title3SB - self.headline = values.headline - self.subheadline = values.subheadline - self.body = values.body - self.bodySB = values.bodySB - self.callout = values.callout - self.calloutSB = values.calloutSB - self.footnote = values.footnote - self.footnoteSB = values.footnoteSB - self.caption1 = values.caption1 - self.caption1SB = values.caption1SB - self.caption2 = values.caption2 - self.caption2SB = values.caption2SB + self.largeTitle = values.largeTitle.uiFont + self.largeTitleB = values.largeTitleB.uiFont + self.title1 = values.title1.uiFont + self.title1B = values.title1B.uiFont + self.title2 = values.title2.uiFont + self.title2B = values.title2B.uiFont + self.title3 = values.title3.uiFont + self.title3SB = values.title3SB.uiFont + self.headline = values.headline.uiFont + self.subheadline = values.subheadline.uiFont + self.body = values.body.uiFont + self.bodySB = values.bodySB.uiFont + self.callout = values.callout.uiFont + self.calloutSB = values.calloutSB.uiFont + self.footnote = values.footnote.uiFont + self.footnoteSB = values.footnoteSB.uiFont + self.caption1 = values.caption1.uiFont + self.caption1SB = values.caption1SB.uiFont + self.caption2 = values.caption2.uiFont + self.caption2SB = values.caption2SB.uiFont } } diff --git a/DesignKit/Variants/Fonts/ElementFonts.swift b/DesignKit/Variants/Fonts/ElementFonts.swift index 6612d3dc13..d7538c9056 100644 --- a/DesignKit/Variants/Fonts/ElementFonts.swift +++ b/DesignKit/Variants/Fonts/ElementFonts.swift @@ -14,12 +14,42 @@ // limitations under the License. // -import UIKit +import SwiftUI /// Fonts at https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1362%3A0 @objcMembers public class ElementFonts { + // MARK: - Types + + /// A wrapper to provide both a `UIFont` and a SwiftUI `Font` in the same type. + /// The need for this comes from `Font` not adapting for dynamic type until the app + /// is restarted (or working at all in Xcode Previews) when initialised from a `UIFont` + /// (even if that font was created with the appropriate metrics). + public struct SharedFont { + public let uiFont: UIFont + /// The underlying font for the `font` property. This is stored + /// as an optional `Any` due to unavailability on iOS 12. + private let _font: Any? + + @available(iOS 13.0, *) + public var font: Font { + _font as! Font + } + + @available(iOS, deprecated: 13.0, message: "Use init(uiFont:font:) instead and remove this initialiser.") + init(uiFont: UIFont) { + self.uiFont = uiFont + self._font = nil + } + + @available(iOS 13.0, *) + init(uiFont: UIFont, font: Font) { + self.uiFont = uiFont + self._font = font + } + } + // MARK: - Setup public init() { @@ -35,85 +65,217 @@ public class ElementFonts { } // MARK: - Fonts protocol -extension ElementFonts: Fonts { +extension ElementFonts: Fonts { - public var largeTitle: UIFont { - return self.font(forTextStyle: .largeTitle) + public var largeTitle: SharedFont { + let uiFont = self.font(forTextStyle: .largeTitle) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .largeTitle) + } else { + return SharedFont(uiFont: uiFont) + } } - public var largeTitleB: UIFont { - return self.largeTitle.vc_bold + public var largeTitleB: SharedFont { + let uiFont = self.largeTitle.uiFont.vc_bold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .largeTitle.bold()) + } else { + return SharedFont(uiFont: uiFont) + } } - public var title1: UIFont { - return self.font(forTextStyle: .title1) + public var title1: SharedFont { + let uiFont = self.font(forTextStyle: .title1) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .title) + } else { + return SharedFont(uiFont: uiFont) + } } - public var title1B: UIFont { - return self.title1.vc_bold + public var title1B: SharedFont { + let uiFont = self.title1.uiFont.vc_bold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .title.bold()) + } else { + return SharedFont(uiFont: uiFont) + } } - public var title2: UIFont { - return self.font(forTextStyle: .title2) + public var title2: SharedFont { + let uiFont = self.font(forTextStyle: .title2) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: Font(uiFont)) + } else if #available(iOS 14.0, *) { + return SharedFont(uiFont: uiFont, font: .title2) + } else { + return SharedFont(uiFont: uiFont) + } } - public var title2B: UIFont { - return self.title2.vc_bold + public var title2B: SharedFont { + let uiFont = self.title2.uiFont.vc_bold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: Font(uiFont)) + } else if #available(iOS 14.0, *) { + return SharedFont(uiFont: uiFont, font: .title2.bold()) + } else { + return SharedFont(uiFont: uiFont) + } } - public var title3: UIFont { - return self.font(forTextStyle: .title3) + public var title3: SharedFont { + let uiFont = self.font(forTextStyle: .title3) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: Font(uiFont)) + } else if #available(iOS 14.0, *) { + return SharedFont(uiFont: uiFont, font: .title3) + } else { + return SharedFont(uiFont: uiFont) + } } - public var title3SB: UIFont { - return self.title3.vc_semiBold + public var title3SB: SharedFont { + let uiFont = self.title3.uiFont.vc_semiBold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: Font(uiFont)) + } else if #available(iOS 14.0, *) { + return SharedFont(uiFont: uiFont, font: .title3.weight(.semibold)) + } else { + return SharedFont(uiFont: uiFont) + } } - public var headline: UIFont { - return self.font(forTextStyle: .headline) + public var headline: SharedFont { + let uiFont = self.font(forTextStyle: .headline) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .headline) + } else { + return SharedFont(uiFont: uiFont) + } } - public var subheadline: UIFont { - return self.font(forTextStyle: .subheadline) + public var subheadline: SharedFont { + let uiFont = self.font(forTextStyle: .subheadline) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .subheadline) + } else { + return SharedFont(uiFont: uiFont) + } } - public var body: UIFont { - return self.font(forTextStyle: .body) + public var body: SharedFont { + let uiFont = self.font(forTextStyle: .body) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .body) + } else { + return SharedFont(uiFont: uiFont) + } } - public var bodySB: UIFont { - return self.body.vc_semiBold + public var bodySB: SharedFont { + let uiFont = self.body.uiFont.vc_semiBold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .body.weight(.semibold)) + } else { + return SharedFont(uiFont: uiFont) + } } - public var callout: UIFont { - return self.font(forTextStyle: .callout) + public var callout: SharedFont { + let uiFont = self.font(forTextStyle: .callout) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .callout) + } else { + return SharedFont(uiFont: uiFont) + } } - public var calloutSB: UIFont { - return self.callout.vc_semiBold + public var calloutSB: SharedFont { + let uiFont = self.callout.uiFont.vc_semiBold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .callout.weight(.semibold)) + } else { + return SharedFont(uiFont: uiFont) + } } - public var footnote: UIFont { - return self.font(forTextStyle: .footnote) + public var footnote: SharedFont { + let uiFont = self.font(forTextStyle: .footnote) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .footnote) + } else { + return SharedFont(uiFont: uiFont) + } } - public var footnoteSB: UIFont { - return self.footnote.vc_semiBold + public var footnoteSB: SharedFont { + let uiFont = self.footnote.uiFont.vc_semiBold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .footnote.weight(.semibold)) + } else { + return SharedFont(uiFont: uiFont) + } } - public var caption1: UIFont { - return self.font(forTextStyle: .caption1) + public var caption1: SharedFont { + let uiFont = self.font(forTextStyle: .caption1) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .caption) + } else { + return SharedFont(uiFont: uiFont) + } } - public var caption1SB: UIFont { - return self.caption1.vc_semiBold + public var caption1SB: SharedFont { + let uiFont = self.caption1.uiFont.vc_semiBold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: .caption.weight(.semibold)) + } else { + return SharedFont(uiFont: uiFont) + } } - public var caption2: UIFont { - return self.font(forTextStyle: .caption2) + public var caption2: SharedFont { + let uiFont = self.font(forTextStyle: .caption2) + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: Font(uiFont)) + } else if #available(iOS 14.0, *) { + return SharedFont(uiFont: uiFont, font: .caption2) + } else { + return SharedFont(uiFont: uiFont) + } } - public var caption2SB: UIFont { - return self.caption2.vc_semiBold + public var caption2SB: SharedFont { + let uiFont = self.caption2.uiFont.vc_semiBold + + if #available(iOS 13.0, *) { + return SharedFont(uiFont: uiFont, font: Font(uiFont)) + } else if #available(iOS 14.0, *) { + return SharedFont(uiFont: uiFont, font: .caption2.weight(.semibold)) + } else { + return SharedFont(uiFont: uiFont) + } } } diff --git a/changelog.d/5027.bugfix b/changelog.d/5027.bugfix new file mode 100644 index 0000000000..0b947aed0a --- /dev/null +++ b/changelog.d/5027.bugfix @@ -0,0 +1 @@ +Fonts: Fix dynamic type only working after a fresh launch on SwiftUI views. \ No newline at end of file