Skip to content

Commit 1e2b291

Browse files
committed
refactor: Initial timer view (Vala)
1 parent 76cb4ee commit 1e2b291

File tree

7 files changed

+269
-3
lines changed

7 files changed

+269
-3
lines changed

data/resources/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
blueprints = custom_target ('blueprints',
33
input: files (
44
'ui/shortcuts_dialog.blp',
5+
'ui/timer_page.blp',
56
'ui/training_editor.blp',
67
'ui/training_list_row.blp',
78
'ui/window.blp',

data/resources/resources.gresource.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<gresources>
33
<gresource prefix="/xyz/safeworlds/hiit/">
44
<file compressed="true" preprocess="xml-stripblanks">ui/shortcuts_dialog.ui</file>
5+
<file compressed="true" preprocess="xml-stripblanks">ui/timer_page.ui</file>
56
<file compressed="true" preprocess="xml-stripblanks">ui/training_editor.ui</file>
67
<file compressed="true" preprocess="xml-stripblanks">ui/training_list_row.ui</file>
78
<file compressed="true" preprocess="xml-stripblanks">ui/window.ui</file>

data/resources/ui/timer_page.blp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using Gtk 4.0;
2+
using Adw 1;
3+
4+
template $ExerciseTimerTimerPage : Adw.NavigationPage {
5+
title: bind (template.Setup as <$ExerciseTimerTrainingSetup>).Title;
6+
Adw.ToolbarView {
7+
[top]
8+
Adw.HeaderBar {
9+
}
10+
11+
Adw.Clamp {
12+
orientation: horizontal;
13+
height-request: 250;
14+
valign: center;
15+
margin-top: 12;
16+
margin-bottom: 12;
17+
margin-start: 12;
18+
margin-end: 12;
19+
20+
Gtk.Box {
21+
orientation: vertical;
22+
spacing: 12;
23+
24+
Gtk.Box timer_card {
25+
css-classes: ["card"];
26+
orientation: vertical;
27+
valign: fill;
28+
vexpand: true;
29+
30+
Gtk.Box {
31+
orientation: vertical;
32+
valign: center;
33+
vexpand: true;
34+
35+
Gtk.Label {
36+
css-classes: ["timer-title"];
37+
label: bind template.StateFormatted;
38+
}
39+
40+
Gtk.Box timer_label_box {
41+
css-classes: ["timer-label"];
42+
orientation: horizontal;
43+
halign: center;
44+
45+
Gtk.Label {
46+
visible: bind finished_label.visible inverted;
47+
width-chars: 2;
48+
xalign: 1.0;
49+
label: bind template.RemainingMinFormatted;
50+
}
51+
Gtk.Label {
52+
visible: bind finished_label.visible inverted;
53+
width-chars: 1;
54+
label: "∶";
55+
}
56+
Gtk.Label {
57+
visible: bind finished_label.visible inverted;
58+
width-chars: 2;
59+
xalign: 0.0;
60+
label: bind template.RemainingSecFormatted;
61+
}
62+
Gtk.Label finished_label {
63+
visible: bind template.Finished;
64+
// Translators: Shown in the timer page when the training has come to the end
65+
label: _("Finished!");
66+
}
67+
}
68+
Gtk.Box {
69+
orientation: horizontal;
70+
halign: center;
71+
spacing: 12;
72+
73+
Gtk.Button {
74+
css-classes: ["circular", "large-button"];
75+
//TODO icon
76+
valign: center;
77+
// TODO huge button
78+
// Translators: tooltip text for the reset button
79+
tooltip-text: _("Restart Training");
80+
}
81+
Gtk.Button {
82+
css-classes: ["circular", "huge-button"];
83+
// TODO icon
84+
// TODO tooltip
85+
// TODO visible
86+
}
87+
Gtk.ScaleButton {
88+
css-classes: ["circular", "large-button"];
89+
//TODO icon
90+
valign: center;
91+
// Translators: tooltip text for the volume button
92+
tooltip-text: _("Set Volume");
93+
// TODO visible
94+
}
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
}

data/resources/ui/window.blp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ using Gtk 4.0;
22
using Adw 1;
33

44
template $ExerciseTimerWindow : Adw.ApplicationWindow {
5-
// Translators: This is the name of the window, shown e..g. in the application list. Currently this is the app name
5+
// Translators: This is the name of the window. Currently this is the app name
66
title: _("Exercise Timer");
77
default-width: 300;
88
default-height: 300;
99

1010
Adw.NavigationView navigation_view {
1111
Adw.NavigationPage {
12-
// Translators: This is the title of the page which lists all trainings. Currently this is the app name
13-
title: _("Exercise Timer");
12+
// Translators: This is the title of the page which lists all trainings
13+
title: _("Training List");
1414
Adw.ToolbarView {
1515
[top]
1616
Adw.HeaderBar {
@@ -42,6 +42,7 @@ template $ExerciseTimerWindow : Adw.ApplicationWindow {
4242
selection-mode: none;
4343
valign: start;
4444
css-classes: ["boxed-list"];
45+
row-activated => $on_training_activated();
4546
}
4647
}
4748
}

src/TimerPage.vala

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
namespace ExerciseTimer {
2+
[GtkTemplate(ui = "/xyz/safeworlds/hiit/ui/timer_page.ui")]
3+
public class TimerPage : Adw.NavigationPage {
4+
public TimerPage(TrainingSetup setup) {
5+
Setup = setup;
6+
remaining_sets = setup.Sets;
7+
if (setup.WarmupSec > 0) {
8+
current_state = State.Preparation;
9+
remaining_sec = setup.WarmupSec;
10+
} else {
11+
current_state = State.Exercise;
12+
remaining_sec = setup.ExerciseSec;
13+
}
14+
15+
var timer_id = GLib.Timeout.add(1000, onTimeout);
16+
this.hidden.connect((_) => {
17+
if (current_state != State.Finished) {
18+
GLib.Source.remove(timer_id);
19+
}
20+
});
21+
22+
notifyProperties();
23+
updateCssClass();
24+
timer_label_box.set_direction(Gtk.TextDirection.LTR);
25+
}
26+
27+
public TrainingSetup Setup { get; private set; }
28+
29+
public bool Finished {
30+
get {
31+
return current_state == State.Finished;
32+
}
33+
}
34+
35+
public string RemainingMinFormatted {
36+
owned get {
37+
var min = remaining_sec / 60;
38+
return "%02d".printf(min);
39+
}
40+
}
41+
42+
public string RemainingSecFormatted {
43+
owned get {
44+
var sec = remaining_sec % 60;
45+
return "%02d".printf(sec);
46+
}
47+
}
48+
49+
public string StateFormatted {
50+
owned get {
51+
switch (current_state) {
52+
case State.Preparation:
53+
// Translators: Shown on the timer page during preparation
54+
return _("Preparation");
55+
case State.Exercise:
56+
// Translators: Shown on the timer page during exercise
57+
return _("Exercise");
58+
case State.Rest:
59+
// Translators: Shown on the timer page during rest
60+
return _("Rest");
61+
case State.Finished:
62+
return "";
63+
default:
64+
assert_not_reached();
65+
}
66+
}
67+
}
68+
69+
private bool onTimeout() {
70+
bool retval;
71+
if (remaining_sec > 1) {
72+
--remaining_sec;
73+
retval = true;
74+
} else {
75+
switch (current_state) {
76+
case State.Preparation:
77+
current_state = State.Exercise;
78+
remaining_sec = Setup.ExerciseSec;
79+
retval = true;
80+
break;
81+
case State.Exercise:
82+
--remaining_sets;
83+
if (remaining_sets > 0) {
84+
current_state = State.Rest;
85+
remaining_sec = Setup.RestSec;
86+
retval = true;
87+
break;
88+
} else {
89+
current_state = State.Finished;
90+
retval = false;
91+
break;
92+
}
93+
case State.Rest:
94+
current_state = State.Exercise;
95+
remaining_sec = Setup.ExerciseSec;
96+
retval = true;
97+
break;
98+
default:
99+
assert_not_reached();
100+
}
101+
updateCssClass();
102+
}
103+
104+
notifyProperties();
105+
return retval;
106+
}
107+
108+
private void notifyProperties() {
109+
notify_property("RemainingMinFormatted");
110+
notify_property("RemainingSecFormatted");
111+
notify_property("StateFormatted");
112+
notify_property("Finished");
113+
}
114+
115+
private void updateCssClass() {
116+
var classes = new string[2];
117+
classes[0] = "card";
118+
switch (current_state) {
119+
case State.Preparation:
120+
classes[1] = "timer-warmup";
121+
break;
122+
case State.Exercise:
123+
case State.Finished:
124+
classes[1] = "timer-exercise";
125+
break;
126+
case State.Rest:
127+
classes[1] = "timer-rest";
128+
break;
129+
default:
130+
assert_not_reached();
131+
}
132+
timer_card.css_classes = classes;
133+
}
134+
135+
private enum State {
136+
Preparation,
137+
Exercise,
138+
Rest,
139+
Finished,
140+
}
141+
142+
[GtkChild]
143+
unowned Gtk.Box timer_card;
144+
[GtkChild]
145+
unowned Gtk.Box timer_label_box;
146+
147+
private State current_state;
148+
private int remaining_sec;
149+
private int remaining_sets;
150+
}
151+
}

src/Window.vala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,16 @@ namespace ExerciseTimer {
3434
}
3535
}
3636

37+
[GtkCallback]
38+
private void on_training_activated(Gtk.ListBoxRow row) {
39+
var training_list_row = row as TrainingListRow;
40+
var setup = training_list_row.Setup;
41+
var timer_page = new TimerPage(setup);
42+
navigation_view.push(timer_page);
43+
}
44+
45+
[GtkChild]
46+
private unowned Adw.NavigationView navigation_view;
3747
[GtkChild]
3848
private unowned Gtk.Stack training_list_stack;
3949
[GtkChild]

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ config_source = configure_file(
2626

2727
sources = [
2828
'Application.vala',
29+
'TimerPage.vala',
2930
'TrainingEditor.vala',
3031
'TrainingListRow.vala',
3132
'TrainingSetup.vala',

0 commit comments

Comments
 (0)