chore: added font size to customization
67e5655e
5 file(s) · +44 −9
| 52 | 52 | /// The font design for content |
|
| 53 | 53 | @Published var fontDesign: FontDesignOption = .monospaced |
|
| 54 | 54 | ||
| 55 | + | /// The base font size for content (default 16pt) |
|
| 56 | + | @Published var baseFontSize: CGFloat = 16 |
|
| 57 | + | ||
| 55 | 58 | /// The home page URL that the browser navigates to on launch and when pressing Home |
|
| 56 | 59 | @AppStorage("homePage") var homePage: String = "gemini://geminiprotocol.net/" |
|
| 57 | 60 | ||
| 60 | 63 | private static let backgroundColorKey = "backgroundColorHex" |
|
| 61 | 64 | private static let textColorKey = "textColorHex" |
|
| 62 | 65 | private static let fontDesignKey = "fontDesign" |
|
| 66 | + | private static let baseFontSizeKey = "baseFontSize" |
|
| 63 | 67 | ||
| 64 | 68 | init() { |
|
| 65 | 69 | if let hex = UserDefaults.standard.string(forKey: Self.accentColorKey), |
|
| 78 | 82 | let font = FontDesignOption(rawValue: fontRaw) { |
|
| 79 | 83 | fontDesign = font |
|
| 80 | 84 | } |
|
| 85 | + | let savedFontSize = UserDefaults.standard.double(forKey: Self.baseFontSizeKey) |
|
| 86 | + | if savedFontSize > 0 { |
|
| 87 | + | baseFontSize = savedFontSize |
|
| 88 | + | } |
|
| 81 | 89 | } |
|
| 82 | 90 | ||
| 83 | 91 | /// Sets all accent colors to the given color and persists the choice |
|
| 113 | 121 | func setFontDesign(_ font: FontDesignOption) { |
|
| 114 | 122 | fontDesign = font |
|
| 115 | 123 | UserDefaults.standard.set(font.rawValue, forKey: Self.fontDesignKey) |
|
| 124 | + | } |
|
| 125 | + | ||
| 126 | + | /// Sets the base font size and persists the choice |
|
| 127 | + | func setBaseFontSize(_ size: CGFloat) { |
|
| 128 | + | baseFontSize = size |
|
| 129 | + | UserDefaults.standard.set(Double(size), forKey: Self.baseFontSizeKey) |
|
| 116 | 130 | } |
|
| 117 | 131 | } |
|
| 118 | 132 | ||
| 372 | 372 | ||
| 373 | 373 | #Preview { |
|
| 374 | 374 | ContentView() |
|
| 375 | + | .environmentObject(ThemeSettings()) |
|
| 375 | 376 | } |
| 372 | 372 | ), |
|
| 373 | 373 | onDismiss: {} |
|
| 374 | 374 | ) |
|
| 375 | + | .environmentObject(ThemeSettings()) |
|
| 375 | 376 | } |
| 14 | 14 | @State private var selectedBackgroundColor: Color = Color(UIColor.systemBackground) |
|
| 15 | 15 | @State private var selectedTextColor: Color = Color(UIColor.label) |
|
| 16 | 16 | @State private var selectedFontDesign: FontDesignOption = .monospaced |
|
| 17 | + | @State private var selectedFontSize: Double = 16 |
|
| 17 | 18 | ||
| 18 | 19 | var body: some View { |
|
| 19 | 20 | NavigationStack { |
|
| 38 | 39 | Text(option.rawValue).tag(option) |
|
| 39 | 40 | } |
|
| 40 | 41 | } |
|
| 42 | + | VStack(alignment: .leading) { |
|
| 43 | + | HStack { |
|
| 44 | + | Text("Font Size") |
|
| 45 | + | Spacer() |
|
| 46 | + | Text("\(Int(selectedFontSize))pt") |
|
| 47 | + | .foregroundColor(.secondary) |
|
| 48 | + | } |
|
| 49 | + | Slider(value: $selectedFontSize, in: 12...24, step: 1) |
|
| 50 | + | } |
|
| 41 | 51 | } header: { |
|
| 42 | 52 | Text("Appearance") |
|
| 43 | 53 | } footer: { |
|
| 59 | 69 | themeSettings.setBackgroundColor(selectedBackgroundColor) |
|
| 60 | 70 | themeSettings.setTextColor(selectedTextColor) |
|
| 61 | 71 | themeSettings.setFontDesign(selectedFontDesign) |
|
| 72 | + | themeSettings.setBaseFontSize(CGFloat(selectedFontSize)) |
|
| 62 | 73 | dismiss() |
|
| 63 | 74 | } |
|
| 64 | 75 | } |
|
| 69 | 80 | selectedBackgroundColor = themeSettings.backgroundColor |
|
| 70 | 81 | selectedTextColor = themeSettings.textColor |
|
| 71 | 82 | selectedFontDesign = themeSettings.fontDesign |
|
| 83 | + | selectedFontSize = Double(themeSettings.baseFontSize) |
|
| 72 | 84 | } |
|
| 73 | 85 | } |
|
| 74 | 86 | } |
|
| 76 | 88 | ||
| 77 | 89 | #Preview { |
|
| 78 | 90 | SettingsView() |
|
| 91 | + | .environmentObject(ThemeSettings()) |
|
| 79 | 92 | } |
|
| 7 | 7 | ||
| 8 | 8 | struct PreformattedBlockView: View { |
|
| 9 | 9 | let text: String |
|
| 10 | + | let baseFontSize: CGFloat |
|
| 10 | 11 | ||
| 11 | - | private let maxFontSize: CGFloat = 12 |
|
| 12 | + | private var maxFontSize: CGFloat { baseFontSize * 0.75 } |
|
| 12 | 13 | private let charWidthRatio: CGFloat = 0.6 // Monospace char width ≈ 0.6 * font size |
|
| 13 | 14 | private let lineHeightRatio: CGFloat = 1.2 |
|
| 14 | 15 | ||
| 71 | 72 | .padding(8) |
|
| 72 | 73 | } |
|
| 73 | 74 | ||
| 75 | + | private var fontSize: CGFloat { themeSettings.baseFontSize } |
|
| 76 | + | private var heading1Size: CGFloat { fontSize * 1.75 } |
|
| 77 | + | private var heading2Size: CGFloat { fontSize * 1.5 } |
|
| 78 | + | private var heading3Size: CGFloat { fontSize * 1.25 } |
|
| 79 | + | ||
| 74 | 80 | @ViewBuilder |
|
| 75 | 81 | private func lineView(for line: TitanLine) -> some View { |
|
| 76 | 82 | switch line { |
|
| 77 | 83 | case .text(let text): |
|
| 78 | 84 | Text(text) |
|
| 79 | - | .font(.system(.body, design: themeSettings.fontDesign.fontDesign)) |
|
| 85 | + | .font(.system(size: fontSize, design: themeSettings.fontDesign.fontDesign)) |
|
| 80 | 86 | .foregroundColor(themeSettings.textColor) |
|
| 81 | 87 | ||
| 82 | 88 | case .link(let url, let label): |
|
| 84 | 90 | HStack(alignment:.top, spacing: 4) { |
|
| 85 | 91 | Text(label) |
|
| 86 | 92 | .multilineTextAlignment(.leading) |
|
| 87 | - | .font(.system(size: 14, design: themeSettings.fontDesign.fontDesign)) |
|
| 93 | + | .font(.system(size: fontSize, design: themeSettings.fontDesign.fontDesign)) |
|
| 88 | 94 | } |
|
| 89 | 95 | } |
|
| 90 | 96 | .foregroundColor(themeSettings.linkColor) |
|
| 92 | 98 | ||
| 93 | 99 | case .heading1(let text): |
|
| 94 | 100 | Text(text) |
|
| 95 | - | .font(.system(.title, design: themeSettings.fontDesign.fontDesign)) |
|
| 101 | + | .font(.system(size: heading1Size, design: themeSettings.fontDesign.fontDesign)) |
|
| 96 | 102 | .fontWeight(.bold) |
|
| 97 | 103 | .foregroundColor(themeSettings.textColor) |
|
| 98 | 104 | .padding(.top, 8) |
|
| 99 | 105 | ||
| 100 | 106 | case .heading2(let text): |
|
| 101 | 107 | Text(text) |
|
| 102 | - | .font(.system(.title2, design: themeSettings.fontDesign.fontDesign)) |
|
| 108 | + | .font(.system(size: heading2Size, design: themeSettings.fontDesign.fontDesign)) |
|
| 103 | 109 | .fontWeight(.semibold) |
|
| 104 | 110 | .foregroundColor(themeSettings.textColor) |
|
| 105 | 111 | .padding(.top, 6) |
|
| 106 | 112 | ||
| 107 | 113 | case .heading3(let text): |
|
| 108 | 114 | Text(text) |
|
| 109 | - | .font(.system(.title3, design: themeSettings.fontDesign.fontDesign)) |
|
| 115 | + | .font(.system(size: heading3Size, design: themeSettings.fontDesign.fontDesign)) |
|
| 110 | 116 | .fontWeight(.medium) |
|
| 111 | 117 | .foregroundColor(themeSettings.textColor) |
|
| 112 | 118 | .padding(.top, 4) |
|
| 116 | 122 | Text("\u{2022}") |
|
| 117 | 123 | Text(text) |
|
| 118 | 124 | } |
|
| 119 | - | .font(.system(.body, design: themeSettings.fontDesign.fontDesign)) |
|
| 125 | + | .font(.system(size: fontSize, design: themeSettings.fontDesign.fontDesign)) |
|
| 120 | 126 | .foregroundColor(themeSettings.textColor) |
|
| 121 | 127 | ||
| 122 | 128 | case .quote(let text): |
|
| 123 | 129 | Text(text) |
|
| 124 | - | .font(.system(.body, design: themeSettings.fontDesign.fontDesign)) |
|
| 130 | + | .font(.system(size: fontSize, design: themeSettings.fontDesign.fontDesign)) |
|
| 125 | 131 | .italic() |
|
| 126 | 132 | .foregroundColor(.secondary) |
|
| 127 | 133 | .padding(.leading, 12) |
|
| 128 | 134 | ||
| 129 | 135 | case .preformattedBlock(let text, _): |
|
| 130 | - | PreformattedBlockView(text: text) |
|
| 136 | + | PreformattedBlockView(text: text, baseFontSize: fontSize) |
|
| 131 | 137 | .padding(.vertical, 4) |
|
| 132 | 138 | } |
|
| 133 | 139 | } |
|