From 742fcdfabaeed8f9f70e14165cc9740f5b17d5a8 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Fri, 5 Jun 2026 07:11:03 +0200 Subject: Add support for storing data permanently --- src/scorecounter/__init__.py | 1 + src/scorecounter/app.py | 109 +++++++++++++++++++++++++++++++------------ 2 files changed, 79 insertions(+), 31 deletions(-) (limited to 'src') 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 @@ """Simple score counter for two teams""" +import dataclasses +import json + import toga from toga.colors import BLUE, RED, WHITE from toga.constants import COLUMN, ROW +@dataclasses.dataclass +class ScoreCounterTeam: + """A dataclass that represents the state of a team""" + + name: str + score: int + + def to_dict(self) -> dict: + """Returns a dictionary representation of the object""" + return {'name': self.name, 'score': self.score} + + class ScoreCounter(toga.App): """The main ScoreCounter application""" - def startup(self): + def startup(self) -> None: """startup entry point""" - self._score_team1 = 0 - self._score_team2 = 0 - - self._name_team1 = 'Team 1' - self._name_team2 = 'Team 2' + self._team1, self._team2 = self.load_teams() self.main_window = toga.MainWindow( title=self.formal_name, on_resize=self.cb_main_window_resize @@ -35,44 +46,48 @@ class ScoreCounter(toga.App): self.main_window.show() - def cb_clear(self, _widget): + def cb_clear(self, _widget: toga.Widget) -> None: """Clear on press callback""" - self._score_team1 = 0 - self._score_team2 = 0 + self._team1.score = 0 + self._team2.score = 0 + self.save() self.refresh() - def cb_score_team1(self, _widget): + def cb_score_team1(self, _widget: toga.Widget) -> None: """Team1 on press callback""" - self._score_team1 += 1 + self._team1.score += 1 + self.save() self.refresh() - def cb_score_team2(self, _widget): + def cb_score_team2(self, _widget: toga.Widget) -> None: """Team 2 on press callback""" - self._score_team2 += 1 + self._team2.score += 1 + self.save() self.refresh() - def cb_main_window_resize(self, widget) -> None: + def cb_main_window_resize(self, widget: toga.Widget) -> None: """On main window resize callback""" self._button_team1.style.height = int(widget.size.height / 5) self._button_team2.style.height = int(widget.size.height / 5) - def cb_set(self, _widget): + def cb_set(self, _widget: toga.Widget) -> None: """Set the settings callback""" - self._name_team1 = self._input_team1.value - self._name_team2 = self._input_team2.value + self._team1.name = self._input_team1.value + self._team2.name = self._input_team2.value + self.save() self.refresh() self._draw_main_view() - def cb_settings(self, _widget): + def cb_settings(self, _widget: toga.Widget) -> None: """Create settings window menu""" - self._input_team1 = toga.TextInput(flex=1, value=self._name_team1) + self._input_team1 = toga.TextInput(flex=1, value=self._team1.name) box_team1 = toga.Box( direction=ROW, margin=5, children=[toga.Label('Team 1:', margin=5), self._input_team1], ) - self._input_team2 = toga.TextInput(flex=1, value=self._name_team2) + self._input_team2 = toga.TextInput(flex=1, value=self._team2.name) box_team2 = toga.Box( direction=ROW, margin=5, @@ -93,24 +108,56 @@ class ScoreCounter(toga.App): children=[box_team1, box_team2, toga.Box(flex=1), button_box], ) - def refresh(self): + def load_teams(self) -> tuple[ScoreCounterTeam, ScoreCounterTeam]: + """ + Loads the teams from config of config exists + + Default teams are returned if config doesn't exist + + :return: Tuple of 2 teams + :rtype: tuple + """ + config_path = self.paths.config / 'scorecounter_config.json' + + try: + with config_path.open('r', encoding='utf-8') as fp: + config_dict = json.load(fp) + return ( + ScoreCounterTeam(**config_dict['team1']), + ScoreCounterTeam(**config_dict['team2']), + ) + except Exception: + return ( + ScoreCounterTeam(name='Team Red', score=0), + ScoreCounterTeam(name='Team Blue', score=0), + ) + + def refresh(self) -> None: """Refreshes the score labels""" - self._button_team1.text = f'{self._name_team1} (+1)' - self._button_team2.text = f'{self._name_team2} (+1)' - self._score_label1.text = f'{self._name_team1}: {self._score_team1}' - self._score_label2.text = f'{self._name_team2}: {self._score_team2}' + self._button_team1.text = f'{self._team1.name} (+1)' + self._button_team2.text = f'{self._team2.name} (+1)' + self._score_label1.text = f'{self._team1.name}: {self._team1.score}' + self._score_label2.text = f'{self._team2.name}: {self._team2.score}' + + def save(self) -> None: + """Saves the teams to storage""" + data = {'team1': self._team1.to_dict(), 'team2': self._team2.to_dict()} + + config_path = self.paths.config / 'scorecounter_config.json' + with config_path.open('w', encoding='utf-8') as fp: + json.dump(data, fp, indent=4) - def _draw_main_view(self): + def _draw_main_view(self) -> None: """Draws the main view in the main window""" self._score_label1 = toga.Label( - f'{self._name_team1}: {self._score_team1}', + f'{self._team1.name}: {self._team1.score}', margin=(0, 5), color=RED, font_weight='bold', font_size=24, ) self._score_label2 = toga.Label( - f'{self._name_team2}: {self._score_team2}', + f'{self._team2.name}: {self._team2.score}', margin=(0, 5), color=BLUE, font_weight='bold', @@ -124,7 +171,7 @@ class ScoreCounter(toga.App): ) self._button_team1 = toga.Button( - f'{self._name_team1} (+1)', + f'{self._team1.name} (+1)', on_press=self.cb_score_team1, background_color=RED, flex=1, @@ -132,7 +179,7 @@ class ScoreCounter(toga.App): color=WHITE, ) self._button_team2 = toga.Button( - f'{self._name_team2} (+1)', + f'{self._team2.name} (+1)', on_press=self.cb_score_team2, background_color=BLUE, flex=1, @@ -153,6 +200,6 @@ class ScoreCounter(toga.App): self._button_team2.style.height = int(self.main_window.size.height / 5) -def main(): +def main() -> ScoreCounter: """main entry point""" return ScoreCounter() -- cgit v1.3