chore: added font size to customization 67e5655e
Steve · 2025-12-25 19:30 5 file(s) · +44 −9
Titan/Settings/ThemeSettings.swift +14 −0
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
Titan/Views/ContentView.swift +1 −0
372 372
373 373
#Preview {
374 374
    ContentView()
375 +
        .environmentObject(ThemeSettings())
375 376
}
Titan/Views/MediaPreviewView.swift +1 −0
372 372
        ),
373 373
        onDismiss: {}
374 374
    )
375 +
    .environmentObject(ThemeSettings())
375 376
}
Titan/Views/SettingsView.swift +13 −0
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
}
Titan/Views/TitanContentView.swift +15 −9
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
    }