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.

refactor(ui): replace long-break section with card, move reset-after to prefs

+168 -114
+120
ui/components/interval_card.slint
··· 1 1 import { Theme } from "../theme.slint"; 2 2 import { NumberField, PaperInput } from "inputs.slint"; 3 + import { PaperToggle } from "toggles.slint"; 3 4 4 5 export struct LevelEntry { 5 6 work-mins: int, ··· 159 160 } 160 161 } 161 162 } 163 + 164 + export component LongRestCard { 165 + in property <int> index; 166 + in-out property <bool> enabled: false; 167 + in-out property <int> after-cycles: 2; 168 + in-out property <int> duration-mins: 30; 169 + in-out property <string> label: "Long rest"; 170 + 171 + callback enabled-changed(bool); 172 + callback after-cycles-changed(int); 173 + callback duration-mins-changed(int); 174 + callback label-changed(string); 175 + 176 + Rectangle { 177 + border-radius: 8px; 178 + background: Theme.surface; 179 + border-width: 1px; 180 + border-color: Theme.line; 181 + 182 + HorizontalLayout { 183 + padding-left: 18px; 184 + padding-right: 14px; 185 + padding-top: 12px; 186 + padding-bottom: 12px; 187 + spacing: 18px; 188 + 189 + // Index column — matches IntervalCard 190 + VerticalLayout { 191 + spacing: 8px; 192 + width: 20px; 193 + 194 + Text { 195 + text: root.index; 196 + font-family: "Shippori Mincho"; 197 + font-size: Theme.font_headline; 198 + color: Theme.ink-hi; 199 + height: 34px; 200 + horizontal-alignment: center; 201 + vertical-alignment: bottom; 202 + } 203 + 204 + Rectangle { height: 28px; } 205 + } 206 + 207 + VerticalLayout { 208 + spacing: 8px; 209 + 210 + HorizontalLayout { 211 + spacing: 8px; 212 + 213 + PaperInput { 214 + width: 200px; 215 + text: root.label; 216 + placeholder-text: "Long rest"; 217 + field-label: "long rest label"; 218 + edited(v) => { root.label-changed(v); } 219 + } 220 + 221 + Rectangle { horizontal-stretch: 1; } 222 + } 223 + 224 + HorizontalLayout { 225 + spacing: 8px; 226 + alignment: start; 227 + opacity: root.enabled ? 1.0 : 0.35; 228 + animate opacity { duration: 120ms; } 229 + 230 + Rectangle { width: 4px; } 231 + 232 + Text { 233 + text: "every"; 234 + font-size: Theme.font_label; 235 + color: Theme.ink-mid; 236 + vertical-alignment: center; 237 + } 238 + 239 + NumberField { 240 + width: 80px; 241 + value <=> root.after-cycles; 242 + minimum: 2; 243 + maximum: 20; 244 + field-label: "cycles before long rest"; 245 + } 246 + 247 + Text { 248 + text: "cycles · pause"; 249 + font-size: Theme.font_label; 250 + color: Theme.ink-mid; 251 + vertical-alignment: center; 252 + } 253 + 254 + NumberField { 255 + width: 72px; 256 + value <=> root.duration-mins; 257 + minimum: 1; 258 + maximum: 120; 259 + field-label: "long rest duration minutes"; 260 + } 261 + 262 + Text { 263 + text: "min"; 264 + font-size: Theme.font_label; 265 + color: Theme.ink-mid; 266 + vertical-alignment: center; 267 + } 268 + } 269 + } 270 + 271 + VerticalLayout { 272 + alignment: LayoutAlignment.stretch; 273 + 274 + PaperToggle { 275 + checked <=> root.enabled; 276 + label: "Long rest"; 277 + } 278 + } 279 + } 280 + } 281 + }
+1 -1
ui/settings.slint
··· 104 104 long-break-enabled <=> root.long-break-enabled; 105 105 long-break-after-cycles <=> root.long-break-after-cycles; 106 106 long-break-duration-mins <=> root.long-break-duration-mins; 107 - long-break-gap-mins <=> root.long-break-gap-mins; 108 107 long-break-label <=> root.long-break-label; 109 108 enforced-mode <=> root.enforced-mode; 110 109 idle-detection-enabled <=> root.idle-detection-enabled; ··· 124 123 autostart <=> root.autostart; 125 124 theme-mode <=> root.theme-mode; 126 125 text-size-mode <=> root.text-size-mode; 126 + long-break-gap-mins <=> root.long-break-gap-mins; 127 127 open-config-dir => { root.open-config-dir(); } 128 128 theme-mode-changed(i) => { root.theme-mode-changed(i); } 129 129 text-size-mode-changed(i) => { root.text-size-mode-changed(i); }
+35 -1
ui/views/profile_tab.slint
··· 2 2 import { Theme } from "../theme.slint"; 3 3 import { SettingLabel } from "../components/atoms.slint"; 4 4 import { PaperButton } from "../components/buttons.slint"; 5 - import { VolumeSlider, PaperComboBox } from "../components/inputs.slint"; 5 + import { VolumeSlider, PaperComboBox, NumberField } from "../components/inputs.slint"; 6 6 import { PaperToggle } from "../components/toggles.slint"; 7 7 import { ChipGroup } from "../components/chips.slint"; 8 8 ··· 12 12 in-out property <bool> autostart: false; 13 13 in-out property <int> theme-mode: 0; 14 14 in-out property <int> text-size-mode: 0; 15 + in-out property <int> long-break-gap-mins: 30; 15 16 16 17 callback open-config-dir; 17 18 callback theme-mode-changed(int); ··· 130 131 PaperToggle { 131 132 checked <=> root.autostart; 132 133 label: "Launch with system"; 134 + } 135 + } 136 + 137 + HorizontalLayout { 138 + padding-top: 12px; 139 + padding-bottom: 4px; 140 + spacing: 24px; 141 + 142 + SettingLabel { 143 + title: "Reset after"; 144 + description: "Time away before resetting the long-rest cycle."; 145 + } 146 + 147 + Rectangle { horizontal-stretch: 1; } 148 + 149 + HorizontalLayout { 150 + spacing: 8px; 151 + alignment: start; 152 + 153 + NumberField { 154 + width: 80px; 155 + value <=> root.long-break-gap-mins; 156 + minimum: 1; 157 + maximum: 120; 158 + field-label: "idle reset threshold minutes"; 159 + } 160 + 161 + Text { 162 + text: "min away"; 163 + font-size: Theme.font_label; 164 + color: Theme.ink-mid; 165 + vertical-alignment: center; 166 + } 133 167 } 134 168 } 135 169
+12 -112
ui/views/rhythm_tab.slint
··· 3 3 import { SettingLabel, SectionHeading } from "../components/atoms.slint"; 4 4 import { PaperButton } from "../components/buttons.slint"; 5 5 import { PaperToggle } from "../components/toggles.slint"; 6 - import { NumberField, PaperInput, PaperComboBox } from "../components/inputs.slint"; 7 - import { IntervalCard, LevelEntry } from "../components/interval_card.slint"; 6 + import { NumberField, PaperComboBox } from "../components/inputs.slint"; 7 + import { IntervalCard, LongRestCard, LevelEntry } from "../components/interval_card.slint"; 8 8 9 9 export { LevelEntry } 10 10 ··· 16 16 in-out property <bool> long-break-enabled: false; 17 17 in-out property <int> long-break-after-cycles: 3; 18 18 in-out property <int> long-break-duration-mins: 30; 19 - in-out property <int> long-break-gap-mins: 30; 20 19 in-out property <string> long-break-label: "Long rest"; 21 20 in-out property <bool> enforced-mode: false; 22 21 in-out property <bool> idle-detection-enabled: true; ··· 126 125 Rectangle { height: 10px; } 127 126 } 128 127 128 + LongRestCard { 129 + index: root.levels.length + 1; 130 + enabled <=> root.long-break-enabled; 131 + after-cycles <=> root.long-break-after-cycles; 132 + duration-mins <=> root.long-break-duration-mins; 133 + label <=> root.long-break-label; 134 + } 135 + 136 + Rectangle { height: 10px; } 137 + 129 138 add-ta := TouchArea { 130 139 height: 44px * Theme.font-scale; 131 140 accessible-role: AccessibleRole.button; ··· 146 155 horizontal-alignment: center; 147 156 vertical-alignment: center; 148 157 animate color { duration: 120ms; } 149 - } 150 - } 151 - } 152 - 153 - Rectangle { height: 20px; } 154 - 155 - HorizontalLayout { 156 - spacing: 24px; 157 - 158 - SettingLabel { 159 - title: "Long rest"; 160 - description: "A longer pause after several cycles."; 161 - } 162 - 163 - Rectangle { horizontal-stretch: 1; } 164 - 165 - PaperToggle { 166 - checked <=> root.long-break-enabled; 167 - label: "Long rest"; 168 - } 169 - } 170 - 171 - if root.long-break-enabled: Rectangle { height: 12px; } 172 - 173 - if root.long-break-enabled: VerticalLayout { 174 - spacing: 0px; 175 - 176 - HorizontalLayout { 177 - spacing: 8px; 178 - alignment: start; 179 - 180 - Text { 181 - text: "after"; 182 - font-size: Theme.font_label; 183 - color: Theme.ink-mid; 184 - vertical-alignment: center; 185 - } 186 - 187 - NumberField { 188 - width: 80px; 189 - value <=> root.long-break-after-cycles; 190 - minimum: 2; 191 - maximum: 20; 192 - field-label: "cycles before long rest"; 193 - } 194 - 195 - Text { 196 - text: "cycles, take"; 197 - font-size: Theme.font_label; 198 - color: Theme.ink-mid; 199 - vertical-alignment: center; 200 - } 201 - 202 - NumberField { 203 - width: 80px; 204 - value <=> root.long-break-duration-mins; 205 - minimum: 1; 206 - maximum: 120; 207 - field-label: "long rest duration minutes"; 208 - } 209 - 210 - Text { 211 - text: "min"; 212 - font-size: Theme.font_label; 213 - color: Theme.ink-mid; 214 - vertical-alignment: center; 215 - } 216 - 217 - Text { 218 - text: "·"; 219 - font-size: Theme.font_label; 220 - color: Theme.ink-lo; 221 - vertical-alignment: center; 222 - } 223 - 224 - PaperInput { 225 - width: 110px; 226 - text <=> root.long-break-label; 227 - placeholder-text: "Long rest"; 228 - field-label: "long rest label"; 229 - } 230 - } 231 - 232 - Rectangle { height: 10px; } 233 - 234 - HorizontalLayout { 235 - spacing: 8px; 236 - alignment: start; 237 - 238 - Text { 239 - text: "Reset after"; 240 - font-size: Theme.font_xsmall; 241 - color: Theme.ink-mid; 242 - vertical-alignment: center; 243 - } 244 - 245 - NumberField { 246 - width: 80px; 247 - value <=> root.long-break-gap-mins; 248 - minimum: 1; 249 - maximum: 120; 250 - field-label: "idle reset threshold minutes"; 251 - } 252 - 253 - Text { 254 - text: "min away."; 255 - font-size: Theme.font_xsmall; 256 - color: Theme.ink-mid; 257 - vertical-alignment: center; 258 158 } 259 159 } 260 160 }