Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>UIAppFonts</key>
<array>
<string>InterVariable-Italic.ttf</string>
<string>InterVariable.ttf</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,22 @@ extension StyleGuideFont {
self.textStyle = textStyle
}

/// Returns a `StyleGuideFont` that uses the DMSans font.
/// Returns a `StyleGuideFont` that uses the Inter font.
///
/// - Parameters:
/// - lineHeight: The line height for this style, in px.
/// - size: The default font size for this style, in px.
/// - textStyle: The text style for the font, used to determine how the font scales with dynamic type.
/// - Returns: A `StyleGuideFont` that uses the DMSans font.
/// - Returns: A `StyleGuideFont` that uses the Inter font.
///
static func dmSans(lineHeight: CGFloat, size: CGFloat, textStyle: SwiftUI.Font.TextStyle) -> StyleGuideFont {
static func inter(lineHeight: CGFloat, size: CGFloat, textStyle: SwiftUI.Font.TextStyle) -> StyleGuideFont {
FontFamily.registerAllCustomFonts()
return self.init(font: FontFamily.DMSans.regular, lineHeight: lineHeight, size: size, textStyle: textStyle)
return self.init(
font: FontFamily.InterVariable.regular,
lineHeight: lineHeight,
size: size,
textStyle: textStyle,
)
}

/// Returns a new `StyleGuideFont` with same properties but different font.
Expand All @@ -86,55 +91,55 @@ extension StyleGuideFont {

public extension StyleGuideFont {
/// The font for the huge title style.
static let hugeTitle = StyleGuideFont.dmSans(lineHeight: 41, size: 34, textStyle: .largeTitle)
static let hugeTitle = StyleGuideFont.inter(lineHeight: 41, size: 34, textStyle: .largeTitle)

/// The font for the large title style.
static let largeTitle = StyleGuideFont.dmSans(lineHeight: 32, size: 26, textStyle: .largeTitle)
static let largeTitle = StyleGuideFont.inter(lineHeight: 32, size: 26, textStyle: .largeTitle)

/// The font for the title style.
static let title = StyleGuideFont.dmSans(lineHeight: 28, size: 22, textStyle: .title)
static let title = StyleGuideFont.inter(lineHeight: 28, size: 22, textStyle: .title)

/// The font for the title2 style.
static let title2 = StyleGuideFont.dmSans(lineHeight: 22, size: 17, textStyle: .title2)
static let title2 = StyleGuideFont.inter(lineHeight: 22, size: 17, textStyle: .title2)

/// The font for the title3 style.
static let title3 = StyleGuideFont.dmSans(lineHeight: 21, size: 16, textStyle: .title3)
static let title3 = StyleGuideFont.inter(lineHeight: 21, size: 16, textStyle: .title3)

/// The font for the headline style.
static let headline = StyleGuideFont.dmSans(lineHeight: 28, size: 15, textStyle: .headline)
static let headline = StyleGuideFont.inter(lineHeight: 28, size: 15, textStyle: .headline)

/// The font for the body style.
static let body = StyleGuideFont.dmSans(lineHeight: 20, size: 15, textStyle: .body)
static let body = StyleGuideFont.inter(lineHeight: 20, size: 15, textStyle: .body)

/// The font for the bold body style.
static let bodyBold = body.with(font: FontFamily.DMSans.bold)
static let bodyBold = body.with(font: FontFamily.InterVariable.bold)

/// The font for the monospaced body style.
static let bodyMonospaced = StyleGuideFont(font: .system(.body, design: .monospaced), lineHeight: 22, size: 17)

/// The font for the bold semibody style.
static let bodySemibold = body.with(font: FontFamily.DMSans.semiBold)
static let bodySemibold = body.with(font: FontFamily.InterVariable.semiBold)
Comment on lines 114 to +121

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ IMPORTANT: Verify FontFamily.InterVariable.bold/.semiBold resolve to distinct weights and not regular.

Details

DM Sans shipped six discrete TTFs, so SwiftGen generated separate .regular/.bold/.semiBold cases, each backed by its own PostScript-named face. This PR replaces them with a single upright variable TTF (InterVariable.ttf) plus an italic one.

Two things to confirm, since neither is covered by automated tests (the only StyleGuideFont tests are snapshot tests, and they are disabled via the disabletest_ prefix):

  1. Compilation β€” that SwiftGen still generates .bold and .semiBold cases under FontFamily.InterVariable from these two files. A single variable face typically reports one style name, which could yield only .regular (+ italic) and break the build on lines 115/121/127/133. The Test CI check is still pending, so this isn't confirmed yet.

  2. Rendering β€” SwiftGen's FontConvertible.font(size:) resolves via UIFont(name: <postScriptName>, size:); it does not apply variable-font weight axes. Unless the .bold/.semiBold cases map to separate internal named instances, bodyBold and bodySemibold (and calloutSemibold, subheadlineSemibold, plus the bold UIKit appearances in UI.swift) will render at the default/regular weight β€” a visual regression on all emphasized text across both apps.

Confirming via a build plus the deferred screenshots would close this out.


/// The font for the callout style.
static let callout = StyleGuideFont.dmSans(lineHeight: 18, size: 13, textStyle: .callout)
static let callout = StyleGuideFont.inter(lineHeight: 18, size: 13, textStyle: .callout)

/// The font for the callout semibold style.
static let calloutSemibold = callout.with(font: FontFamily.DMSans.semiBold)
static let calloutSemibold = callout.with(font: FontFamily.InterVariable.semiBold)

/// The font for the subheadline style.
static let subheadline = StyleGuideFont.dmSans(lineHeight: 16, size: 12, textStyle: .subheadline)
static let subheadline = StyleGuideFont.inter(lineHeight: 16, size: 12, textStyle: .subheadline)

/// The font for the subheadline semibold style.
static let subheadlineSemibold = subheadline.with(font: FontFamily.DMSans.semiBold)
static let subheadlineSemibold = subheadline.with(font: FontFamily.InterVariable.semiBold)

/// The font for the footnote style.
static let footnote = StyleGuideFont.dmSans(lineHeight: 18, size: 12, textStyle: .footnote)
static let footnote = StyleGuideFont.inter(lineHeight: 18, size: 12, textStyle: .footnote)

/// The font for the caption1 style.
static let caption1 = StyleGuideFont.dmSans(lineHeight: 18, size: 12, textStyle: .caption)
static let caption1 = StyleGuideFont.inter(lineHeight: 18, size: 12, textStyle: .caption)

/// The font for the caption2 style.
static let caption2 = StyleGuideFont.dmSans(lineHeight: 13, size: 11, textStyle: .caption2)
static let caption2 = StyleGuideFont.inter(lineHeight: 13, size: 11, textStyle: .caption2)

/// The font for the caption2 style monospaced.
static let caption2Monospaced = StyleGuideFont(
Expand Down Expand Up @@ -253,7 +258,7 @@ public extension Text {
// MARK: Previews

#if DEBUG
struct StyleGuideFont_Previews: PreviewProvider {
struct StyleGuideFont_Previews: PreviewProvider { // swiftlint:disable:this type_body_length
static var previews: some View {
HStack {
VStack(alignment: .trailing, spacing: 8) {
Expand Down Expand Up @@ -450,6 +455,51 @@ struct StyleGuideFont_Previews: PreviewProvider {
.background(Color(.systemGroupedBackground))
.previewDisplayName("Standard vs Bold Italic")

HStack {
VStack(alignment: .trailing, spacing: 8) {
Text("Ultra Light")
.styleGuide(.body, weight: .ultraLight)
Text("Thin")
.styleGuide(.body, weight: .thin)
Text("Light")
.styleGuide(.body, weight: .light)
Text("Normal")
.styleGuide(.body, weight: .regular)
Text("Medium")
.styleGuide(.body, weight: .medium)
Text("Semibold")
.styleGuide(.body, weight: .semibold)
Text("Bold")
.styleGuide(.body, weight: .bold)
Text("Heavy")
.styleGuide(.body, weight: .heavy)
Text("Black")
.styleGuide(.body, weight: .black)
}
VStack(alignment: .leading, spacing: 8) {
Text("Ultra Light Italic")
.styleGuide(.body, weight: .ultraLight, isItalic: true)
Text("Thin Italic")
.styleGuide(.body, weight: .thin, isItalic: true)
Text("Light Italic")
.styleGuide(.body, weight: .light, isItalic: true)
Text("Normal Italic")
.styleGuide(.body, weight: .regular, isItalic: true)
Text("Medium Italic")
.styleGuide(.body, weight: .medium, isItalic: true)
Text("Semibold Italic")
.styleGuide(.body, weight: .semibold, isItalic: true)
Text("Bold Italic")
.styleGuide(.body, weight: .bold, isItalic: true)
Text("Heavy Italic")
.styleGuide(.body, weight: .heavy, isItalic: true)
Text("Black Italic")
.styleGuide(.body, weight: .black, isItalic: true)
}
}
.background(Color(.systemGroupedBackground))
.previewDisplayName("Body Weights")

VStack(alignment: .leading) {
Button("Sample Button", action: {})
.buttonStyle(.primary())
Expand Down
18 changes: 11 additions & 7 deletions BitwardenKit/UI/Platform/Application/Appearance/UI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ public enum UI {
@MainActor
public static func applyDefaultAppearances() { // swiftlint:disable:this function_body_length
let bodyFont = UIFontMetrics(forTextStyle: .body).scaledFont(
for: FontFamily.DMSans.regular.font(size: 15),
for: FontFamily.InterVariable.regular.font(size: 15),
)
let bodyBoldFont = UIFontMetrics(forTextStyle: .body).scaledFont(
for: FontFamily.DMSans.bold.font(size: 15),
for: FontFamily.InterVariable.bold.font(size: 15),
)
let largeTitleFont = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(
for: FontFamily.DMSans.bold.font(size: 26),
for: FontFamily.InterVariable.bold.font(size: 26),
)
let iconBadgeBackground = SharedAsset.Colors.iconBadgeBackground.color
let iconBadgeTextAttributes: [NSAttributedString.Key: Any] = [
.font: FontFamily.DMSans.bold.font(size: 12),
.font: FontFamily.InterVariable.bold.font(size: 12),
.foregroundColor: SharedAsset.Colors.iconBadgeForeground.color,
]

Expand Down Expand Up @@ -124,7 +124,7 @@ public enum UI {

UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).title = Localizations.cancel
UIBarButtonItem.appearance(whenContainedInInstancesOf: [UISearchBar.self]).setTitleTextAttributes(
[.font: FontFamily.DMSans.regular.font(size: 15)],
[.font: FontFamily.InterVariable.regular.font(size: 15)],
for: .normal,
)

Expand All @@ -137,14 +137,18 @@ public enum UI {

UISegmentedControl.appearance().setTitleTextAttributes(
[
.font: UIFontMetrics(forTextStyle: .callout).scaledFont(for: FontFamily.DMSans.regular.font(size: 13)),
.font: UIFontMetrics(forTextStyle: .callout).scaledFont(
for: FontFamily.InterVariable.regular.font(size: 13),
),
.foregroundColor: SharedAsset.Colors.textSecondary.color,
],
for: .normal,
)
UISegmentedControl.appearance().setTitleTextAttributes(
[
.font: UIFontMetrics(forTextStyle: .callout).scaledFont(for: FontFamily.DMSans.semiBold.font(size: 13)),
.font: UIFontMetrics(forTextStyle: .callout).scaledFont(
for: FontFamily.InterVariable.semiBold.font(size: 13),
),
.foregroundColor: SharedAsset.Colors.textInteraction.color,
],
for: .selected,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public struct BitwardenStepper<Label: View, Footer: View>: View {
// This width will change as the number of digits changes (e.g. "9" to "10"), but that's
// better than it changing for each digit (e.g. "0" to "1").
let zeroString = String(repeating: "0", count: value.numberOfDigits)
let font = FontFamily.DMSans.semiBold.font(size: StyleGuideFont.body.size)
let font = FontFamily.InterVariable.semiBold.font(size: StyleGuideFont.body.size)
let traitCollection = UITraitCollection(
preferredContentSizeCategory: UIContentSizeCategory(dynamicTypeSize),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public struct BitwardenUITextView: UIViewRepresentable {
textView.textContainerInset = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0)
textView.textContainer.lineFragmentPadding = 0
textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
let customFont = FontFamily.DMSans.regular.font(size: 15)
let customFont = FontFamily.InterVariable.regular.font(size: 15)
textView.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: customFont)
return textView
}
Expand Down
Binary file removed BitwardenResources/Fonts/DMSans-Bold.ttf
Binary file not shown.
Binary file removed BitwardenResources/Fonts/DMSans-BoldItalic.ttf
Binary file not shown.
Binary file removed BitwardenResources/Fonts/DMSans-Italic.ttf
Binary file not shown.
Binary file removed BitwardenResources/Fonts/DMSans-Regular.ttf
Binary file not shown.
Binary file removed BitwardenResources/Fonts/DMSans-SemiBold.ttf
Binary file not shown.
Binary file removed BitwardenResources/Fonts/DMSans-SemiBoldItalic.ttf
Binary file not shown.
Binary file not shown.
Binary file added BitwardenResources/Fonts/InterVariable.ttf
Binary file not shown.
8 changes: 2 additions & 6 deletions BitwardenShared/UI/Platform/Application/Support/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@
<string>1</string>
<key>UIAppFonts</key>
<array>
<string>DMSans-Bold.ttf</string>
<string>DMSans-BoldItalic.ttf</string>
<string>DMSans-Italic.ttf</string>
<string>DMSans-Regular.ttf</string>
<string>DMSans-SemiBold.ttf</string>
<string>DMSans-SemiBoldItalic.ttf</string>
<string>InterVariable-Italic.ttf</string>
<string>InterVariable.ttf</string>
</array>
</dict>
</plist>
Loading