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.

fix(ui): refines interval cards, appearance, and text size components

+ adds background panel i'm undecided about (colors are ugly)

+493 -513
+28 -26
Cargo.lock
··· 2432 2432 2433 2433 [[package]] 2434 2434 name = "i-slint-backend-linuxkms" 2435 - version = "1.16.0" 2435 + version = "1.16.1" 2436 2436 source = "registry+https://github.com/rust-lang/crates.io-index" 2437 - checksum = "580bb55cd14cb12bd9169920661235797f4c8220318d0071e971fce345e28488" 2437 + checksum = "3224c3aa9f3ea568daf38389d0f7ace164eda4d6f1851042eb83750ac43e1a65" 2438 2438 dependencies = [ 2439 2439 "bytemuck", 2440 2440 "calloop 0.14.4", 2441 + "cfg_aliases", 2441 2442 "drm", 2442 2443 "gbm", 2443 2444 "glutin", ··· 2454 2455 2455 2456 [[package]] 2456 2457 name = "i-slint-backend-selector" 2457 - version = "1.16.0" 2458 + version = "1.16.1" 2458 2459 source = "registry+https://github.com/rust-lang/crates.io-index" 2459 - checksum = "0ed4d0e693f83dbe68fea69b8ebebda8b245f34350d83e5f8fd62c0333d938b8" 2460 + checksum = "f93c9c4203e0a2c5c396b8f1686160816f73e9b9cadaf3915aa3b888a83448aa" 2460 2461 dependencies = [ 2461 2462 "cfg-if", 2462 2463 "i-slint-backend-linuxkms", ··· 2469 2470 2470 2471 [[package]] 2471 2472 name = "i-slint-backend-winit" 2472 - version = "1.16.0" 2473 + version = "1.16.1" 2473 2474 source = "registry+https://github.com/rust-lang/crates.io-index" 2474 - checksum = "90f7fddf48d12b366f352f8fb78d59665c490cf279786772f1d1592e143edd0d" 2475 + checksum = "f4df6ec88d452e3c22e418d20c96bc1ccbc9509e81e6596426d3388bf226a5f9" 2475 2476 dependencies = [ 2476 2477 "accesskit", 2477 2478 "accesskit_winit", ··· 2516 2517 2517 2518 [[package]] 2518 2519 name = "i-slint-common" 2519 - version = "1.16.0" 2520 + version = "1.16.1" 2520 2521 source = "registry+https://github.com/rust-lang/crates.io-index" 2521 - checksum = "0f44bc19b68be0295354769bc456ccca1c8cb5a38c4cbb5566b0b3fdb918921b" 2522 + checksum = "40cae5cd0a81ce044029ac303256e025f98a4c59495b5189fc22b588da094e01" 2522 2523 dependencies = [ 2523 2524 "derive_more", 2524 2525 "fontique", ··· 2529 2530 2530 2531 [[package]] 2531 2532 name = "i-slint-compiler" 2532 - version = "1.16.0" 2533 + version = "1.16.1" 2533 2534 source = "registry+https://github.com/rust-lang/crates.io-index" 2534 - checksum = "dba63c5a2774a878478572a0b48b2af4895323d1dc969432c690362f0ab67d5c" 2535 + checksum = "a7b7f9834faf2a62cc36f01decc7c683e66bb0861b53511723c3da9ad914d9bb" 2535 2536 dependencies = [ 2536 2537 "annotate-snippets", 2537 2538 "by_address", ··· 2562 2563 2563 2564 [[package]] 2564 2565 name = "i-slint-core" 2565 - version = "1.16.0" 2566 + version = "1.16.1" 2566 2567 source = "registry+https://github.com/rust-lang/crates.io-index" 2567 - checksum = "8bac8ed92f61140aa03e426b28cd135e252c82891bc1ed88f2f799ba367f21c8" 2568 + checksum = "89e4a57afd78d8a1f599a78781dc1413af68545b2bc5ba5e143ecf022c75d5f3" 2568 2569 dependencies = [ 2569 2570 "auto_enums", 2570 2571 "bitflags 2.11.1", ··· 2610 2611 2611 2612 [[package]] 2612 2613 name = "i-slint-core-macros" 2613 - version = "1.16.0" 2614 + version = "1.16.1" 2614 2615 source = "registry+https://github.com/rust-lang/crates.io-index" 2615 - checksum = "315b38ab2265294fedd11a578468ab146fd579a5765d68d42824a060a4772fc4" 2616 + checksum = "7931356d5238281e6be994ec15241fb2d9e66359776d53b4bd6b2fdd9c257c6e" 2616 2617 dependencies = [ 2617 2618 "quote", 2618 2619 "serde_json", ··· 2621 2622 2622 2623 [[package]] 2623 2624 name = "i-slint-renderer-femtovg" 2624 - version = "1.16.0" 2625 + version = "1.16.1" 2625 2626 source = "registry+https://github.com/rust-lang/crates.io-index" 2626 - checksum = "9f1b4e3873e9dd6000ecbf5724ceaea638d089bdd5367f30fcffb3f43e1f235f" 2627 + checksum = "72b28a8f0a7a777e670fbe2af6cbcec4935c37335bc0dab100f73bdc197dfa3a" 2627 2628 dependencies = [ 2628 2629 "cfg-if", 2629 2630 "const-field-offset", ··· 2643 2644 2644 2645 [[package]] 2645 2646 name = "i-slint-renderer-skia" 2646 - version = "1.16.0" 2647 + version = "1.16.1" 2647 2648 source = "registry+https://github.com/rust-lang/crates.io-index" 2648 - checksum = "9cd39e5a129ba4c30d18159c344e756e81d4ea2d0ab3dc5c9834d47339d3e580" 2649 + checksum = "d4030ff9eeb1b99fdf9b47472f3a7a582f3bcb57207c9bc07505dc6998abdcbc" 2649 2650 dependencies = [ 2650 2651 "bytemuck", 2651 2652 "cfg-if", ··· 2680 2681 2681 2682 [[package]] 2682 2683 name = "i-slint-renderer-software" 2683 - version = "1.16.0" 2684 + version = "1.16.1" 2684 2685 source = "registry+https://github.com/rust-lang/crates.io-index" 2685 - checksum = "6a8fa9e24ad40900de052eda07ee1dbbe0d66efcb25742d81296b1ba9d28c9d0" 2686 + checksum = "ee8a21285f3a81a8e1b1e7c385eefe89bf9487f53fabfd5b238c68bc895d6013" 2686 2687 dependencies = [ 2687 2688 "bytemuck", 2688 2689 "clru", ··· 2996 2997 "env_logger", 2997 2998 "fontdue", 2998 2999 "gtk", 3000 + "i-slint-backend-selector", 2999 3001 "image", 3000 3002 "log", 3001 3003 "muda 0.15.3", ··· 5280 5282 5281 5283 [[package]] 5282 5284 name = "slint" 5283 - version = "1.16.0" 5285 + version = "1.16.1" 5284 5286 source = "registry+https://github.com/rust-lang/crates.io-index" 5285 - checksum = "364a1e8fae7f1969224acc59ba729f06aeaf808123796389eae458c396119ef0" 5287 + checksum = "d46bc502cc6b113bfd1a7e9a0876532a9454ff4ee905afe09784eaa2ec3f3f33" 5286 5288 dependencies = [ 5287 5289 "const-field-offset", 5288 5290 "i-slint-backend-selector", ··· 5302 5304 5303 5305 [[package]] 5304 5306 name = "slint-build" 5305 - version = "1.16.0" 5307 + version = "1.16.1" 5306 5308 source = "registry+https://github.com/rust-lang/crates.io-index" 5307 - checksum = "ec94124d27a1b691fd8613c653bae47ece44cb469af11ce0edf645acf458ae61" 5309 + checksum = "a73854b9adf81fa1600b46df488ffc3796400e8e9b40d504a94a36b55c8f3d0a" 5308 5310 dependencies = [ 5309 5311 "derive_more", 5310 5312 "fontique", ··· 5315 5317 5316 5318 [[package]] 5317 5319 name = "slint-macros" 5318 - version = "1.16.0" 5320 + version = "1.16.1" 5319 5321 source = "registry+https://github.com/rust-lang/crates.io-index" 5320 - checksum = "c2f2659f0896ccf5921a1b0af835c4d5285a3292bfcf36cb9bf9e4fbcbe874fc" 5322 + checksum = "6d5884e06072c329da7096ad1367eb83b98c78e5313f7ac90d66f90d4acc62ee" 5321 5323 dependencies = [ 5322 5324 "i-slint-compiler", 5323 5325 "proc-macro2",
+1
Cargo.toml
··· 43 43 anyhow = "1" 44 44 open = "5" 45 45 display-info = "0.5" 46 + i-slint-backend-selector = "1.16.1" 46 47 47 48 [target.'cfg(target_os = "linux")'.dependencies] 48 49 zbus = { version = "4", default-features = false, features = ["tokio"] }
+7 -26
ui/components/atoms.slint
··· 32 32 33 33 spacing: 4px * Theme.font-scale; 34 34 35 - HorizontalLayout { 36 - spacing: 12px * Theme.font-scale; 37 - 38 - Text { 39 - text: root.title; 40 - font-family: "Shippori Mincho"; 41 - font-size: Theme.font_label; 42 - font-weight: 700; 43 - color: Theme.ink-hi; 44 - } 45 - 46 - VerticalLayout { 47 - horizontal-stretch: 1; 48 - spacing: 0px; 49 - 50 - Rectangle { vertical-stretch: 1; } 51 - 52 - Rectangle { 53 - height: 1px; 54 - background: Theme.line; 55 - } 56 - 57 - Rectangle { vertical-stretch: 1; } 58 - } 35 + Text { 36 + text: root.title; 37 + font-size: Theme.font_body; 38 + font-weight: 500; 39 + color: Theme.ink; 59 40 } 60 41 61 42 if root.description != "": Text { 62 43 text: root.description; 63 - font-size: Theme.font_xxsmall; 64 - color: Theme.ink-lo; 44 + font-size: Theme.font_xsmall; 45 + color: Theme.ink-mid; 65 46 } 66 47 }
+13 -20
ui/components/inputs.slint
··· 40 40 41 41 Rectangle { 42 42 border-radius: 6px * Theme.font-scale; 43 - background: Theme.surface; 44 - border-width: 1px; 45 - border-color: Theme.line; 43 + background: Theme.surface-inp; 44 + border-width: 0px; 46 45 clip: true; 47 46 48 47 HorizontalLayout { 48 + padding-left: 4px * Theme.font-scale; 49 + padding-right: 4px * Theme.font-scale; 50 + spacing: 2px * Theme.font-scale; 51 + 49 52 btn-minus := TouchArea { 50 - width: 26px * Theme.font-scale; 53 + width: 22px * Theme.font-scale; 51 54 enabled: root.enabled; 52 55 accessible-role: button; 53 56 accessible-label: "Decrease " + root.field-label; ··· 60 63 } 61 64 62 65 Rectangle { 66 + border-radius: 4px * Theme.font-scale; 63 67 background: btn-minus.has-hover ? Theme.tint : transparent; 64 68 animate background { duration: 120ms; } 65 69 } ··· 72 76 vertical-alignment: center; 73 77 animate color { duration: 120ms; } 74 78 } 75 - } 76 - 77 - Rectangle { 78 - width: 1px; 79 - background: Theme.line; 80 79 } 81 80 82 81 Text { 83 82 text: root.value; 84 83 font-size: Theme.font_label; 85 84 font-weight: 500; 86 - color: Theme.ink; 85 + color: root.enabled ? Theme.ink : Theme.ink-dis; 87 86 horizontal-alignment: center; 88 87 vertical-alignment: center; 89 88 horizontal-stretch: 1; 90 89 } 91 90 92 - Rectangle { 93 - width: 1px; 94 - background: Theme.line; 95 - } 96 - 97 91 btn-plus := TouchArea { 98 - width: 26px * Theme.font-scale; 92 + width: 22px * Theme.font-scale; 99 93 enabled: root.enabled; 100 94 accessible-role: button; 101 95 accessible-label: "Increase " + root.field-label; ··· 108 102 } 109 103 110 104 Rectangle { 105 + border-radius: 4px * Theme.font-scale; 111 106 background: btn-plus.has-hover ? Theme.tint : transparent; 112 107 animate background { duration: 120ms; } 113 108 } ··· 140 135 141 136 Rectangle { 142 137 border-radius: 6px * Theme.font-scale; 143 - background: ti.has-focus ? Theme.tint-soft : Theme.surface-inp; 144 - border-width: 1px; 145 - border-color: ti.has-focus ? Theme.accent-muted : Theme.line; 138 + background: ti.has-focus ? Theme.tint : Theme.tint-soft; 139 + border-width: 0px; 146 140 animate background { duration: 120ms; } 147 - animate border-color { duration: 120ms; } 148 141 clip: true; 149 142 150 143 // Placeholder text when empty and unfocused
+1
ui/theme.slint
··· 45 45 out property <color> surface: self.dark ? #EDE9E10F : #FFFFFF80; // cards, chips 46 46 out property <color> surface-inp: self.dark ? #EDE9E10A : #FFFFFF60; // input default bg 47 47 out property <color> surface-hov: self.dark ? #EDE9E11A : #FFFFFF; // hovered chip/card 48 + out property <color> panel: self.dark ? #EDE9E11E : #2320281E; // section panel backgrounds 48 49 49 50 // ── Primary button (inverted palette) ───────────────────────────────────── 50 51 out property <color> btn-bg: self.dark ? #EDE9E1 : #232028;
+276 -278
ui/views/profile_tab.slint
··· 19 19 vertical-stretch: 1; 20 20 21 21 VerticalLayout { 22 - padding-left: 24px * Theme.font-scale; 23 - padding-right: 24px * Theme.font-scale; 22 + padding-left: 28px * Theme.font-scale; 23 + padding-right: 28px * Theme.font-scale; 24 24 padding-top: 24px * Theme.font-scale; 25 25 padding-bottom: 24px * Theme.font-scale; 26 26 spacing: 0px; 27 27 28 - // ── System ───────────────────────────────────────────────────────────── 29 - SectionHeading { 30 - title: "System"; 31 - description: "App behavior and configuration."; 32 - } 33 - 34 - Rectangle { height: 12px * Theme.font-scale; } 35 - 36 - Rectangle { 37 - border-radius: 10px * Theme.font-scale; 38 - background: Theme.surface; 39 - border-width: 1px; 40 - border-color: Theme.line; 41 - clip: true; 42 - 43 - VerticalLayout { 44 - // Autostart row 45 - HorizontalLayout { 46 - height: 60px * Theme.font-scale; 47 - padding-left: 16px * Theme.font-scale; 48 - padding-right: 16px * Theme.font-scale; 49 - spacing: 14px * Theme.font-scale; 50 - alignment: center; 51 - 52 - Rectangle { 53 - width: 34px * Theme.font-scale; 54 - height: 34px * Theme.font-scale; 55 - border-radius: 8px * Theme.font-scale; 56 - background: Theme.tint; 57 - 58 - Text { 59 - text: "▶"; 60 - font-size: 11px * Theme.font-scale; 61 - color: Theme.ink-mid; 62 - horizontal-alignment: center; 63 - vertical-alignment: center; 64 - } 65 - } 66 - 67 - VerticalLayout { 68 - horizontal-stretch: 1; 69 - alignment: center; 70 - spacing: 2px; 71 - 72 - Text { 73 - text: "Start quietly at login"; 74 - font-size: Theme.font_body; 75 - font-weight: 500; 76 - color: Theme.ink; 77 - } 78 - 79 - Text { 80 - text: "Launch in the background"; 81 - font-size: Theme.font_xsmall; 82 - color: Theme.ink-mid; 83 - } 84 - } 85 - 86 - PaperToggle { 87 - checked <=> root.autostart; 88 - label: "Start quietly at login"; 89 - } 90 - } 91 - 92 - PaperDivider { } 93 - 94 - // Open config folder row 95 - config-ta := TouchArea { 96 - height: 52px * Theme.font-scale; 97 - accessible-role: AccessibleRole.button; 98 - accessible-label: "Open configuration folder"; 99 - accessible-action-default => { root.open-config-dir(); } 100 - clicked => { root.open-config-dir(); } 101 - 102 - Rectangle { 103 - background: config-ta.has-hover ? Theme.tint : transparent; 104 - animate background { duration: 120ms; } 105 - 106 - HorizontalLayout { 107 - padding-left: 16px * Theme.font-scale; 108 - padding-right: 16px * Theme.font-scale; 109 - spacing: 14px * Theme.font-scale; 110 - alignment: center; 111 - 112 - Rectangle { 113 - width: 34px * Theme.font-scale; 114 - height: 34px * Theme.font-scale; 115 - border-radius: 8px * Theme.font-scale; 116 - background: Theme.tint; 117 - 118 - Text { 119 - text: "⊟"; 120 - font-size: 14px * Theme.font-scale; 121 - color: Theme.ink-mid; 122 - horizontal-alignment: center; 123 - vertical-alignment: center; 124 - } 125 - } 126 - 127 - Text { 128 - horizontal-stretch: 1; 129 - text: "Open configuration folder"; 130 - font-size: Theme.font_body; 131 - font-weight: 500; 132 - color: Theme.ink; 133 - vertical-alignment: center; 134 - } 135 - 136 - Text { 137 - text: "›"; 138 - font-size: 22px * Theme.font-scale; 139 - color: Theme.ink-lo; 140 - vertical-alignment: center; 141 - } 142 - } 143 - } 144 - } 145 - } 146 - } 147 - 148 - Rectangle { height: 24px * Theme.font-scale; } 149 - 150 28 // ── Sensory experience ────────────────────────────────────────────────── 151 29 SectionHeading { 152 30 title: "Sensory experience"; ··· 163 41 Rectangle { 164 42 horizontal-stretch: 1; 165 43 border-radius: 10px * Theme.font-scale; 166 - background: Theme.surface; 167 - border-width: 1px; 168 - border-color: Theme.line; 44 + background: Theme.panel; 169 45 170 46 VerticalLayout { 171 - padding: 14px * Theme.font-scale; 47 + padding: 16px * Theme.font-scale; 172 48 spacing: 12px * Theme.font-scale; 173 49 174 50 Text { ··· 178 54 color: Theme.ink; 179 55 } 180 56 181 - HorizontalLayout { 182 - spacing: 6px * Theme.font-scale; 183 - alignment: start; 57 + // Segmented control pill 58 + Rectangle { 59 + border-radius: 8px * Theme.font-scale; 60 + background: Theme.surface; 61 + border-width: 1px; 62 + border-color: Theme.line; 63 + height: 40px * Theme.font-scale; 64 + 65 + HorizontalLayout { 66 + padding: 3px * Theme.font-scale; 67 + spacing: 2px * Theme.font-scale; 184 68 185 - // Light chip (index 1) 186 - Rectangle { 187 - width: 36px * Theme.font-scale; 188 - height: 36px * Theme.font-scale; 189 - border-radius: 8px * Theme.font-scale; 190 - background: root.theme-mode == 1 ? Theme.btn-bg : (light-ta.has-hover ? Theme.surface-hov : transparent); 191 - border-width: 1px; 192 - border-color: root.theme-mode == 1 ? transparent : Theme.line; 193 - animate background { duration: 120ms; } 194 - accessible-role: AccessibleRole.radio-button; 195 - accessible-label: "Light theme"; 196 - accessible-checked: root.theme-mode == 1; 197 - accessible-action-default => { root.theme-mode = 1; root.theme-mode-changed(1); } 69 + // Light chip 70 + Rectangle { 71 + horizontal-stretch: 1; 72 + border-radius: 6px * Theme.font-scale; 73 + background: root.theme-mode == 1 ? Theme.btn-bg : (light-ta.has-hover ? Theme.surface-hov : transparent); 74 + border-width: 0px; 75 + animate background { duration: 120ms; } 76 + accessible-role: AccessibleRole.radio-button; 77 + accessible-label: "Light theme"; 78 + accessible-checked: root.theme-mode == 1; 79 + accessible-action-default => { root.theme-mode = 1; root.theme-mode-changed(1); } 198 80 199 - light-ta := TouchArea { 200 - clicked => { root.theme-mode = 1; root.theme-mode-changed(1); } 201 - } 81 + light-ta := TouchArea { 82 + clicked => { root.theme-mode = 1; root.theme-mode-changed(1); } 83 + } 202 84 203 - Text { 204 - text: "☀"; 205 - font-size: 16px * Theme.font-scale; 206 - color: root.theme-mode == 1 ? Theme.btn-fg : Theme.ink; 207 - horizontal-alignment: center; 208 - vertical-alignment: center; 85 + Text { 86 + text: "☀"; 87 + font-size: 16px * Theme.font-scale; 88 + color: root.theme-mode == 1 ? Theme.btn-fg : Theme.ink; 89 + horizontal-alignment: center; 90 + vertical-alignment: center; 91 + } 209 92 } 210 - } 211 93 212 - // Dark chip (index 2) 213 - Rectangle { 214 - width: 36px * Theme.font-scale; 215 - height: 36px * Theme.font-scale; 216 - border-radius: 8px * Theme.font-scale; 217 - background: root.theme-mode == 2 ? Theme.btn-bg : (dark-ta.has-hover ? Theme.surface-hov : transparent); 218 - border-width: 1px; 219 - border-color: root.theme-mode == 2 ? transparent : Theme.line; 220 - animate background { duration: 120ms; } 221 - accessible-role: AccessibleRole.radio-button; 222 - accessible-label: "Dark theme"; 223 - accessible-checked: root.theme-mode == 2; 224 - accessible-action-default => { root.theme-mode = 2; root.theme-mode-changed(2); } 94 + // Dark chip 95 + Rectangle { 96 + horizontal-stretch: 1; 97 + border-radius: 6px * Theme.font-scale; 98 + background: root.theme-mode == 2 ? Theme.btn-bg : (dark-ta.has-hover ? Theme.surface-hov : transparent); 99 + border-width: 0px; 100 + animate background { duration: 120ms; } 101 + accessible-role: AccessibleRole.radio-button; 102 + accessible-label: "Dark theme"; 103 + accessible-checked: root.theme-mode == 2; 104 + accessible-action-default => { root.theme-mode = 2; root.theme-mode-changed(2); } 225 105 226 - dark-ta := TouchArea { 227 - clicked => { root.theme-mode = 2; root.theme-mode-changed(2); } 228 - } 106 + dark-ta := TouchArea { 107 + clicked => { root.theme-mode = 2; root.theme-mode-changed(2); } 108 + } 229 109 230 - Text { 231 - text: "☾"; 232 - font-size: 16px * Theme.font-scale; 233 - color: root.theme-mode == 2 ? Theme.btn-fg : Theme.ink; 234 - horizontal-alignment: center; 235 - vertical-alignment: center; 110 + Text { 111 + text: "☾"; 112 + font-size: 16px * Theme.font-scale; 113 + color: root.theme-mode == 2 ? Theme.btn-fg : Theme.ink; 114 + horizontal-alignment: center; 115 + vertical-alignment: center; 116 + } 236 117 } 237 - } 238 118 239 - // System chip (index 0) 240 - Rectangle { 241 - width: 36px * Theme.font-scale; 242 - height: 36px * Theme.font-scale; 243 - border-radius: 8px * Theme.font-scale; 244 - background: root.theme-mode == 0 ? Theme.btn-bg : (sys-ta.has-hover ? Theme.surface-hov : transparent); 245 - border-width: 1px; 246 - border-color: root.theme-mode == 0 ? transparent : Theme.line; 247 - animate background { duration: 120ms; } 248 - accessible-role: AccessibleRole.radio-button; 249 - accessible-label: "System theme"; 250 - accessible-checked: root.theme-mode == 0; 251 - accessible-action-default => { root.theme-mode = 0; root.theme-mode-changed(0); } 119 + // System chip 120 + Rectangle { 121 + horizontal-stretch: 1; 122 + border-radius: 6px * Theme.font-scale; 123 + background: root.theme-mode == 0 ? Theme.btn-bg : (sys-ta.has-hover ? Theme.surface-hov : transparent); 124 + border-width: 0px; 125 + animate background { duration: 120ms; } 126 + accessible-role: AccessibleRole.radio-button; 127 + accessible-label: "System theme"; 128 + accessible-checked: root.theme-mode == 0; 129 + accessible-action-default => { root.theme-mode = 0; root.theme-mode-changed(0); } 252 130 253 - sys-ta := TouchArea { 254 - clicked => { root.theme-mode = 0; root.theme-mode-changed(0); } 255 - } 131 + sys-ta := TouchArea { 132 + clicked => { root.theme-mode = 0; root.theme-mode-changed(0); } 133 + } 256 134 257 - Text { 258 - text: "◑"; 259 - font-size: 16px * Theme.font-scale; 260 - color: root.theme-mode == 0 ? Theme.btn-fg : Theme.ink; 261 - horizontal-alignment: center; 262 - vertical-alignment: center; 135 + Text { 136 + text: "◑"; 137 + font-size: 16px * Theme.font-scale; 138 + color: root.theme-mode == 0 ? Theme.btn-fg : Theme.ink; 139 + horizontal-alignment: center; 140 + vertical-alignment: center; 141 + } 263 142 } 264 143 } 265 144 } ··· 270 149 Rectangle { 271 150 horizontal-stretch: 1; 272 151 border-radius: 10px * Theme.font-scale; 273 - background: Theme.surface; 274 - border-width: 1px; 275 - border-color: Theme.line; 152 + background: Theme.panel; 276 153 277 154 VerticalLayout { 278 - padding: 14px * Theme.font-scale; 155 + padding: 16px * Theme.font-scale; 279 156 spacing: 12px * Theme.font-scale; 280 157 281 158 Text { ··· 285 162 color: Theme.ink; 286 163 } 287 164 288 - // T− [value] T+ stepper 289 - HorizontalLayout { 290 - height: 36px * Theme.font-scale; 291 - spacing: 0px; 292 - alignment: center; 165 + // T− / label / T+ in pill 166 + Rectangle { 167 + border-radius: 8px * Theme.font-scale; 168 + background: Theme.surface; 169 + border-width: 1px; 170 + border-color: Theme.line; 171 + height: 40px * Theme.font-scale; 172 + 173 + HorizontalLayout { 174 + padding: 3px * Theme.font-scale; 293 175 294 - ts-dec := TouchArea { 295 - width: 28px * Theme.font-scale; 296 - accessible-role: AccessibleRole.button; 297 - accessible-label: "Decrease text size"; 298 - accessible-action-default => { 299 - if root.text-size-mode > 0 { 300 - root.text-size-mode -= 1; 301 - root.text-size-mode-changed(root.text-size-mode); 176 + ts-dec := TouchArea { 177 + width: 36px * Theme.font-scale; 178 + accessible-role: AccessibleRole.button; 179 + accessible-label: "Decrease text size"; 180 + accessible-action-default => { 181 + if root.text-size-mode > 0 { 182 + root.text-size-mode -= 1; 183 + root.text-size-mode-changed(root.text-size-mode); 184 + } 302 185 } 303 - } 304 - clicked => { 305 - if root.text-size-mode > 0 { 306 - root.text-size-mode -= 1; 307 - root.text-size-mode-changed(root.text-size-mode); 186 + clicked => { 187 + if root.text-size-mode > 0 { 188 + root.text-size-mode -= 1; 189 + root.text-size-mode-changed(root.text-size-mode); 190 + } 308 191 } 309 - } 310 192 311 - Rectangle { 312 - border-radius: 6px * Theme.font-scale; 313 - background: ts-dec.has-hover ? Theme.tint : transparent; 314 - animate background { duration: 120ms; } 193 + Rectangle { 194 + border-radius: 6px * Theme.font-scale; 195 + background: ts-dec.has-hover ? Theme.surface-hov : transparent; 196 + animate background { duration: 120ms; } 315 197 316 - Text { 317 - text: "T"; 318 - font-size: 11px * Theme.font-scale; 319 - font-weight: 500; 320 - color: root.text-size-mode <= 0 ? Theme.ink-dis : Theme.ink-lo; 321 - horizontal-alignment: center; 322 - vertical-alignment: center; 323 - animate color { duration: 120ms; } 198 + Text { 199 + text: "T"; 200 + font-size: 11px * Theme.font-scale; 201 + font-weight: 500; 202 + color: root.text-size-mode <= 0 ? Theme.ink-dis : Theme.ink-lo; 203 + horizontal-alignment: center; 204 + vertical-alignment: center; 205 + animate color { duration: 120ms; } 206 + } 324 207 } 325 208 } 326 - } 327 209 328 - Text { 329 - horizontal-stretch: 1; 330 - text: ["Compact", "Small", "Default", "Large", "X-Large"][root.text-size-mode]; 331 - font-size: Theme.font_xsmall; 332 - font-weight: 500; 333 - color: Theme.ink; 334 - horizontal-alignment: center; 335 - vertical-alignment: center; 336 - } 210 + Text { 211 + horizontal-stretch: 1; 212 + text: ["Compact", "Small", "Default", "Large", "X-Large"][root.text-size-mode]; 213 + font-size: Theme.font_xsmall; 214 + font-weight: 500; 215 + color: Theme.ink; 216 + horizontal-alignment: center; 217 + vertical-alignment: center; 218 + } 337 219 338 - ts-inc := TouchArea { 339 - width: 28px * Theme.font-scale; 340 - accessible-role: AccessibleRole.button; 341 - accessible-label: "Increase text size"; 342 - accessible-action-default => { 343 - if root.text-size-mode < 4 { 344 - root.text-size-mode += 1; 345 - root.text-size-mode-changed(root.text-size-mode); 220 + ts-inc := TouchArea { 221 + width: 36px * Theme.font-scale; 222 + accessible-role: AccessibleRole.button; 223 + accessible-label: "Increase text size"; 224 + accessible-action-default => { 225 + if root.text-size-mode < 4 { 226 + root.text-size-mode += 1; 227 + root.text-size-mode-changed(root.text-size-mode); 228 + } 346 229 } 347 - } 348 - clicked => { 349 - if root.text-size-mode < 4 { 350 - root.text-size-mode += 1; 351 - root.text-size-mode-changed(root.text-size-mode); 230 + clicked => { 231 + if root.text-size-mode < 4 { 232 + root.text-size-mode += 1; 233 + root.text-size-mode-changed(root.text-size-mode); 234 + } 352 235 } 353 - } 354 236 355 - Rectangle { 356 - border-radius: 6px * Theme.font-scale; 357 - background: ts-inc.has-hover ? Theme.tint : transparent; 358 - animate background { duration: 120ms; } 237 + Rectangle { 238 + border-radius: 6px * Theme.font-scale; 239 + background: ts-inc.has-hover ? Theme.surface-hov : transparent; 240 + animate background { duration: 120ms; } 359 241 360 - Text { 361 - text: "T"; 362 - font-size: 18px * Theme.font-scale; 363 - font-weight: 500; 364 - color: root.text-size-mode >= 4 ? Theme.ink-dis : Theme.ink-lo; 365 - horizontal-alignment: center; 366 - vertical-alignment: center; 367 - animate color { duration: 120ms; } 242 + Text { 243 + text: "T"; 244 + font-size: 18px * Theme.font-scale; 245 + font-weight: 500; 246 + color: root.text-size-mode >= 4 ? Theme.ink-dis : Theme.ink-lo; 247 + horizontal-alignment: center; 248 + vertical-alignment: center; 249 + animate color { duration: 120ms; } 250 + } 368 251 } 369 252 } 370 253 } ··· 378 261 // Chime card 379 262 Rectangle { 380 263 border-radius: 10px * Theme.font-scale; 381 - background: Theme.surface; 382 - border-width: 1px; 383 - border-color: Theme.line; 264 + background: Theme.panel; 384 265 clip: true; 385 266 386 267 VerticalLayout { ··· 392 273 spacing: 14px * Theme.font-scale; 393 274 alignment: center; 394 275 395 - // Accent icon badge 396 276 Rectangle { 397 277 width: 36px * Theme.font-scale; 398 278 height: 36px * Theme.font-scale; ··· 476 356 477 357 Rectangle { height: 24px * Theme.font-scale; } 478 358 359 + // ── System ───────────────────────────────────────────────────────────── 360 + SectionHeading { 361 + title: "System"; 362 + description: "App behavior and configuration."; 363 + } 364 + 365 + Rectangle { height: 12px * Theme.font-scale; } 366 + 367 + Rectangle { 368 + border-radius: 10px * Theme.font-scale; 369 + background: Theme.panel; 370 + clip: true; 371 + 372 + VerticalLayout { 373 + // Autostart row 374 + HorizontalLayout { 375 + height: 60px * Theme.font-scale; 376 + padding-left: 16px * Theme.font-scale; 377 + padding-right: 16px * Theme.font-scale; 378 + spacing: 14px * Theme.font-scale; 379 + alignment: center; 380 + 381 + Rectangle { 382 + width: 34px * Theme.font-scale; 383 + height: 34px * Theme.font-scale; 384 + border-radius: 8px * Theme.font-scale; 385 + background: Theme.surface; 386 + 387 + Text { 388 + text: "▶"; 389 + font-size: 11px * Theme.font-scale; 390 + color: Theme.ink-mid; 391 + horizontal-alignment: center; 392 + vertical-alignment: center; 393 + } 394 + } 395 + 396 + VerticalLayout { 397 + horizontal-stretch: 1; 398 + alignment: center; 399 + spacing: 2px; 400 + 401 + Text { 402 + text: "Start quietly at login"; 403 + font-size: Theme.font_body; 404 + font-weight: 500; 405 + color: Theme.ink; 406 + } 407 + 408 + Text { 409 + text: "Launch in the background"; 410 + font-size: Theme.font_xsmall; 411 + color: Theme.ink-mid; 412 + } 413 + } 414 + 415 + PaperToggle { 416 + checked <=> root.autostart; 417 + label: "Start quietly at login"; 418 + } 419 + } 420 + 421 + PaperDivider { } 422 + 423 + // Open config folder row 424 + config-ta := TouchArea { 425 + height: 52px * Theme.font-scale; 426 + accessible-role: AccessibleRole.button; 427 + accessible-label: "Open configuration folder"; 428 + accessible-action-default => { root.open-config-dir(); } 429 + clicked => { root.open-config-dir(); } 430 + 431 + Rectangle { 432 + background: config-ta.has-hover ? Theme.tint : transparent; 433 + animate background { duration: 120ms; } 434 + 435 + HorizontalLayout { 436 + padding-left: 16px * Theme.font-scale; 437 + padding-right: 16px * Theme.font-scale; 438 + spacing: 14px * Theme.font-scale; 439 + alignment: center; 440 + 441 + Rectangle { 442 + width: 34px * Theme.font-scale; 443 + height: 34px * Theme.font-scale; 444 + border-radius: 8px * Theme.font-scale; 445 + background: Theme.surface; 446 + 447 + Text { 448 + text: "⊟"; 449 + font-size: 14px * Theme.font-scale; 450 + color: Theme.ink-mid; 451 + horizontal-alignment: center; 452 + vertical-alignment: center; 453 + } 454 + } 455 + 456 + Text { 457 + horizontal-stretch: 1; 458 + text: "Open configuration folder"; 459 + font-size: Theme.font_body; 460 + font-weight: 500; 461 + color: Theme.ink; 462 + vertical-alignment: center; 463 + } 464 + 465 + Text { 466 + text: "›"; 467 + font-size: 22px * Theme.font-scale; 468 + color: Theme.ink-lo; 469 + vertical-alignment: center; 470 + } 471 + } 472 + } 473 + } 474 + } 475 + } 476 + 477 + Rectangle { height: 24px * Theme.font-scale; } 478 + 479 479 // ── Behavior ──────────────────────────────────────────────────────────── 480 480 SectionHeading { 481 481 title: "Behavior"; ··· 486 486 487 487 Rectangle { 488 488 border-radius: 10px * Theme.font-scale; 489 - background: Theme.surface; 490 - border-width: 1px; 491 - border-color: Theme.line; 489 + background: Theme.panel; 492 490 493 491 HorizontalLayout { 494 492 height: 66px * Theme.font-scale; ··· 501 499 width: 34px * Theme.font-scale; 502 500 height: 34px * Theme.font-scale; 503 501 border-radius: 8px * Theme.font-scale; 504 - background: Theme.tint; 502 + background: Theme.surface; 505 503 506 504 Text { 507 505 text: "⟳";
+167 -163
ui/views/rhythm_tab.slint
··· 42 42 padding-left: 28px * Theme.font-scale; 43 43 padding-right: 28px * Theme.font-scale; 44 44 padding-top: 24px * Theme.font-scale; 45 - padding-bottom: 16px * Theme.font-scale; 45 + padding-bottom: 20px * Theme.font-scale; 46 46 spacing: 0px; 47 47 48 + // ── Active profile ────────────────────────────────────────────────────── 48 49 HorizontalLayout { 49 - padding-bottom: 14px * Theme.font-scale; 50 + padding-bottom: 20px * Theme.font-scale; 50 51 spacing: 24px * Theme.font-scale; 51 52 52 53 SettingLabel { 53 54 title: "Active profile"; 55 + description: "The cadence ioma follows today."; 54 56 } 55 57 56 58 Rectangle { horizontal-stretch: 1; } 57 59 58 - PaperComboBox { 59 - width: 140px * Theme.font-scale; 60 - model: root.profile-names; 61 - selected-index: root.profile-index; 62 - field-label: "Active profile"; 63 - selection-changed(i) => { 64 - root.active-profile = root.profile-names[i]; 65 - root.profile-changed(root.profile-names[i]); 60 + VerticalLayout { 61 + alignment: center; 62 + 63 + PaperComboBox { 64 + width: 140px * Theme.font-scale; 65 + model: root.profile-names; 66 + selected-index: root.profile-index; 67 + field-label: "Active profile"; 68 + selection-changed(i) => { 69 + root.active-profile = root.profile-names[i]; 70 + root.profile-changed(root.profile-names[i]); 71 + } 66 72 } 67 73 } 68 74 } 69 75 70 - Rectangle { height: 16px * Theme.font-scale; } 76 + // ── Break cadence panel ───────────────────────────────────────────────── 77 + Rectangle { 78 + border-radius: 10px * Theme.font-scale; 79 + background: Theme.panel; 71 80 72 - Text { 73 - text: "Break cadence"; 74 - font-size: Theme.font_body; 75 - font-weight: 500; 76 - color: Theme.ink; 77 - } 81 + VerticalLayout { 82 + padding: 20px * Theme.font-scale; 83 + spacing: 20px * Theme.font-scale; 78 84 79 - Rectangle { height: 14px * Theme.font-scale; } 80 - 81 - for level[i] in root.levels: VerticalLayout { 82 - spacing: 0px; 83 - 84 - IntervalCard { 85 - index: i + 1; 86 - work-mins: level.work-mins; 87 - break-mins: level.break-mins; 88 - break-secs: level.break-extra-secs; 89 - label: level.label; 90 - enforced: level.enforced; 91 - remove-clicked => { root.level-removed(i); } 92 - work-mins-changed(v) => { 93 - root.level-changed(i, { 94 - work-mins: v, 95 - break-mins: level.break-mins, 96 - break-extra-secs: level.break-extra-secs, 97 - label: level.label, 98 - enforced: level.enforced, 99 - }); 85 + SectionHeading { 86 + title: "Break cadence"; 87 + description: "Each row is an interval. ioma cycles through them in order."; 100 88 } 101 - break-mins-changed(v) => { 102 - root.level-changed(i, { 103 - work-mins: level.work-mins, 104 - break-mins: v, 105 - break-extra-secs: level.break-extra-secs, 106 - label: level.label, 107 - enforced: level.enforced, 108 - }); 109 - } 110 - break-secs-changed(v) => { 111 - root.level-changed(i, { 112 - work-mins: level.work-mins, 113 - break-mins: level.break-mins, 114 - break-extra-secs: v, 115 - label: level.label, 116 - enforced: level.enforced, 117 - }); 118 - } 119 - label-changed(v) => { 120 - root.level-changed(i, { 121 - work-mins: level.work-mins, 122 - break-mins: level.break-mins, 123 - break-extra-secs: level.break-extra-secs, 124 - label: v, 125 - enforced: level.enforced, 126 - }); 127 - } 128 - enforced-changed(v) => { 129 - root.level-changed(i, { 130 - work-mins: level.work-mins, 131 - break-mins: level.break-mins, 132 - break-extra-secs: level.break-extra-secs, 133 - label: level.label, 134 - enforced: v, 135 - }); 136 - } 137 - } 138 89 139 - Rectangle { height: 10px * Theme.font-scale; } 140 - } 141 - 142 - LongRestCard { 143 - index: root.levels.length + 1; 144 - enabled <=> root.long-break-enabled; 145 - after-cycles <=> root.long-break-after-cycles; 146 - duration-mins <=> root.long-break-duration-mins; 147 - label <=> root.long-break-label; 148 - enforced <=> root.long-break-enforced; 149 - } 90 + for level[i] in root.levels: IntervalCard { 91 + index: i + 1; 92 + work-mins: level.work-mins; 93 + break-mins: level.break-mins; 94 + break-secs: level.break-extra-secs; 95 + label: level.label; 96 + enforced: level.enforced; 97 + remove-clicked => { root.level-removed(i); } 98 + work-mins-changed(v) => { 99 + root.level-changed(i, { 100 + work-mins: v, 101 + break-mins: level.break-mins, 102 + break-extra-secs: level.break-extra-secs, 103 + label: level.label, 104 + enforced: level.enforced, 105 + }); 106 + } 107 + break-mins-changed(v) => { 108 + root.level-changed(i, { 109 + work-mins: level.work-mins, 110 + break-mins: v, 111 + break-extra-secs: level.break-extra-secs, 112 + label: level.label, 113 + enforced: level.enforced, 114 + }); 115 + } 116 + break-secs-changed(v) => { 117 + root.level-changed(i, { 118 + work-mins: level.work-mins, 119 + break-mins: level.break-mins, 120 + break-extra-secs: v, 121 + label: level.label, 122 + enforced: level.enforced, 123 + }); 124 + } 125 + label-changed(v) => { 126 + root.level-changed(i, { 127 + work-mins: level.work-mins, 128 + break-mins: level.break-mins, 129 + break-extra-secs: level.break-extra-secs, 130 + label: v, 131 + enforced: level.enforced, 132 + }); 133 + } 134 + enforced-changed(v) => { 135 + root.level-changed(i, { 136 + work-mins: level.work-mins, 137 + break-mins: level.break-mins, 138 + break-extra-secs: level.break-extra-secs, 139 + label: level.label, 140 + enforced: v, 141 + }); 142 + } 143 + } 150 144 151 - Rectangle { height: 10px * Theme.font-scale; } 145 + LongRestCard { 146 + index: root.levels.length + 1; 147 + enabled <=> root.long-break-enabled; 148 + after-cycles <=> root.long-break-after-cycles; 149 + duration-mins <=> root.long-break-duration-mins; 150 + label <=> root.long-break-label; 151 + enforced <=> root.long-break-enforced; 152 + } 152 153 153 - add-ta := TouchArea { 154 - height: 44px * Theme.font-scale; 155 - accessible-role: AccessibleRole.button; 156 - accessible-label: "Add interval"; 157 - accessible-action-default => { root.level-added(); } 158 - clicked => { root.level-added(); } 154 + add-ta := TouchArea { 155 + height: 44px * Theme.font-scale; 156 + accessible-role: AccessibleRole.button; 157 + accessible-label: "Add interval"; 158 + accessible-action-default => { root.level-added(); } 159 + clicked => { root.level-added(); } 159 160 160 - Rectangle { 161 - border-radius: 8px * Theme.font-scale; 162 - background: add-ta.has-hover ? Theme.surface-hov : transparent; 163 - border-width: 1px; 164 - border-color: Theme.line-med; 161 + Rectangle { 162 + border-radius: 8px * Theme.font-scale; 163 + background: add-ta.has-hover ? Theme.surface-hov : transparent; 164 + border-width: 1px; 165 + border-color: Theme.line-med; 165 166 166 - Text { 167 - text: "+ Add interval"; 168 - font-size: Theme.font_xsmall; 169 - color: add-ta.has-hover ? Theme.ink : Theme.ink-lo; 170 - horizontal-alignment: center; 171 - vertical-alignment: center; 172 - animate color { duration: 120ms; } 167 + Text { 168 + text: "+ Add interval"; 169 + font-size: Theme.font_xsmall; 170 + color: add-ta.has-hover ? Theme.ink : Theme.ink-lo; 171 + horizontal-alignment: center; 172 + vertical-alignment: center; 173 + animate color { duration: 120ms; } 174 + } 175 + } 173 176 } 174 177 } 175 178 } 176 179 177 - Rectangle { height: 28px * Theme.font-scale; } 180 + Rectangle { height: 20px * Theme.font-scale; } 178 181 179 - SectionHeading { 180 - title: "During breaks"; 181 - description: "Rules for how breaks are handled when they start."; 182 - } 182 + // ── During breaks panel ───────────────────────────────────────────────── 183 + Rectangle { 184 + border-radius: 10px * Theme.font-scale; 185 + background: Theme.panel; 183 186 184 - Rectangle { height: 14px * Theme.font-scale; } 187 + VerticalLayout { 188 + padding: 20px * Theme.font-scale; 189 + spacing: 16px * Theme.font-scale; 185 190 186 - // Idle detection — toggle + inline controls on one row 187 - HorizontalLayout { 188 - spacing: 10px * Theme.font-scale; 189 - alignment: start; 191 + SectionHeading { 192 + title: "During breaks"; 193 + description: "Rules for how breaks are handled when they start."; 194 + } 190 195 191 - PaperToggle { 192 - checked <=> root.idle-detection-enabled; 193 - label: "Pause timer if idle"; 194 - } 196 + HorizontalLayout { 197 + spacing: 10px * Theme.font-scale; 198 + alignment: start; 195 199 196 - Text { 197 - text: "Pause timer if I'm idle for"; 198 - font-size: Theme.font_label; 199 - color: Theme.ink-mid; 200 - vertical-alignment: center; 201 - opacity: root.idle-detection-enabled ? 1.0 : 0.4; 202 - animate opacity { duration: 120ms; } 203 - } 200 + PaperToggle { 201 + checked <=> root.idle-detection-enabled; 202 + label: "Pause timer if idle"; 203 + } 204 204 205 - NumberField { 206 - width: 80px * Theme.font-scale; 207 - value <=> root.idle-threshold-mins; 208 - minimum: 1; 209 - maximum: 60; 210 - enabled: root.idle-detection-enabled; 211 - field-label: "Idle threshold minutes"; 212 - } 205 + Text { 206 + text: "Pause timer if I'm idle for"; 207 + font-size: Theme.font_label; 208 + color: Theme.ink-mid; 209 + vertical-alignment: center; 210 + opacity: root.idle-detection-enabled ? 1.0 : 0.4; 211 + animate opacity { duration: 120ms; } 212 + } 213 213 214 - Text { 215 - text: "minutes."; 216 - font-size: Theme.font_label; 217 - color: Theme.ink-mid; 218 - vertical-alignment: center; 219 - opacity: root.idle-detection-enabled ? 1.0 : 0.4; 220 - animate opacity { duration: 120ms; } 221 - } 222 - } 223 - 224 - Rectangle { height: 16px * Theme.font-scale; } 214 + NumberField { 215 + width: 80px * Theme.font-scale; 216 + value <=> root.idle-threshold-mins; 217 + minimum: 1; 218 + maximum: 60; 219 + enabled: root.idle-detection-enabled; 220 + field-label: "Idle threshold minutes"; 221 + } 225 222 226 - PaperDivider { } 223 + Text { 224 + text: "minutes."; 225 + font-size: Theme.font_label; 226 + color: Theme.ink-mid; 227 + vertical-alignment: center; 228 + opacity: root.idle-detection-enabled ? 1.0 : 0.4; 229 + animate opacity { duration: 120ms; } 230 + } 231 + } 227 232 228 - Rectangle { height: 14px * Theme.font-scale; } 233 + PaperDivider { } 229 234 230 - // Emergency unlock 231 - HorizontalLayout { 232 - spacing: 24px * Theme.font-scale; 235 + HorizontalLayout { 236 + spacing: 24px * Theme.font-scale; 233 237 234 - SettingLabel { 235 - title: "Emergency unlock"; 236 - description: "Set a password to skip enforced breaks."; 237 - } 238 + SettingLabel { 239 + title: "Emergency unlock"; 240 + description: "Set a password to skip enforced breaks."; 241 + } 238 242 239 - Rectangle { horizontal-stretch: 1; } 243 + Rectangle { horizontal-stretch: 1; } 240 244 241 - VerticalLayout { 242 - alignment: LayoutAlignment.center; 245 + VerticalLayout { 246 + alignment: LayoutAlignment.center; 243 247 244 - PaperButton { 245 - text: root.password-is-set ? "Change password…" : "Set password…"; 246 - clicked => { root.set-password-clicked(); } 248 + PaperButton { 249 + text: root.password-is-set ? "Change password…" : "Set password…"; 250 + clicked => { root.set-password-clicked(); } 251 + } 252 + } 247 253 } 248 254 } 249 255 } 250 - 251 - Rectangle { height: 8px * Theme.font-scale; } 252 256 253 257 Rectangle { vertical-stretch: 1; } 254 258 }