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: swaps content between profile and rhythm tab

+368 -376
+15 -15
ui/settings.slint
··· 95 95 Rectangle { height: 1px; background: Theme.line; } 96 96 97 97 if root.active-tab == "rhythm": RhythmTab { 98 - enforced-mode <=> root.enforced-mode; 99 - sound-enabled <=> root.sound-enabled; 100 - sound-volume <=> root.sound-volume; 101 - autostart <=> root.autostart; 102 - idle-detection-enabled <=> root.idle-detection-enabled; 103 - idle-threshold-mins <=> root.idle-threshold-mins; 104 - theme-mode <=> root.theme-mode; 105 - text-size-mode <=> root.text-size-mode; 106 - set-password-clicked => { root.set-password-clicked(); } 107 - open-config-dir => { root.open-config-dir(); } 108 - theme-mode-changed(i) => { root.theme-mode-changed(i); } 109 - text-size-mode-changed(i) => { root.text-size-mode-changed(i); } 110 - } 111 - 112 - if root.active-tab == "profile": ProfileTab { 113 98 active-profile <=> root.active-profile; 114 99 profile-names: root.profile-names; 115 100 profile-name-widths: root.profile-name-widths; ··· 123 108 level-changed(i, entry) => { root.level-changed(i, entry); } 124 109 level-removed(i) => { root.level-removed(i); } 125 110 level-added => { root.level-added(); } 111 + } 112 + 113 + if root.active-tab == "profile": ProfileTab { 114 + enforced-mode <=> root.enforced-mode; 115 + sound-enabled <=> root.sound-enabled; 116 + sound-volume <=> root.sound-volume; 117 + autostart <=> root.autostart; 118 + idle-detection-enabled <=> root.idle-detection-enabled; 119 + idle-threshold-mins <=> root.idle-threshold-mins; 120 + theme-mode <=> root.theme-mode; 121 + text-size-mode <=> root.text-size-mode; 122 + set-password-clicked => { root.set-password-clicked(); } 123 + open-config-dir => { root.open-config-dir(); } 124 + theme-mode-changed(i) => { root.theme-mode-changed(i); } 125 + text-size-mode-changed(i) => { root.text-size-mode-changed(i); } 126 126 } 127 127 128 128 if root.active-tab == "about": AboutTab { }
+173 -179
ui/views/profile_tab.slint
··· 1 1 import { ScrollView } from "std-widgets.slint"; 2 2 import { Theme } from "../theme.slint"; 3 - import { SettingLabel } from "../components/atoms.slint"; 3 + import { SettingLabel, SectionHeading } from "../components/atoms.slint"; 4 + import { PaperButton } from "../components/buttons.slint"; 5 + import { NumberField, VolumeSlider, PaperComboBox } from "../components/inputs.slint"; 4 6 import { PaperToggle } from "../components/toggles.slint"; 5 - import { NumberField, PaperInput, PaperComboBox } from "../components/inputs.slint"; 6 - import { IntervalCard, LevelEntry } from "../components/interval_card.slint"; 7 - 8 - export { LevelEntry } 9 7 10 8 export component ProfileTab inherits ScrollView { 11 - in-out property <string> active-profile: ""; 12 - in property <[string]> profile-names; 13 - in property <[int]> profile-name-widths; 14 - in-out property <[LevelEntry]> levels; 15 - in-out property <bool> long-break-enabled: false; 16 - in-out property <int> long-break-after-cycles: 3; 17 - in-out property <int> long-break-duration-mins: 30; 18 - in-out property <int> long-break-gap-mins: 30; 19 - in-out property <string> long-break-label: "Long rest"; 20 - 21 - callback level-changed(int, LevelEntry); 22 - callback level-removed(int); 23 - callback level-added; 24 - callback profile-changed(string); 9 + in-out property <bool> enforced-mode: false; 10 + in-out property <bool> sound-enabled: true; 11 + in-out property <float> sound-volume: 0.7; 12 + in-out property <bool> autostart: false; 13 + in-out property <bool> idle-detection-enabled: true; 14 + in-out property <int> idle-threshold-mins: 5; 15 + in-out property <int> theme-mode: 0; 16 + in-out property <int> text-size-mode: 0; 25 17 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; 18 + callback set-password-clicked; 19 + callback open-config-dir; 20 + callback theme-mode-changed(int); 21 + callback text-size-mode-changed(int); 33 22 34 23 vertical-stretch: 1; 35 24 ··· 40 29 padding-bottom: 16px; 41 30 spacing: 0px; 42 31 43 - HorizontalLayout { 44 - padding-bottom: 14px; 45 - spacing: 24px; 32 + SectionHeading { 33 + title: "During breaks"; 34 + } 46 35 47 - SettingLabel { 48 - title: "Active profile"; 49 - } 36 + Rectangle { height: 12px; } 50 37 51 - Rectangle { horizontal-stretch: 1; } 38 + VerticalLayout { 39 + spacing: 0px; 52 40 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]); 60 - } 61 - } 62 - } 41 + HorizontalLayout { 42 + padding-top: 12px; 43 + padding-bottom: 4px; 44 + spacing: 24px; 63 45 64 - Rectangle { height: 16px; } 46 + SettingLabel { 47 + title: "Enforced mode"; 48 + description: "Full-screen break. Emergency unlock requires a password."; 49 + } 65 50 66 - Text { 67 - text: "Break cadence"; 68 - font-size: Theme.font_body; 69 - font-weight: 500; 70 - color: Theme.ink; 71 - } 51 + Rectangle { horizontal-stretch: 1; } 72 52 73 - Rectangle { height: 14px; } 53 + PaperToggle { 54 + checked <=> root.enforced-mode; 55 + label: "Enforced mode"; 56 + } 57 + } 74 58 75 - for level[i] in root.levels: VerticalLayout { 76 - spacing: 0px; 59 + HorizontalLayout { 60 + padding-bottom: 12px; 77 61 78 - IntervalCard { 79 - index: i + 1; 80 - work-mins: level.work-mins; 81 - break-mins: level.break-mins; 82 - break-secs: level.break-extra-secs; 83 - label: level.label; 84 - remove-clicked => { root.level-removed(i); } 85 - work-mins-changed(v) => { 86 - root.level-changed(i, { 87 - work-mins: v, 88 - break-mins: level.break-mins, 89 - break-extra-secs: level.break-extra-secs, 90 - label: level.label 91 - }); 92 - } 93 - break-mins-changed(v) => { 94 - root.level-changed(i, { 95 - work-mins: level.work-mins, 96 - break-mins: v, 97 - break-extra-secs: level.break-extra-secs, 98 - label: level.label 99 - }); 62 + PaperButton { 63 + text: "Set emergency unlock password…"; 64 + preferred-width: 220px; 65 + clicked => { root.set-password-clicked(); } 100 66 } 101 - break-secs-changed(v) => { 102 - root.level-changed(i, { 103 - work-mins: level.work-mins, 104 - break-mins: level.break-mins, 105 - break-extra-secs: v, 106 - label: level.label 107 - }); 67 + } 68 + 69 + HorizontalLayout { 70 + padding-top: 12px; 71 + padding-bottom: 4px; 72 + spacing: 24px; 73 + 74 + SettingLabel { 75 + title: "Pause on idle"; 76 + description: "If you've stepped away, ioma waits."; 108 77 } 109 - label-changed(v) => { 110 - root.level-changed(i, { 111 - work-mins: level.work-mins, 112 - break-mins: level.break-mins, 113 - break-extra-secs: level.break-extra-secs, 114 - label: v 115 - }); 78 + 79 + Rectangle { horizontal-stretch: 1; } 80 + 81 + PaperToggle { 82 + checked <=> root.idle-detection-enabled; 83 + label: "Pause on idle"; 116 84 } 117 85 } 118 86 119 - Rectangle { height: 10px; } 120 - } 87 + HorizontalLayout { 88 + padding-bottom: 12px; 89 + spacing: 10px; 90 + alignment: start; 121 91 122 - add-ta := TouchArea { 123 - height: 44px * Theme.font-scale; 124 - accessible-role: AccessibleRole.button; 125 - accessible-label: "Add interval"; 126 - accessible-action-default => { root.level-added(); } 127 - clicked => { root.level-added(); } 92 + Text { 93 + text: "for"; 94 + font-size: Theme.font_label; 95 + color: Theme.ink-mid; 96 + vertical-alignment: center; 97 + } 128 98 129 - Rectangle { 130 - border-radius: 8px; 131 - background: add-ta.has-hover ? Theme.surface-hov : transparent; 132 - border-width: 1px; 133 - border-color: Theme.line-med; 99 + NumberField { 100 + width: 80px; 101 + value <=> root.idle-threshold-mins; 102 + minimum: 1; 103 + maximum: 60; 104 + field-label: "Idle threshold minutes"; 105 + } 134 106 135 107 Text { 136 - text: "+ Add interval"; 137 - font-size: Theme.font_xsmall; 138 - color: add-ta.has-hover ? Theme.ink : Theme.ink-lo; 139 - horizontal-alignment: center; 108 + text: "minutes before resetting"; 109 + font-size: Theme.font_label; 110 + color: Theme.ink-mid; 140 111 vertical-alignment: center; 141 - animate color { duration: 120ms; } 142 112 } 143 113 } 144 114 } 145 115 146 - Rectangle { height: 20px; } 147 - 148 - HorizontalLayout { 149 - spacing: 24px; 116 + Rectangle { height: 28px; } 150 117 151 - SettingLabel { 152 - title: "Long rest"; 153 - description: "A longer pause after several cycles."; 154 - } 155 - 156 - Rectangle { horizontal-stretch: 1; } 157 - 158 - PaperToggle { 159 - checked <=> root.long-break-enabled; 160 - label: "Long rest"; 161 - } 118 + SectionHeading { 119 + title: "Sensory experience"; 162 120 } 163 121 164 122 Rectangle { height: 12px; } 165 123 166 124 VerticalLayout { 167 125 spacing: 0px; 168 - opacity: root.long-break-enabled ? 1.0 : 0.38; 169 - animate opacity { duration: 200ms; } 170 126 171 127 HorizontalLayout { 172 - spacing: 8px; 173 - alignment: start; 128 + padding-top: 12px; 129 + padding-bottom: 4px; 130 + spacing: 24px; 174 131 175 - Text { 176 - text: "after"; 177 - font-size: Theme.font_label; 178 - color: Theme.ink-mid; 179 - vertical-alignment: center; 132 + SettingLabel { 133 + title: "Chime on break start"; 180 134 } 181 135 182 - NumberField { 183 - width: 80px; 184 - enabled: root.long-break-enabled; 185 - value <=> root.long-break-after-cycles; 186 - minimum: 2; 187 - maximum: 20; 188 - field-label: "cycles before long rest"; 136 + Rectangle { horizontal-stretch: 1; } 137 + 138 + PaperToggle { 139 + checked <=> root.sound-enabled; 140 + label: "Chime on break start"; 189 141 } 142 + } 143 + 144 + HorizontalLayout { 145 + padding-bottom: 12px; 146 + spacing: 12px; 147 + alignment: center; 190 148 191 149 Text { 192 - text: "cycles, take"; 150 + text: "volume"; 193 151 font-size: Theme.font_label; 194 152 color: Theme.ink-mid; 195 153 vertical-alignment: center; 196 154 } 197 155 198 - NumberField { 199 - width: 80px; 200 - enabled: root.long-break-enabled; 201 - value <=> root.long-break-duration-mins; 202 - minimum: 1; 203 - maximum: 120; 204 - field-label: "long rest duration minutes"; 156 + VolumeSlider { 157 + value <=> root.sound-volume; 158 + horizontal-stretch: 1; 205 159 } 206 160 207 161 Text { 208 - text: "min"; 162 + text: "\{Math.round(root.sound-volume * 100)}%"; 163 + min-width: 44px; 209 164 font-size: Theme.font_label; 210 - color: Theme.ink-mid; 165 + font-weight: 600; 166 + color: Theme.ink; 167 + horizontal-alignment: right; 211 168 vertical-alignment: center; 212 169 } 170 + } 171 + 172 + HorizontalLayout { 173 + padding-top: 12px; 174 + padding-bottom: 10px; 175 + spacing: 24px; 213 176 214 - Text { 215 - text: "·"; 216 - font-size: Theme.font_label; 217 - color: Theme.ink-lo; 218 - vertical-alignment: center; 177 + SettingLabel { 178 + title: "Appearance"; 219 179 } 220 180 221 - PaperInput { 222 - width: 110px; 223 - enabled: root.long-break-enabled; 224 - text <=> root.long-break-label; 225 - placeholder-text: "Long rest"; 226 - field-label: "long rest label"; 181 + Rectangle { horizontal-stretch: 1; } 182 + 183 + PaperComboBox { 184 + model: ["System", "Light", "Dark"]; 185 + selected-index: root.theme-mode; 186 + field-label: "Appearance"; 187 + selection-changed(i) => { 188 + root.theme-mode = i; 189 + root.theme-mode-changed(i); 190 + } 227 191 } 228 192 } 229 - 230 - Rectangle { height: 10px; } 231 193 232 194 HorizontalLayout { 233 - spacing: 8px; 234 - alignment: start; 195 + padding-top: 12px; 196 + padding-bottom: 10px; 197 + spacing: 24px; 235 198 236 - Text { 237 - text: "Reset after"; 238 - font-size: Theme.font_xsmall; 239 - color: Theme.ink-mid; 240 - vertical-alignment: center; 199 + SettingLabel { 200 + title: "Text size"; 241 201 } 242 202 203 + Rectangle { horizontal-stretch: 1; } 204 + 243 205 NumberField { 244 - width: 80px; 245 - enabled: root.long-break-enabled; 246 - value <=> root.long-break-gap-mins; 247 - minimum: 1; 248 - maximum: 120; 249 - field-label: "idle reset threshold minutes"; 206 + width: 100px; 207 + value <=> root.text-size-mode; 208 + minimum: 0; 209 + maximum: 4; 210 + field-label: "Text size"; 211 + edited(v) => { root.text-size-mode-changed(v); } 250 212 } 213 + } 214 + } 215 + 216 + Rectangle { height: 28px; } 251 217 252 - Text { 253 - text: "min away."; 254 - font-size: Theme.font_xsmall; 255 - color: Theme.ink-mid; 256 - vertical-alignment: center; 218 + SectionHeading { 219 + title: "On this computer"; 220 + } 221 + 222 + Rectangle { height: 12px; } 223 + 224 + VerticalLayout { 225 + spacing: 0px; 226 + 227 + HorizontalLayout { 228 + padding-top: 12px; 229 + padding-bottom: 10px; 230 + spacing: 24px; 231 + 232 + SettingLabel { 233 + title: "Launch with system"; 234 + } 235 + 236 + Rectangle { horizontal-stretch: 1; } 237 + 238 + PaperToggle { 239 + checked <=> root.autostart; 240 + label: "Launch with system"; 241 + } 242 + } 243 + 244 + HorizontalLayout { 245 + padding-bottom: 12px; 246 + 247 + PaperButton { 248 + text: "Open config file location"; 249 + preferred-width: 180px; 250 + clicked => { root.open-config-dir(); } 257 251 } 258 252 } 259 253 }
+180 -182
ui/views/rhythm_tab.slint
··· 1 1 import { ScrollView } from "std-widgets.slint"; 2 2 import { Theme } from "../theme.slint"; 3 - import { SettingLabel, PaperDivider, SectionHeading } from "../components/atoms.slint"; 4 - import { PaperButton } from "../components/buttons.slint"; 5 - import { NumberField, VolumeSlider, PaperComboBox } from "../components/inputs.slint"; 3 + import { SettingLabel } from "../components/atoms.slint"; 6 4 import { PaperToggle } from "../components/toggles.slint"; 5 + import { NumberField, PaperInput, PaperComboBox } from "../components/inputs.slint"; 6 + import { IntervalCard, LevelEntry } from "../components/interval_card.slint"; 7 + 8 + export { LevelEntry } 7 9 8 10 export component RhythmTab inherits ScrollView { 9 - in-out property <bool> enforced-mode: false; 10 - in-out property <bool> sound-enabled: true; 11 - in-out property <float> sound-volume: 0.7; 12 - in-out property <bool> autostart: false; 13 - in-out property <bool> idle-detection-enabled: true; 14 - in-out property <int> idle-threshold-mins: 5; 15 - in-out property <int> theme-mode: 0; 16 - in-out property <int> text-size-mode: 0; 11 + in-out property <string> active-profile: ""; 12 + in property <[string]> profile-names; 13 + in property <[int]> profile-name-widths; 14 + in-out property <[LevelEntry]> levels; 15 + in-out property <bool> long-break-enabled: false; 16 + in-out property <int> long-break-after-cycles: 3; 17 + in-out property <int> long-break-duration-mins: 30; 18 + in-out property <int> long-break-gap-mins: 30; 19 + in-out property <string> long-break-label: "Long rest"; 17 20 18 - callback set-password-clicked; 19 - callback open-config-dir; 20 - callback theme-mode-changed(int); 21 - callback text-size-mode-changed(int); 21 + callback level-changed(int, LevelEntry); 22 + callback level-removed(int); 23 + callback level-added; 24 + callback profile-changed(string); 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; 22 33 23 34 vertical-stretch: 1; 24 35 ··· 29 40 padding-bottom: 16px; 30 41 spacing: 0px; 31 42 32 - SectionHeading { 33 - title: "During breaks"; 34 - } 43 + HorizontalLayout { 44 + padding-bottom: 14px; 45 + spacing: 24px; 35 46 36 - Rectangle { height: 12px; } 47 + SettingLabel { 48 + title: "Active profile"; 49 + } 37 50 38 - VerticalLayout { 39 - spacing: 0px; 51 + Rectangle { horizontal-stretch: 1; } 40 52 41 - HorizontalLayout { 42 - padding-top: 12px; 43 - padding-bottom: 4px; 44 - spacing: 24px; 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]); 60 + } 61 + } 62 + } 45 63 46 - SettingLabel { 47 - title: "Enforced mode"; 48 - description: "Full-screen break. Emergency unlock requires a password."; 49 - } 64 + Rectangle { height: 16px; } 50 65 51 - Rectangle { horizontal-stretch: 1; } 66 + Text { 67 + text: "Break cadence"; 68 + font-size: Theme.font_body; 69 + font-weight: 500; 70 + color: Theme.ink; 71 + } 52 72 53 - PaperToggle { 54 - checked <=> root.enforced-mode; 55 - label: "Enforced mode"; 56 - } 57 - } 73 + Rectangle { height: 14px; } 58 74 59 - HorizontalLayout { 60 - padding-bottom: 12px; 75 + for level[i] in root.levels: VerticalLayout { 76 + spacing: 0px; 61 77 62 - PaperButton { 63 - text: "Set emergency unlock password…"; 64 - preferred-width: 220px; 65 - clicked => { 66 - root.set-password-clicked(); 67 - } 78 + IntervalCard { 79 + index: i + 1; 80 + work-mins: level.work-mins; 81 + break-mins: level.break-mins; 82 + break-secs: level.break-extra-secs; 83 + label: level.label; 84 + remove-clicked => { root.level-removed(i); } 85 + work-mins-changed(v) => { 86 + root.level-changed(i, { 87 + work-mins: v, 88 + break-mins: level.break-mins, 89 + break-extra-secs: level.break-extra-secs, 90 + label: level.label 91 + }); 68 92 } 69 - } 70 - 71 - HorizontalLayout { 72 - padding-top: 12px; 73 - padding-bottom: 4px; 74 - spacing: 24px; 75 - 76 - SettingLabel { 77 - title: "Pause on idle"; 78 - description: "If you've stepped away, ioma waits."; 93 + break-mins-changed(v) => { 94 + root.level-changed(i, { 95 + work-mins: level.work-mins, 96 + break-mins: v, 97 + break-extra-secs: level.break-extra-secs, 98 + label: level.label 99 + }); 79 100 } 80 - 81 - Rectangle { horizontal-stretch: 1; } 82 - 83 - PaperToggle { 84 - checked <=> root.idle-detection-enabled; 85 - label: "Pause on idle"; 101 + break-secs-changed(v) => { 102 + root.level-changed(i, { 103 + work-mins: level.work-mins, 104 + break-mins: level.break-mins, 105 + break-extra-secs: v, 106 + label: level.label 107 + }); 108 + } 109 + label-changed(v) => { 110 + root.level-changed(i, { 111 + work-mins: level.work-mins, 112 + break-mins: level.break-mins, 113 + break-extra-secs: level.break-extra-secs, 114 + label: v 115 + }); 86 116 } 87 117 } 88 118 89 - HorizontalLayout { 90 - padding-bottom: 12px; 91 - spacing: 10px; 92 - alignment: start; 119 + Rectangle { height: 10px; } 120 + } 93 121 94 - Text { 95 - text: "for"; 96 - font-size: Theme.font_label; 97 - color: Theme.ink-mid; 98 - vertical-alignment: center; 99 - } 122 + add-ta := TouchArea { 123 + height: 44px * Theme.font-scale; 124 + accessible-role: AccessibleRole.button; 125 + accessible-label: "Add interval"; 126 + accessible-action-default => { root.level-added(); } 127 + clicked => { root.level-added(); } 100 128 101 - NumberField { 102 - width: 80px; 103 - value <=> root.idle-threshold-mins; 104 - minimum: 1; 105 - maximum: 60; 106 - field-label: "Idle threshold minutes"; 107 - } 129 + Rectangle { 130 + border-radius: 8px; 131 + background: add-ta.has-hover ? Theme.surface-hov : transparent; 132 + border-width: 1px; 133 + border-color: Theme.line-med; 108 134 109 135 Text { 110 - text: "minutes before resetting"; 111 - font-size: Theme.font_label; 112 - color: Theme.ink-mid; 136 + text: "+ Add interval"; 137 + font-size: Theme.font_xsmall; 138 + color: add-ta.has-hover ? Theme.ink : Theme.ink-lo; 139 + horizontal-alignment: center; 113 140 vertical-alignment: center; 141 + animate color { duration: 120ms; } 114 142 } 115 143 } 116 144 } 117 145 118 - Rectangle { height: 28px; } 146 + Rectangle { height: 20px; } 147 + 148 + HorizontalLayout { 149 + spacing: 24px; 150 + 151 + SettingLabel { 152 + title: "Long rest"; 153 + description: "A longer pause after several cycles."; 154 + } 119 155 120 - SectionHeading { 121 - title: "Sensory experience"; 156 + Rectangle { horizontal-stretch: 1; } 157 + 158 + PaperToggle { 159 + checked <=> root.long-break-enabled; 160 + label: "Long rest"; 161 + } 122 162 } 123 163 124 164 Rectangle { height: 12px; } 125 165 126 166 VerticalLayout { 127 167 spacing: 0px; 168 + opacity: root.long-break-enabled ? 1.0 : 0.38; 169 + animate opacity { duration: 200ms; } 128 170 129 171 HorizontalLayout { 130 - padding-top: 12px; 131 - padding-bottom: 4px; 132 - spacing: 24px; 172 + spacing: 8px; 173 + alignment: start; 133 174 134 - SettingLabel { 135 - title: "Chime on break start"; 175 + Text { 176 + text: "after"; 177 + font-size: Theme.font_label; 178 + color: Theme.ink-mid; 179 + vertical-alignment: center; 136 180 } 137 181 138 - Rectangle { horizontal-stretch: 1; } 139 - 140 - PaperToggle { 141 - checked <=> root.sound-enabled; 142 - label: "Chime on break start"; 182 + NumberField { 183 + width: 80px; 184 + enabled: root.long-break-enabled; 185 + value <=> root.long-break-after-cycles; 186 + minimum: 2; 187 + maximum: 20; 188 + field-label: "cycles before long rest"; 143 189 } 144 - } 145 - 146 - HorizontalLayout { 147 - padding-bottom: 12px; 148 - spacing: 12px; 149 - alignment: center; 150 190 151 191 Text { 152 - text: "volume"; 192 + text: "cycles, take"; 153 193 font-size: Theme.font_label; 154 194 color: Theme.ink-mid; 155 195 vertical-alignment: center; 156 196 } 157 197 158 - VolumeSlider { 159 - value <=> root.sound-volume; 160 - horizontal-stretch: 1; 198 + NumberField { 199 + width: 80px; 200 + enabled: root.long-break-enabled; 201 + value <=> root.long-break-duration-mins; 202 + minimum: 1; 203 + maximum: 120; 204 + field-label: "long rest duration minutes"; 161 205 } 162 206 163 207 Text { 164 - text: "\{Math.round(root.sound-volume * 100)}%"; 165 - min-width: 44px; 208 + text: "min"; 166 209 font-size: Theme.font_label; 167 - font-weight: 600; 168 - color: Theme.ink; 169 - horizontal-alignment: right; 210 + color: Theme.ink-mid; 170 211 vertical-alignment: center; 171 212 } 172 - } 173 - 174 - HorizontalLayout { 175 - padding-top: 12px; 176 - padding-bottom: 10px; 177 - spacing: 24px; 178 213 179 - SettingLabel { 180 - title: "Appearance"; 214 + Text { 215 + text: "·"; 216 + font-size: Theme.font_label; 217 + color: Theme.ink-lo; 218 + vertical-alignment: center; 181 219 } 182 220 183 - Rectangle { horizontal-stretch: 1; } 184 - 185 - PaperComboBox { 186 - model: ["System", "Light", "Dark"]; 187 - selected-index: root.theme-mode; 188 - field-label: "Appearance"; 189 - selection-changed(i) => { 190 - root.theme-mode = i; 191 - root.theme-mode-changed(i); 192 - } 221 + PaperInput { 222 + width: 110px; 223 + enabled: root.long-break-enabled; 224 + text <=> root.long-break-label; 225 + placeholder-text: "Long rest"; 226 + field-label: "long rest label"; 193 227 } 194 228 } 195 229 196 - HorizontalLayout { 197 - padding-top: 12px; 198 - padding-bottom: 10px; 199 - spacing: 24px; 200 - 201 - SettingLabel { 202 - title: "Text size"; 203 - } 204 - 205 - Rectangle { horizontal-stretch: 1; } 206 - 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); 215 - } 216 - } 217 - } 218 - } 219 - 220 - Rectangle { height: 28px; } 221 - 222 - SectionHeading { 223 - title: "On this computer"; 224 - } 225 - 226 - Rectangle { height: 12px; } 227 - 228 - VerticalLayout { 229 - spacing: 0px; 230 + Rectangle { height: 10px; } 230 231 231 232 HorizontalLayout { 232 - padding-top: 12px; 233 - padding-bottom: 10px; 234 - spacing: 24px; 233 + spacing: 8px; 234 + alignment: start; 235 235 236 - SettingLabel { 237 - title: "Launch with system"; 236 + Text { 237 + text: "Reset after"; 238 + font-size: Theme.font_xsmall; 239 + color: Theme.ink-mid; 240 + vertical-alignment: center; 238 241 } 239 242 240 - Rectangle { horizontal-stretch: 1; } 241 - 242 - PaperToggle { 243 - checked <=> root.autostart; 244 - label: "Launch with system"; 243 + NumberField { 244 + width: 80px; 245 + enabled: root.long-break-enabled; 246 + value <=> root.long-break-gap-mins; 247 + minimum: 1; 248 + maximum: 120; 249 + field-label: "idle reset threshold minutes"; 245 250 } 246 - } 247 251 248 - HorizontalLayout { 249 - padding-bottom: 12px; 250 - 251 - PaperButton { 252 - text: "Open config file location"; 253 - preferred-width: 180px; 254 - clicked => { 255 - root.open-config-dir(); 256 - } 252 + Text { 253 + text: "min away."; 254 + font-size: Theme.font_xsmall; 255 + color: Theme.ink-mid; 256 + vertical-alignment: center; 257 257 } 258 258 } 259 259 } 260 260 261 - Rectangle { 262 - vertical-stretch: 1; 263 - } 261 + Rectangle { vertical-stretch: 1; } 264 262 } 265 263 }