a lightweight, interval-based utility to combat digital strain through "Ma" (intentional pauses) for the eyes and body.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(ui): enable custom font sizes

+58 -18
+2
src/config/types.rs
··· 24 24 pub sound_enabled: bool, 25 25 pub sound_volume: f32, 26 26 pub font_size: u32, 27 + pub text_size_mode: u32, 27 28 } 28 29 29 30 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] ··· 110 111 sound_enabled: true, 111 112 sound_volume: 0.7, 112 113 font_size: 48, 114 + text_size_mode: 0, 113 115 } 114 116 } 115 117 }
+2
src/settings/mod.rs
··· 127 127 2 => OverlayTheme::Dark, 128 128 _ => OverlayTheme::System, 129 129 }; 130 + cfg.appearance.text_size_mode = window.get_text_size_mode() as u32; 130 131 } 131 132 132 133 fn populate(window: &SettingsWindow, levels_model: &VecModel<LevelEntry>, cfg: &AppConfig) { ··· 179 180 OverlayTheme::Light => 1, 180 181 OverlayTheme::Dark => 2, 181 182 }); 183 + window.set_text_size_mode(cfg.appearance.text_size_mode as i32); 182 184 183 185 populate_for_profile(window, levels_model, cfg, &active_name); 184 186 }
+11 -1
ui/settings.slint
··· 22 22 default-font-family: "Nunito"; 23 23 24 24 in property <bool> is-dark: false; 25 - init => { Theme.dark = root.is-dark; } 25 + init => { 26 + Theme.dark = root.is-dark; 27 + Theme.font-scale = root.text-size-mode == 2 ? 1.3 : root.text-size-mode == 1 ? 1.15 : 1.0; 28 + } 26 29 changed is-dark => { Theme.dark = root.is-dark; } 30 + changed text-size-mode => { 31 + Theme.font-scale = root.text-size-mode == 2 ? 1.3 : root.text-size-mode == 1 ? 1.15 : 1.0; 32 + } 27 33 28 34 in-out property <bool> enforced-mode: false; 29 35 in-out property <bool> sound-enabled: true; ··· 41 47 in-out property <int> long-break-gap-mins: 30; 42 48 in-out property <string> long-break-label: "Long rest"; 43 49 in-out property <int> theme-mode: 0; 50 + in-out property <int> text-size-mode: 0; 44 51 45 52 callback save-clicked(); 46 53 callback cancel-clicked(); 47 54 callback theme-mode-changed(int); 55 + callback text-size-mode-changed(int); 48 56 callback set-password-clicked(); 49 57 callback open-config-dir(); 50 58 callback profile-changed(string); ··· 97 105 profile-names: root.profile-names; 98 106 profile-name-widths: root.profile-name-widths; 99 107 theme-mode <=> root.theme-mode; 108 + text-size-mode <=> root.text-size-mode; 100 109 set-password-clicked => { root.set-password-clicked(); } 101 110 open-config-dir => { root.open-config-dir(); } 102 111 profile-changed(name) => { root.profile-changed(name); } 103 112 theme-mode-changed(i) => { root.theme-mode-changed(i); } 113 + text-size-mode-changed(i) => { root.text-size-mode-changed(i); } 104 114 } 105 115 106 116 if root.active-tab == "profile": ProfileTab {
+15 -16
ui/theme.slint
··· 1 - // Design token system for ioma. 2 - // Import this file in any .slint UI file that needs themed colors. 3 - // Set Theme.dark = true to switch to dark mode. 1 + // Design token system for ioma 4 2 5 3 export global Theme { 6 4 // Set by each window via `changed is-dark => { Theme.dark = root.is-dark; }` 7 5 in-out property <bool> dark: false; 6 + 7 + // Set by SettingsWindow from the user's text-size-mode setting (0=Default, 1=Large, 2=Larger). 8 + // All font tokens multiply by this so system-level and manual accessibility scaling both work. 9 + in-out property <float> font-scale: 1.0; 8 10 9 11 // ── Font sizes (semantic tokens) ─────────────────────────────────────────── 10 - // Define semantic font sizes here so the UI can switch sizes centrally. 11 - out property <length> font_huge: 96px; // overlay large number 12 - out property <length> font_title: 34px; // big page titles 13 - out property <length> font_headline: 28px; // secondary large headings 14 - out property <length> font_header: 22px; // header / section titles 15 - out property <length> font_medium: 14px; // medium emphasis 16 - out property <length> font_body: 13px; // body text / inputs 17 - out property <length> font_label: 12px; // labels, chips, buttons 18 - out property <length> font_caption: 12.5px; // small captions 19 - out property <length> font_xsmall: 11.5px; // tiny helper text 20 - out property <length> font_xxsmall: 11px; // extra small 21 - 12 + out property <length> font_huge: 124px * font-scale; // overlay large number 13 + out property <length> font_title: 48px * font-scale; // big page titles 14 + out property <length> font_headline: 42px * font-scale; // secondary large headings 15 + out property <length> font_header: 36px * font-scale; // header / section titles 16 + out property <length> font_medium: 19px * font-scale; // medium emphasis 17 + out property <length> font_body: 16px * font-scale; // body text / inputs 18 + out property <length> font_label: 15px * font-scale; // labels, chips, buttons 19 + out property <length> font_xsmall: 14px * font-scale; // helper / description text 20 + out property <length> font_xxsmall: 13px * font-scale; // decorative / chrome text 22 21 23 22 // ── Window background ───────────────────────────────────────────────────── 24 23 // Light: warm cream / Dark: gentle dark blue (desaturated, not tech-stark) ··· 27 26 // ── Ink scale: primary text → near-invisible ────────────────────────────── 28 27 // Light base: #232028 (near-black, warm cast) 29 28 // Dark base: #EDE9E1 (warm off-white) 30 - out property <color> ink: self.dark ? #EDE9E1 : #232028; 29 + out property <color> ink: self.dark ? #EDE9E1 : #232028; 31 30 out property <color> ink-hi: self.dark ? #EDE9E1CC : #232028CC; // prominent secondary 32 31 out property <color> ink-mid: self.dark ? #EDE9E1AA : #232028AA; // standard secondary 33 32 out property <color> ink-lo: self.dark ? #EDE9E188 : #23202888; // tertiary / muted
+1 -1
ui/views/profile_tab.slint
··· 91 91 } 92 92 93 93 add-ta := TouchArea { 94 - height: 44px; 94 + height: 44px * Theme.font-scale; 95 95 accessible-role: AccessibleRole.button; 96 96 accessible-label: "Add interval"; 97 97 accessible-action-default => { root.level-added(); }
+27
ui/views/rhythm_tab.slint
··· 17 17 in property <[string]> profile-names; 18 18 in property <[int]> profile-name-widths; 19 19 in-out property <int> theme-mode: 0; 20 + in-out property <int> text-size-mode: 0; 20 21 21 22 callback set-password-clicked; 22 23 callback open-config-dir; 23 24 callback profile-changed(string); 24 25 callback theme-mode-changed(int); 26 + callback text-size-mode-changed(int); 25 27 26 28 vertical-stretch: 1; 27 29 ··· 234 236 selected-index <=> root.theme-mode; 235 237 selection-changed(i) => { 236 238 root.theme-mode-changed(i); 239 + } 240 + } 241 + } 242 + 243 + PaperDivider { } 244 + 245 + HorizontalLayout { 246 + padding-top: 12px; 247 + padding-bottom: 10px; 248 + spacing: 24px; 249 + 250 + SettingLabel { 251 + title: "Text size"; 252 + description: "Adjusts all UI text for readability."; 253 + } 254 + 255 + Rectangle { 256 + horizontal-stretch: 1; 257 + } 258 + 259 + ChipGroup { 260 + labels: ["Default", "Large", "Larger"]; 261 + selected-index <=> root.text-size-mode; 262 + selection-changed(i) => { 263 + root.text-size-mode-changed(i); 237 264 } 238 265 } 239 266 }