From b34269cdb5d32f8aa3322fe0afd5918f39de14f5 Mon Sep 17 00:00:00 2001 From: David Rodenkirchen Date: Thu, 12 Feb 2026 22:15:45 +0100 Subject: [PATCH] add basic UI for teams (end of day commit) --- src/ezgg_lan_manager/__init__.py | 6 +- .../components/TeamRevealer.py | 43 ++++++ src/ezgg_lan_manager/pages/TeamsPage.py | 122 +++++++++++++++++- .../services/DatabaseService.py | 25 +++- src/ezgg_lan_manager/services/TeamService.py | 4 +- 5 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 src/ezgg_lan_manager/components/TeamRevealer.py diff --git a/src/ezgg_lan_manager/__init__.py b/src/ezgg_lan_manager/__init__.py index f781029..b52831d 100644 --- a/src/ezgg_lan_manager/__init__.py +++ b/src/ezgg_lan_manager/__init__.py @@ -12,13 +12,14 @@ from src.ezgg_lan_manager.services.MailingService import MailingService from src.ezgg_lan_manager.services.NewsService import NewsService from src.ezgg_lan_manager.services.ReceiptPrintingService import ReceiptPrintingService from src.ezgg_lan_manager.services.SeatingService import SeatingService +from src.ezgg_lan_manager.services.TeamService import TeamService from src.ezgg_lan_manager.services.TicketingService import TicketingService from src.ezgg_lan_manager.services.TournamentService import TournamentService from src.ezgg_lan_manager.services.UserService import UserService from src.ezgg_lan_manager.types import * # Inits services in the correct order -def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService, ReceiptPrintingService, TournamentService]: +def init_services() -> tuple[AccountingService, CateringService, ConfigurationService, DatabaseService, MailingService, NewsService, SeatingService, TicketingService, UserService, LocalDataService, ReceiptPrintingService, TournamentService, TeamService]: logging.basicConfig(level=logging.DEBUG) configuration_service = ConfigurationService(from_root("config.toml")) db_service = DatabaseService(configuration_service.get_database_configuration()) @@ -32,6 +33,7 @@ def init_services() -> tuple[AccountingService, CateringService, ConfigurationSe catering_service = CateringService(db_service, accounting_service, user_service, receipt_printing_service) local_data_service = LocalDataService() tournament_service = TournamentService(db_service, user_service) + team_service = TeamService(db_service) - return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service, receipt_printing_service, tournament_service + return accounting_service, catering_service, configuration_service, db_service, mailing_service, news_service, seating_service, ticketing_service, user_service, local_data_service, receipt_printing_service, tournament_service, team_service diff --git a/src/ezgg_lan_manager/components/TeamRevealer.py b/src/ezgg_lan_manager/components/TeamRevealer.py new file mode 100644 index 0000000..c2f8126 --- /dev/null +++ b/src/ezgg_lan_manager/components/TeamRevealer.py @@ -0,0 +1,43 @@ +from functools import partial +from typing import Callable, Optional + +from rio import Component, Revealer, TextStyle, Column, Row, Tooltip, Icon, Spacer, Text, Button + +from src.ezgg_lan_manager.types.Team import TeamStatus, Team +from src.ezgg_lan_manager.types.User import User + + +class TeamRevealer(Component): + user: Optional[User] + team: Team + on_join_button_pressed: Callable + + def build(self) -> Component: + return Revealer( + header=self.team.name, + header_style=TextStyle( + fill=self.session.theme.background_color, + font_size=1 + ), + content=Column( + *[Row( + Tooltip( + anchor=Icon("material/star" if self.team.members[member] == TeamStatus.LEADER else "material/stat_1", fill=self.session.theme.hud_color), + tip="Leiter" if self.team.members[member] == TeamStatus.LEADER else "Mitglied", position="top"), + Text(member.user_name, style=TextStyle(fill=self.session.theme.background_color, font_size=1), margin_left=0.5), + Spacer(grow_y=False)) + for member in self.team.members + ], + Row(Button( + content=f"{self.team.name} beitreten", + shape="rectangle", + style="major", + color="hud", + on_press=partial(self.on_join_button_pressed, self.team), + ) if self.user not in self.team.members.keys() and self.user is not None else Spacer(grow_x=False, grow_y=False), margin_top=1, margin_bottom=1), + margin_right=1, + margin_left=1 + ), + margin_left=1, + margin_right=1, + ) diff --git a/src/ezgg_lan_manager/pages/TeamsPage.py b/src/ezgg_lan_manager/pages/TeamsPage.py index 89fd3be..b3e5ae0 100644 --- a/src/ezgg_lan_manager/pages/TeamsPage.py +++ b/src/ezgg_lan_manager/pages/TeamsPage.py @@ -1,17 +1,133 @@ -from rio import Column, Component, event, Text +from typing import Optional + +from rio import Column, Component, event, Text, TextStyle, ProgressCircle, Spacer, Revealer, Row, Button, Icon, Tooltip, Rectangle, PointerEventListener, PointerEvent from src.ezgg_lan_manager import ConfigurationService from src.ezgg_lan_manager.components.MainViewContentBox import MainViewContentBox -from src.ezgg_lan_manager.types.News import News +from src.ezgg_lan_manager.components.TeamRevealer import TeamRevealer +from src.ezgg_lan_manager.services.TeamService import TeamService +from src.ezgg_lan_manager.services.UserService import UserService +from src.ezgg_lan_manager.types.SessionStorage import SessionStorage +from src.ezgg_lan_manager.types.Team import Team +from src.ezgg_lan_manager.types.User import User class TeamsPage(Component): + all_teams: Optional[list[Team]] = None + user: Optional[User] = None + user_teams: list[Team] = [] + @event.on_populate async def on_populate(self) -> None: + self.all_teams = await self.session[TeamService].get_all_teams() + #self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id) + self.user = await self.session[UserService].get_user("Typhus") # FixMe: Only debug + if self.user is not None: + self.user_teams = await self.session[TeamService].get_teams_for_user_by_id(self.user.user_id) await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Teams") + self.session[SessionStorage].subscribe_to_logged_in_or_out_event(str(self.__class__), self.on_populate) + + async def on_join_button_pressed(self, team: Team) -> None: + # ToDo: handle joining by displaying password popup + print(f"Starting join process for team {team.abbreviation}") + + async def on_leave_button_pressed(self, team: Team) -> None: + # ToDo: handle leaving + print(f"Starting leaving process for team {team.abbreviation}") + + async def on_create_button_pressed(self, _: PointerEvent) -> None: + # ToDo: Add Popup creation dialog + print(f"Starting creation process for team") def build(self) -> Component: + if self.all_teams is None: + return Column( + MainViewContentBox( + ProgressCircle( + color="secondary", + align_x=0.5, + margin_top=1, + margin_bottom=1 + ) + ), + Spacer() + ) + + team_list = [] + for team in self.all_teams: + team_list.append(TeamRevealer(user=self.user, team=team, on_join_button_pressed=self.on_join_button_pressed)) + + if team_list: + team_list[-1].margin_bottom = 1 + + own_teams_content = Spacer(grow_x=False, grow_y=False) + if self.user is not None: + user_team_list = [] + for team in self.user_teams: + # ToDo: Remove from team instead of join + user_team_list.append(TeamRevealer(user=self.user, team=team, on_join_button_pressed=self.on_join_button_pressed)) + + if not user_team_list: + user_team_list.append(Text( + text="Du bist noch in keinem Team.", + style=TextStyle( + fill=self.session.theme.background_color, + font_size=1 + ), + margin_top=1, + margin_bottom=1, + align_x=0.5 + )) + else: + user_team_list[-1].margin_bottom = 1 + own_teams_content = MainViewContentBox( + Column( + Row( + Text( + text="Deine Teams", + style=TextStyle( + fill=self.session.theme.background_color, + font_size=1.2 + ), + grow_x=True, + justify="right", + margin_right=3 + ), + Column( + PointerEventListener(Rectangle( + content=Text(text="Team erstellen", style=TextStyle(fill=self.session.theme.background_color, font_size=0.7), margin=0.1, selectable=False), + stroke_width=0.1, + stroke_color=self.session.theme.hud_color, + cursor="pointer", + hover_fill=self.session.theme.hud_color, + transition_time=0 + ), on_press=self.on_create_button_pressed), + Spacer(), + margin_right=2 + ), + margin_top=1, + margin_bottom=1 + ), + *user_team_list + ) + ) + return Column( - MainViewContentBox(Text("Teams")), + own_teams_content, + MainViewContentBox( + Column( + Text( + text="Alle Teams", + style=TextStyle( + fill=self.session.theme.background_color, + font_size=1.2 + ), + margin_top=1, + margin_bottom=1, + align_x=0.5 + ), + *team_list + ) + ), align_y=0 ) diff --git a/src/ezgg_lan_manager/services/DatabaseService.py b/src/ezgg_lan_manager/services/DatabaseService.py index fa24411..14fb294 100644 --- a/src/ezgg_lan_manager/services/DatabaseService.py +++ b/src/ezgg_lan_manager/services/DatabaseService.py @@ -971,13 +971,32 @@ class DatabaseService: async def get_teams(self) -> list[Team]: # ToDo: Implement - return [] + return [ + Team( + id=1, + name="MockTeamAlpha", + abbreviation="-=MTA=-", + members={User(0, "DemoUserA", "", "abuvbwer", None, None, None, True, False, False, datetime.now(), datetime.now()): TeamStatus.LEADER}, + join_password="abc" + ), + Team( + id=1, + name="MockTeamBeta", + abbreviation="[MTB]", + members={ + User(1, "DemoUserB", "", "abuvbwer", None, None, None, True, False, False, datetime.now(), datetime.now()): TeamStatus.LEADER, + User(2, "DemoUserC", "", "abuvbwer", None, None, None, True, False, False, datetime.now(), datetime.now()): TeamStatus.OFFICER, + User(3, "DemoUserD", "", "abuvbwer", None, None, None, True, False, False, datetime.now(), datetime.now()): TeamStatus.MEMBER + }, + join_password="abc" + ) + ] async def get_team_by_id(self, team_id: int) -> Optional[Team]: return - async def get_team_for_user_by_id(self, user_id: int) -> Optional[Team]: - return + async def get_teams_for_user_by_id(self, user_id: int) -> list[Team]: + return [] async def create_team(self, team_name: str, team_abbr: str, join_password: str) -> Team: return # ToDo: Raise on existing team diff --git a/src/ezgg_lan_manager/services/TeamService.py b/src/ezgg_lan_manager/services/TeamService.py index 9c88f50..96e0194 100644 --- a/src/ezgg_lan_manager/services/TeamService.py +++ b/src/ezgg_lan_manager/services/TeamService.py @@ -36,8 +36,8 @@ class TeamService: async def get_team_by_id(self, team_id: int) -> Optional[Team]: return await self._db_service.get_team_by_id(team_id) - async def get_team_for_user_by_id(self, user_id: int) -> Optional[Team]: - return await self._db_service.get_team_for_user_by_id(user_id) + async def get_teams_for_user_by_id(self, user_id: int) -> list[Team]: + return await self._db_service.get_teams_for_user_by_id(user_id) async def create_team(self, team_name: str, team_abbr: str, join_password: str) -> Team: disallowed_char = self._check_for_disallowed_char(team_name)