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): replace buttons with dropdown selectors, remove unneeded text and dividers

+153 -40
+118
ui/components/inputs.slint
··· 260 260 } 261 261 } 262 262 } 263 + 264 + export component PaperComboBox { 265 + in property <[string]> model: []; 266 + in property <int> selected-index: 0; 267 + in property <string> field-label: ""; 268 + callback selection-changed(int); 269 + 270 + height: 24px * Theme.font-scale; 271 + min-width: 80px; 272 + 273 + accessible-role: combobox; 274 + accessible-label: root.field-label; 275 + accessible-value: root.model[root.selected-index]; 276 + 277 + fs := FocusScope { 278 + key-pressed(event) => { 279 + if event.text == Key.UpArrow || event.text == Key.LeftArrow { 280 + if root.selected-index > 0 { 281 + root.selection-changed(root.selected-index - 1); 282 + } 283 + return EventResult.accept; 284 + } 285 + if event.text == Key.DownArrow || event.text == Key.RightArrow { 286 + if root.selected-index < root.model.length - 1 { 287 + root.selection-changed(root.selected-index + 1); 288 + } 289 + return EventResult.accept; 290 + } 291 + EventResult.reject 292 + } 293 + } 294 + 295 + outer := Rectangle { 296 + border-radius: 5px; 297 + background: ta.has-hover ? Theme.surface-hov : Theme.surface; 298 + border-width: 1px; 299 + border-color: fs.has-focus ? Theme.accent-muted : Theme.line; 300 + animate background { duration: 120ms; } 301 + animate border-color { duration: 120ms; } 302 + 303 + ta := TouchArea { 304 + clicked => { 305 + fs.focus(); 306 + popup.show(); 307 + } 308 + } 309 + 310 + HorizontalLayout { 311 + padding-left: 8px; 312 + padding-right: 6px; 313 + 314 + Text { 315 + text: root.model[root.selected-index]; 316 + font-size: Theme.font_xsmall; 317 + color: Theme.ink; 318 + vertical-alignment: center; 319 + horizontal-stretch: 1; 320 + } 321 + 322 + Text { 323 + text: "▾"; 324 + font-size: 9px; 325 + color: Theme.ink-lo; 326 + vertical-alignment: center; 327 + } 328 + } 329 + 330 + popup := PopupWindow { 331 + y: parent.height + 2px; 332 + width: parent.width; 333 + height: root.model.length * (26px * Theme.font-scale) + 6px; 334 + 335 + Rectangle { 336 + background: Theme.bg; 337 + border-radius: 7px; 338 + border-width: 1px; 339 + border-color: Theme.line-med; 340 + drop-shadow-blur: 12px; 341 + drop-shadow-offset-y: 4px; 342 + drop-shadow-color: Theme.shadow; 343 + clip: true; 344 + 345 + VerticalLayout { 346 + padding: 3px; 347 + spacing: 1px; 348 + 349 + for item[i] in root.model: item-ta := TouchArea { 350 + height: 26px * Theme.font-scale; 351 + clicked => { 352 + root.selection-changed(i); 353 + popup.close(); 354 + } 355 + 356 + Rectangle { 357 + background: i == root.selected-index ? Theme.btn-bg : 358 + (item-ta.has-hover ? Theme.surface-hov : transparent); 359 + border-radius: 4px; 360 + animate background { duration: 80ms; } 361 + 362 + HorizontalLayout { 363 + padding-left: 8px; 364 + padding-right: 8px; 365 + 366 + Text { 367 + text: item; 368 + font-size: Theme.font_xsmall; 369 + font-weight: i == root.selected-index ? 600 : 400; 370 + color: i == root.selected-index ? Theme.btn-fg : Theme.ink; 371 + vertical-alignment: center; 372 + } 373 + } 374 + } 375 + } 376 + } 377 + } 378 + } 379 + } 380 + }
+3 -3
ui/settings.slint
··· 15 15 16 16 export component SettingsWindow inherits Window { 17 17 title: "ioma — Settings"; 18 - preferred-width: 760px; 19 - preferred-height: 680px; 20 - min-width: 520px; 18 + preferred-width: 640px; 19 + preferred-height: 580px; 20 + min-width: 460px; 21 21 background: Theme.bg; 22 22 default-font-family: "Nunito"; 23 23
+18 -20
ui/views/profile_tab.slint
··· 1 1 import { ScrollView } from "std-widgets.slint"; 2 2 import { Theme } from "../theme.slint"; 3 - import { PaperDivider, SettingLabel } from "../components/atoms.slint"; 4 - import { ProfileChips } from "../components/chips.slint"; 3 + import { SettingLabel } from "../components/atoms.slint"; 5 4 import { PaperToggle } from "../components/toggles.slint"; 6 - import { NumberField, PaperInput } from "../components/inputs.slint"; 5 + import { NumberField, PaperInput, PaperComboBox } from "../components/inputs.slint"; 7 6 import { IntervalCard, LevelEntry } from "../components/interval_card.slint"; 8 7 9 8 export { LevelEntry } ··· 24 23 callback level-added; 25 24 callback profile-changed(string); 26 25 26 + private property <int> profile-index: 27 + root.active-profile == root.profile-names[0] ? 0 : 28 + root.active-profile == root.profile-names[1] ? 1 : 29 + root.active-profile == root.profile-names[2] ? 2 : 30 + root.active-profile == root.profile-names[3] ? 3 : 31 + root.active-profile == root.profile-names[4] ? 4 : 32 + root.active-profile == root.profile-names[5] ? 5 : 0; 33 + 27 34 vertical-stretch: 1; 28 35 29 36 VerticalLayout { ··· 39 46 40 47 SettingLabel { 41 48 title: "Active profile"; 42 - description: "The cadence ioma follows today."; 43 49 } 44 50 45 51 Rectangle { horizontal-stretch: 1; } 46 52 47 - ProfileChips { 48 - profile-names: root.profile-names; 49 - name-widths: root.profile-name-widths; 50 - active-profile <=> root.active-profile; 51 - selection-changed(name) => { 52 - root.profile-changed(name); 53 + PaperComboBox { 54 + model: root.profile-names; 55 + selected-index: root.profile-index; 56 + field-label: "Active profile"; 57 + selection-changed(i) => { 58 + root.active-profile = root.profile-names[i]; 59 + root.profile-changed(root.profile-names[i]); 53 60 } 54 61 } 55 62 } 56 63 57 - PaperDivider { } 58 - Rectangle { height: 20px; } 64 + Rectangle { height: 16px; } 59 65 60 66 Text { 61 67 text: "Break cadence"; 62 68 font-size: Theme.font_body; 63 69 font-weight: 500; 64 70 color: Theme.ink; 65 - } 66 - 67 - Text { 68 - text: "Each row is an interval. ioma cycles through them in order."; 69 - font-size: Theme.font_xsmall; 70 - color: Theme.ink-mid; 71 71 } 72 72 73 73 Rectangle { height: 14px; } ··· 143 143 } 144 144 } 145 145 146 - Rectangle { height: 20px; } 147 - PaperDivider { } 148 146 Rectangle { height: 20px; } 149 147 150 148 HorizontalLayout {
+14 -17
ui/views/rhythm_tab.slint
··· 2 2 import { Theme } from "../theme.slint"; 3 3 import { SettingLabel, PaperDivider, SectionHeading } from "../components/atoms.slint"; 4 4 import { PaperButton } from "../components/buttons.slint"; 5 - import { ChipGroup } from "../components/chips.slint"; 6 - import { NumberField, VolumeSlider } from "../components/inputs.slint"; 5 + import { NumberField, VolumeSlider, PaperComboBox } from "../components/inputs.slint"; 7 6 import { PaperToggle } from "../components/toggles.slint"; 8 7 9 8 export component RhythmTab inherits ScrollView { ··· 32 31 33 32 SectionHeading { 34 33 title: "During breaks"; 35 - description: "How firmly ioma holds the pause when it is time to rest."; 36 34 } 37 35 38 36 Rectangle { height: 12px; } ··· 121 119 122 120 SectionHeading { 123 121 title: "Sensory experience"; 124 - description: "Sound, appearance, and readability across the overlay and settings."; 125 122 } 126 123 127 124 Rectangle { height: 12px; } ··· 136 133 137 134 SettingLabel { 138 135 title: "Chime on break start"; 139 - description: "A single, gentle tone."; 140 136 } 141 137 142 138 Rectangle { horizontal-stretch: 1; } ··· 182 178 183 179 SettingLabel { 184 180 title: "Appearance"; 185 - description: "Changes the look of the overlay and settings."; 186 181 } 187 182 188 183 Rectangle { horizontal-stretch: 1; } 189 184 190 - ChipGroup { 191 - labels: ["System", "Light", "Dark"]; 192 - selected-index <=> root.theme-mode; 185 + PaperComboBox { 186 + model: ["System", "Light", "Dark"]; 187 + selected-index: root.theme-mode; 188 + field-label: "Appearance"; 193 189 selection-changed(i) => { 190 + root.theme-mode = i; 194 191 root.theme-mode-changed(i); 195 192 } 196 193 } ··· 203 200 204 201 SettingLabel { 205 202 title: "Text size"; 206 - description: "Adjusts readability throughout the app."; 207 203 } 208 204 209 205 Rectangle { horizontal-stretch: 1; } 210 206 211 - ChipGroup { 212 - labels: ["Smaller", "Small", "Default", "Large", "Larger"]; 213 - selected-index <=> root.text-size-mode; 214 - selection-changed(i) => { 215 - root.text-size-mode-changed(i); 207 + NumberField { 208 + width: 100px; 209 + value <=> root.text-size-mode; 210 + minimum: 0; 211 + maximum: 4; 212 + field-label: "Text size"; 213 + edited(v) => { 214 + root.text-size-mode-changed(v); 216 215 } 217 216 } 218 217 } ··· 222 221 223 222 SectionHeading { 224 223 title: "On this computer"; 225 - description: "Startup behavior and quick access to local configuration."; 226 224 } 227 225 228 226 Rectangle { height: 12px; } ··· 237 235 238 236 SettingLabel { 239 237 title: "Launch with system"; 240 - description: "ioma starts quietly at login."; 241 238 } 242 239 243 240 Rectangle { horizontal-stretch: 1; }