feat: added background and foreground customization 05460409
Steve · 2025-12-25 13:39 4 file(s) · +50 −4
Titan/Settings/ThemeSettings.swift +34 −2
24 24
    /// The color used for toolbar buttons (navigation, menu, etc.)
25 25
    @Published var toolbarButtonColor: Color = .blue
26 26
27 +
    /// The background color for the main content area
28 +
    @Published var backgroundColor: Color = Color(UIColor.systemBackground)
29 +
30 +
    /// The text color for content
31 +
    @Published var textColor: Color = Color(UIColor.label)
32 +
27 33
    /// The home page URL that the browser navigates to on launch and when pressing Home
28 34
    @AppStorage("homePage") var homePage: String = "gemini://geminiprotocol.net/"
29 35
30 36
    /// Key for persisting accent color hex value
31 37
    private static let accentColorKey = "accentColorHex"
38 +
    private static let backgroundColorKey = "backgroundColorHex"
39 +
    private static let textColorKey = "textColorHex"
32 40
33 41
    init() {
34 42
        if let hex = UserDefaults.standard.string(forKey: Self.accentColorKey),
35 43
           let color = Color(hex: hex) {
36 -
            setAllColors(color)
44 +
            setAllAccentColors(color)
45 +
        }
46 +
        if let hex = UserDefaults.standard.string(forKey: Self.backgroundColorKey),
47 +
           let color = Color(hex: hex) {
48 +
            backgroundColor = color
49 +
        }
50 +
        if let hex = UserDefaults.standard.string(forKey: Self.textColorKey),
51 +
           let color = Color(hex: hex) {
52 +
            textColor = color
37 53
        }
38 54
    }
39 55
40 56
    /// Sets all accent colors to the given color and persists the choice
41 -
    func setAllColors(_ color: Color) {
57 +
    func setAllAccentColors(_ color: Color) {
42 58
        accentColor = color
43 59
        progressBarColor = color
44 60
        linkColor = color
47 63
48 64
        if let hex = color.toHex() {
49 65
            UserDefaults.standard.set(hex, forKey: Self.accentColorKey)
66 +
        }
67 +
    }
68 +
69 +
    /// Sets the background color and persists the choice
70 +
    func setBackgroundColor(_ color: Color) {
71 +
        backgroundColor = color
72 +
        if let hex = color.toHex() {
73 +
            UserDefaults.standard.set(hex, forKey: Self.backgroundColorKey)
74 +
        }
75 +
    }
76 +
77 +
    /// Sets the text color and persists the choice
78 +
    func setTextColor(_ color: Color) {
79 +
        textColor = color
80 +
        if let hex = color.toHex() {
81 +
            UserDefaults.standard.set(hex, forKey: Self.textColorKey)
50 82
        }
51 83
    }
52 84
}
Titan/Views/ContentView.swift +1 −0
65 65
                }
66 66
            }
67 67
            .contentMargins(.top, 20, for: .scrollContent)
68 +
            .background(themeSettings.backgroundColor)
68 69
            .safeAreaInset(edge: .bottom) {
69 70
                BrowserToolbar(
70 71
                    urlText: $urlText,
Titan/Views/SettingsView.swift +10 −2
11 11
12 12
    @State private var homePageText: String = ""
13 13
    @State private var selectedAccentColor: Color = .blue
14 +
    @State private var selectedBackgroundColor: Color = Color(UIColor.systemBackground)
15 +
    @State private var selectedTextColor: Color = Color(UIColor.label)
14 16
15 17
    var body: some View {
16 18
        NavigationStack {
28 30
29 31
                Section {
30 32
                    ColorPicker("Accent Color", selection: $selectedAccentColor, supportsOpacity: false)
33 +
                    ColorPicker("Background Color", selection: $selectedBackgroundColor, supportsOpacity: false)
34 +
                    ColorPicker("Text Color", selection: $selectedTextColor, supportsOpacity: false)
31 35
                } header: {
32 36
                    Text("Appearance")
33 37
                } footer: {
34 -
                    Text("Changes the color of links, buttons, and other interactive elements.")
38 +
                    Text("Customize the colors of your browser interface.")
35 39
                }
36 40
            }
37 41
            .navigationTitle("Settings")
45 49
                ToolbarItem(placement: .confirmationAction) {
46 50
                    Button("Save") {
47 51
                        themeSettings.homePage = homePageText
48 -
                        themeSettings.setAllColors(selectedAccentColor)
52 +
                        themeSettings.setAllAccentColors(selectedAccentColor)
53 +
                        themeSettings.setBackgroundColor(selectedBackgroundColor)
54 +
                        themeSettings.setTextColor(selectedTextColor)
49 55
                        dismiss()
50 56
                    }
51 57
                }
53 59
            .onAppear {
54 60
                homePageText = themeSettings.homePage
55 61
                selectedAccentColor = themeSettings.accentColor
62 +
                selectedBackgroundColor = themeSettings.backgroundColor
63 +
                selectedTextColor = themeSettings.textColor
56 64
            }
57 65
        }
58 66
    }
Titan/Views/TitanContentView.swift +5 −0
77 77
        case .text(let text):
78 78
            Text(text)
79 79
                .font(.system(.body, design: .monospaced))
80 +
                .foregroundColor(themeSettings.textColor)
80 81
81 82
        case .link(let url, let label):
82 83
            Button(action: { onLinkTap(url) }) {
93 94
            Text(text)
94 95
                .font(.system(.title, design: .monospaced))
95 96
                .fontWeight(.bold)
97 +
                .foregroundColor(themeSettings.textColor)
96 98
                .padding(.top, 8)
97 99
98 100
        case .heading2(let text):
99 101
            Text(text)
100 102
                .font(.system(.title2, design: .monospaced))
101 103
                .fontWeight(.semibold)
104 +
                .foregroundColor(themeSettings.textColor)
102 105
                .padding(.top, 6)
103 106
104 107
        case .heading3(let text):
105 108
            Text(text)
106 109
                .font(.system(.title3, design: .monospaced))
107 110
                .fontWeight(.medium)
111 +
                .foregroundColor(themeSettings.textColor)
108 112
                .padding(.top, 4)
109 113
110 114
        case .listItem(let text):
113 117
                Text(text)
114 118
            }
115 119
            .font(.system(.body, design: .monospaced))
120 +
            .foregroundColor(themeSettings.textColor)
116 121
117 122
        case .quote(let text):
118 123
            Text(text)