a lightweight, interval-based utility to combat digital strain through "Ma" (intentional pauses) for the eyes and body.
1import { Button, ProgressIndicator, LineEdit } from "std-widgets.slint";
2import { Theme } from "theme.slint";
3import "../assets/fonts/Nunito-Regular.ttf";
4import "../assets/fonts/Nunito-Medium.ttf";
5import "../assets/fonts/Nunito-SemiBold.ttf";
6import "../assets/fonts/Nunito-Bold.ttf";
7import "../assets/fonts/ShipporiMincho-Regular.ttf";
8import "../assets/fonts/ShipporiMincho-Bold.ttf";
9
10export component OverlayWindow inherits Window {
11 title: "ioma — break time";
12 no-frame: true;
13 always-on-top: true;
14
15 // Populated from Rust before showing.
16 in property <string> break-label: "Break time";
17 in property <string> countdown-text: "5:00";
18 in property <float> progress: 0.0; // 0.0 = start, 1.0 = done
19 in property <bool> snooze-visible: true;
20 in property <bool> is-dark: true;
21 in-out property <bool> unlock-input-visible: false;
22 in-out property <string> unlock-error: "";
23
24 callback snooze-clicked();
25 callback unlock-clicked();
26 callback unlock-submit-clicked(string /* password */);
27
28 init => { Theme.dark = root.is-dark; }
29 changed is-dark => { Theme.dark = root.is-dark; }
30
31 changed unlock-input-visible => {
32 if unlock-input-visible { pw-field.focus(); }
33 }
34
35 default-font-family: "Nunito";
36 background: Theme.bg;
37
38 VerticalLayout {
39 alignment: center;
40 spacing: 24px * Theme.font-scale;
41 padding: 48px * Theme.font-scale;
42
43 Text {
44 text: break-label;
45 font-family: "Shippori Mincho";
46 font-size: Theme.font_headline;
47 font-weight: 400;
48 color: Theme.ink-mid;
49 horizontal-alignment: center;
50 }
51
52 Text {
53 text: countdown-text;
54 font-family: "Shippori Mincho";
55 font-size: Theme.font_huge;
56 font-weight: 700;
57 color: Theme.ink;
58 horizontal-alignment: center;
59 }
60
61 HorizontalLayout {
62 alignment: center;
63
64 Rectangle {
65 height: 8px * Theme.font-scale;
66 width: 320px * Theme.font-scale;
67 background: Theme.progress-track;
68 border-radius: 4px * Theme.font-scale;
69
70 Rectangle {
71 x: 0;
72 width: parent.width * progress;
73 height: parent.height;
74 background: Theme.accent;
75 border-radius: 4px * Theme.font-scale;
76 }
77 }
78 }
79
80 HorizontalLayout {
81 alignment: center;
82 spacing: 16px * Theme.font-scale;
83
84 if snooze-visible : Button {
85 text: "Snooze once";
86 clicked => { root.snooze-clicked(); }
87 }
88
89 if !unlock-input-visible : Button {
90 text: "Unlock";
91 clicked => { root.unlock-clicked(); }
92 }
93 }
94
95 VerticalLayout {
96 visible: unlock-input-visible;
97 alignment: center;
98 spacing: 8px * Theme.font-scale;
99
100 HorizontalLayout {
101 alignment: center;
102 pw-field := LineEdit {
103 width: 260px * Theme.font-scale;
104 placeholder-text: "Emergency password";
105 input-type: password;
106 accepted => { root.unlock-submit-clicked(self.text); }
107 }
108 }
109
110 if unlock-error != "" : Text {
111 text: unlock-error;
112 color: #E55A4E;
113 font-size: Theme.font_body;
114 horizontal-alignment: center;
115 }
116
117 HorizontalLayout {
118 alignment: center;
119 spacing: 8px * Theme.font-scale;
120
121 Button {
122 text: "Cancel";
123 clicked => {
124 root.unlock-input-visible = false;
125 root.unlock-error = "";
126 pw-field.text = "";
127 }
128 }
129 Button {
130 text: "Submit";
131 clicked => { root.unlock-submit-clicked(pw-field.text); }
132 }
133 }
134 }
135 }
136}