summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimeon Simeonov2026-06-05 07:11:03 +0200
committerSimeon Simeonov2026-06-05 07:11:03 +0200
commit742fcdfabaeed8f9f70e14165cc9740f5b17d5a8 (patch)
tree7ac25ffe633cf6d36ead4e8cf2cce9f230936f6e /src
parent7b66519eb4ebe119e5fdc9c1eb6a11fdfab9b7bf (diff)
Add support for storing data permanently
Diffstat (limited to 'src')
-rw-r--r--src/scorecounter/__init__.py1
-rw-r--r--src/scorecounter/app.py109
2 files changed, 79 insertions, 31 deletions
diff --git a/src/scorecounter/__init__.py b/src/scorecounter/__init__.py
index e69de29..9bb96e2 100644
--- a/src/scorecounter/__init__.py
+++ b/src/scorecounter/__init__.py
@@ -0,0 +1 @@
"""scorecounter package"""
diff --git a/src/scorecounter/app.py b/src/scorecounter/app.py
index fecdf9d..124ae35 100644
--- a/src/scorecounter/app.py
+++ b/src/scorecounter/app.py
@@ -1,20 +1,31 @@
1"""Simple score counter for two teams""" 1"""Simple score counter for two teams"""
2 2
3import dataclasses
4import json
5
3import toga 6import toga
4from toga.colors import BLUE, RED, WHITE 7from toga.colors import BLUE, RED, WHITE
5from toga.constants import COLUMN, ROW 8from toga.constants import COLUMN, ROW
6 9
7 10
11@dataclasses.dataclass
12class ScoreCounterTeam:
13 """A dataclass that represents the state of a team"""
14
15 name: str
16 score: int
17
18 def to_dict(self) -> dict:
19 """Returns a dictionary representation of the object"""
20 return {'name': self.name, 'score': self.score}
21
22
8class ScoreCounter(toga.App): 23class ScoreCounter(toga.App):
9 """The main ScoreCounter application""" 24 """The main ScoreCounter application"""
10 25
11 def startup(self): 26 def startup(self) -> None:
12 """startup entry point""" 27 """startup entry point"""
13 self._score_team1 = 0 28 self._team1, self._team2 = self.load_teams()
14 self._score_team2 = 0
15
16 self._name_team1 = 'Team 1'
17 self._name_team2 = 'Team 2'
18 29
19 self.main_window = toga.MainWindow( 30 self.main_window = toga.MainWindow(
20 title=self.formal_name, on_resize=self.cb_main_window_resize 31 title=self.formal_name, on_resize=self.cb_main_window_resize
@@ -35,44 +46,48 @@ class ScoreCounter(toga.App):
35 46
36 self.main_window.show() 47 self.main_window.show()
37 48
38 def cb_clear(self, _widget): 49 def cb_clear(self, _widget: toga.Widget) -> None:
39 """Clear on press callback""" 50 """Clear on press callback"""
40 self._score_team1 = 0 51 self._team1.score = 0
41 self._score_team2 = 0 52 self._team2.score = 0
53 self.save()
42 self.refresh() 54 self.refresh()
43 55
44 def cb_score_team1(self, _widget): 56 def cb_score_team1(self, _widget: toga.Widget) -> None:
45 """Team1 on press callback""" 57 """Team1 on press callback"""
46 self._score_team1 += 1 58 self._team1.score += 1
59 self.save()
47 self.refresh() 60 self.refresh()
48 61
49 def cb_score_team2(self, _widget): 62 def cb_score_team2(self, _widget: toga.Widget) -> None:
50 """Team 2 on press callback""" 63 """Team 2 on press callback"""
51 self._score_team2 += 1 64 self._team2.score += 1
65 self.save()
52 self.refresh() 66 self.refresh()
53 67
54 def cb_main_window_resize(self, widget) -> None: 68 def cb_main_window_resize(self, widget: toga.Widget) -> None:
55 """On main window resize callback""" 69 """On main window resize callback"""
56 self._button_team1.style.height = int(widget.size.height / 5) 70 self._button_team1.style.height = int(widget.size.height / 5)
57 self._button_team2.style.height = int(widget.size.height / 5) 71 self._button_team2.style.height = int(widget.size.height / 5)
58 72
59 def cb_set(self, _widget): 73 def cb_set(self, _widget: toga.Widget) -> None:
60 """Set the settings callback""" 74 """Set the settings callback"""
61 self._name_team1 = self._input_team1.value 75 self._team1.name = self._input_team1.value
62 self._name_team2 = self._input_team2.value 76 self._team2.name = self._input_team2.value
77 self.save()
63 self.refresh() 78 self.refresh()
64 self._draw_main_view() 79 self._draw_main_view()
65 80
66 def cb_settings(self, _widget): 81 def cb_settings(self, _widget: toga.Widget) -> None:
67 """Create settings window menu""" 82 """Create settings window menu"""
68 self._input_team1 = toga.TextInput(flex=1, value=self._name_team1) 83 self._input_team1 = toga.TextInput(flex=1, value=self._team1.name)
69 box_team1 = toga.Box( 84 box_team1 = toga.Box(
70 direction=ROW, 85 direction=ROW,
71 margin=5, 86 margin=5,
72 children=[toga.Label('Team 1:', margin=5), self._input_team1], 87 children=[toga.Label('Team 1:', margin=5), self._input_team1],
73 ) 88 )
74 89
75 self._input_team2 = toga.TextInput(flex=1, value=self._name_team2) 90 self._input_team2 = toga.TextInput(flex=1, value=self._team2.name)
76 box_team2 = toga.Box( 91 box_team2 = toga.Box(
77 direction=ROW, 92 direction=ROW,
78 margin=5, 93 margin=5,
@@ -93,24 +108,56 @@ class ScoreCounter(toga.App):
93 children=[box_team1, box_team2, toga.Box(flex=1), button_box], 108 children=[box_team1, box_team2, toga.Box(flex=1), button_box],
94 ) 109 )
95 110
96 def refresh(self): 111 def load_teams(self) -> tuple[ScoreCounterTeam, ScoreCounterTeam]:
112 """
113 Loads the teams from config of config exists
114
115 Default teams are returned if config doesn't exist
116
117 :return: Tuple of 2 teams
118 :rtype: tuple
119 """
120 config_path = self.paths.config / 'scorecounter_config.json'
121
122 try:
123 with config_path.open('r', encoding='utf-8') as fp:
124 config_dict = json.load(fp)
125 return (
126 ScoreCounterTeam(**config_dict['team1']),
127 ScoreCounterTeam(**config_dict['team2']),
128 )
129 except Exception:
130 return (
131 ScoreCounterTeam(name='Team Red', score=0),
132 ScoreCounterTeam(name='Team Blue', score=0),
133 )
134
135 def refresh(self) -> None:
97 """Refreshes the score labels""" 136 """Refreshes the score labels"""
98 self._button_team1.text = f'{self._name_team1} (+1)' 137 self._button_team1.text = f'{self._team1.name} (+1)'
99 self._button_team2.text = f'{self._name_team2} (+1)' 138 self._button_team2.text = f'{self._team2.name} (+1)'
100 self._score_label1.text = f'{self._name_team1}: {self._score_team1}' 139 self._score_label1.text = f'{self._team1.name}: {self._team1.score}'
101 self._score_label2.text = f'{self._name_team2}: {self._score_team2}' 140 self._score_label2.text = f'{self._team2.name}: {self._team2.score}'
141
142 def save(self) -> None:
143 """Saves the teams to storage"""
144 data = {'team1': self._team1.to_dict(), 'team2': self._team2.to_dict()}
145
146 config_path = self.paths.config / 'scorecounter_config.json'
147 with config_path.open('w', encoding='utf-8') as fp:
148 json.dump(data, fp, indent=4)
102 149
103 def _draw_main_view(self): 150 def _draw_main_view(self) -> None:
104 """Draws the main view in the main window""" 151 """Draws the main view in the main window"""
105 self._score_label1 = toga.Label( 152 self._score_label1 = toga.Label(
106 f'{self._name_team1}: {self._score_team1}', 153 f'{self._team1.name}: {self._team1.score}',
107 margin=(0, 5), 154 margin=(0, 5),
108 color=RED, 155 color=RED,
109 font_weight='bold', 156 font_weight='bold',
110 font_size=24, 157 font_size=24,
111 ) 158 )
112 self._score_label2 = toga.Label( 159 self._score_label2 = toga.Label(
113 f'{self._name_team2}: {self._score_team2}', 160 f'{self._team2.name}: {self._team2.score}',
114 margin=(0, 5), 161 margin=(0, 5),
115 color=BLUE, 162 color=BLUE,
116 font_weight='bold', 163 font_weight='bold',
@@ -124,7 +171,7 @@ class ScoreCounter(toga.App):
124 ) 171 )
125 172
126 self._button_team1 = toga.Button( 173 self._button_team1 = toga.Button(
127 f'{self._name_team1} (+1)', 174 f'{self._team1.name} (+1)',
128 on_press=self.cb_score_team1, 175 on_press=self.cb_score_team1,
129 background_color=RED, 176 background_color=RED,
130 flex=1, 177 flex=1,
@@ -132,7 +179,7 @@ class ScoreCounter(toga.App):
132 color=WHITE, 179 color=WHITE,
133 ) 180 )
134 self._button_team2 = toga.Button( 181 self._button_team2 = toga.Button(
135 f'{self._name_team2} (+1)', 182 f'{self._team2.name} (+1)',
136 on_press=self.cb_score_team2, 183 on_press=self.cb_score_team2,
137 background_color=BLUE, 184 background_color=BLUE,
138 flex=1, 185 flex=1,
@@ -153,6 +200,6 @@ class ScoreCounter(toga.App):
153 self._button_team2.style.height = int(self.main_window.size.height / 5) 200 self._button_team2.style.height = int(self.main_window.size.height / 5)
154 201
155 202
156def main(): 203def main() -> ScoreCounter:
157 """main entry point""" 204 """main entry point"""
158 return ScoreCounter() 205 return ScoreCounter()