ezgg-lan-manager/src/ezgg_lan_manager/pages/TournamentDetailsPage.py
2026-02-03 13:20:07 +01:00

224 lines
10 KiB
Python

from typing import Optional, Union, Literal
from from_root import from_root
from rio import Column, Component, event, TextStyle, Text, Row, Image, Spacer, ProgressCircle, Button, Checkbox, ThemeContextSwitcher, Link
from src.ezgg_lan_manager import ConfigurationService, TournamentService, UserService
from src.ezgg_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ezgg_lan_manager.components.TournamentDetailsInfoRow import TournamentDetailsInfoRow
from src.ezgg_lan_manager.types.DateUtil import weekday_to_display_text
from src.ezgg_lan_manager.types.SessionStorage import SessionStorage
from src.ezgg_lan_manager.types.Tournament import Tournament
from src.ezgg_lan_manager.types.TournamentBase import TournamentStatus, tournament_status_to_display_text, tournament_format_to_display_texts
from src.ezgg_lan_manager.types.User import User
class TournamentDetailsPage(Component):
tournament: Optional[Union[Tournament, str]] = None
rules_accepted: bool = False
user: Optional[User] = None
loading: bool = False
# State for message above register button
message: str = ""
is_success: bool = False
@event.on_populate
async def on_populate(self) -> None:
try:
tournament_id = int(self.session.active_page_url.query_string.split("id=")[-1])
except (ValueError, AttributeError, TypeError):
tournament_id = None
if tournament_id is not None:
self.tournament = await self.session[TournamentService].get_tournament_by_id(tournament_id)
if self.tournament is not None:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - {self.tournament.name}")
else:
await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Turniere")
self.user = await self.session[UserService].get_user(self.session[SessionStorage].user_id)
self.loading_done()
async def register_pressed(self) -> None:
self.loading = True
if not self.user:
return
try:
await self.session[TournamentService].register_user_for_tournament(self.user.user_id, self.tournament.id)
self.is_success = True
self.message = f"Erfolgreich angemeldet!"
except Exception as e:
self.is_success = False
self.message = f"Fehler: {e}"
self.loading = False
async def unregister_pressed(self) -> None:
self.loading = True
if not self.user:
return
try:
await self.session[TournamentService].unregister_user_from_tournament(self.user.user_id, self.tournament.id)
self.is_success = True
self.message = f"Erfolgreich abgemeldet!"
except Exception as e:
self.is_success = False
self.message = f"Fehler: {e}"
self.loading = False
async def tree_button_clicked(self) -> None:
pass # ToDo: Implement tournament tree view
def loading_done(self) -> None:
if self.tournament is None:
self.tournament = "Turnier konnte nicht gefunden werden"
self.session[SessionStorage].subscribe_to_logged_in_or_out_event(str(self.__class__), self.on_populate)
def build(self) -> Component:
if self.tournament is None:
content = Column(
ProgressCircle(
color="secondary",
align_x=0.5,
margin_top=0,
margin_bottom=0
),
min_height=10
)
elif isinstance(self.tournament, str):
content = Row(
Text(
text=self.tournament,
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1
),
margin_top=2,
margin_bottom=2,
align_x=0.5
)
)
else:
tournament_status_color = self.session.theme.background_color
tree_button = Spacer(grow_x=False, grow_y=False)
if self.tournament.status == TournamentStatus.OPEN:
tournament_status_color = self.session.theme.success_color
elif self.tournament.status == TournamentStatus.CLOSED:
tournament_status_color = self.session.theme.danger_color
elif self.tournament.status == TournamentStatus.ONGOING or self.tournament.status == TournamentStatus.COMPLETED:
tournament_status_color = self.session.theme.warning_color
tree_button = Button(
content="Turnierbaum anzeigen",
shape="rectangle",
style="minor",
color="hud",
margin_left=4,
margin_right=4,
margin_top=1,
on_press=self.tree_button_clicked
)
# ToDo: Integrate Teams logic
ids_of_participants = [p.id for p in self.tournament.participants]
color_key: Literal["hud", "danger"] = "hud"
on_press_function = self.register_pressed
if self.user and self.user.user_id in ids_of_participants: # User already registered for tournament
button_text = "Abmelden"
button_sensitive_hook = True # User has already accepted the rules previously
color_key = "danger"
on_press_function = self.unregister_pressed
elif self.user and self.user.user_id not in ids_of_participants:
button_text = "Anmelden"
button_sensitive_hook = self.rules_accepted
else:
# This should NEVER happen
button_text = "Anmelden"
button_sensitive_hook = False
if self.tournament.status != TournamentStatus.OPEN or self.tournament.is_full:
button_sensitive_hook = False # Override button controls if tournament is not open anymore or full
if self.user:
accept_rules_row = Row(
ThemeContextSwitcher(content=Checkbox(is_on=self.bind().rules_accepted, margin_left=4), color=self.session.theme.hud_color),
Text("Ich akzeptiere die ", margin_left=1, style=TextStyle(fill=self.session.theme.background_color, font_size=0.8), overflow="nowrap", justify="right"),
Link(Text("Turnierregeln", margin_right=4, style=TextStyle(fill=self.session.theme.background_color, font_size=0.8, italic=True), overflow="nowrap", justify="left"), "./tournament-rules", open_in_new_tab=True)
)
button = Button(
content=button_text,
shape="rectangle",
style="major",
color=color_key,
margin_left=2,
margin_right=2,
is_sensitive=button_sensitive_hook,
on_press=on_press_function,
is_loading=self.loading
)
else:
# No UI here if user not logged in
accept_rules_row, button = Spacer(), Spacer()
content = Column(
Row(
Image(image=from_root(f"src/ezgg_lan_manager/assets/img/games/{self.tournament.game_title.image_name}")),
Text(
text=self.tournament.name,
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1.2
),
margin_top=1,
margin_bottom=1,
align_x=0.5
),
margin_right=6,
margin_left=6
),
Spacer(min_height=1),
TournamentDetailsInfoRow("Status", tournament_status_to_display_text(self.tournament.status), tournament_status_color),
TournamentDetailsInfoRow("Startzeit", f"{weekday_to_display_text(self.tournament.start_time.weekday())}, {self.tournament.start_time.strftime('%H:%M')} Uhr"),
TournamentDetailsInfoRow("Format", tournament_format_to_display_texts(self.tournament.format)[0]),
TournamentDetailsInfoRow("Best of", tournament_format_to_display_texts(self.tournament.format)[1]),
TournamentDetailsInfoRow(
"Teilnehmer",
f"{len(self.tournament.participants)} / {self.tournament.max_participants}",
self.session.theme.danger_color if self.tournament.is_full else self.session.theme.background_color
),
tree_button,
Row(
Text(
text="Info",
style=TextStyle(
fill=self.session.theme.background_color,
font_size=1.2
),
margin_top=1,
margin_bottom=1,
align_x=0.5
)
),
# FixMe: Use rio.Markdown with correct TextStyle instead to allow basic text formatting from DB-side.
Text(self.tournament.description, margin_left=2, margin_right=2, style=TextStyle(fill=self.session.theme.background_color, font_size=1), overflow="wrap"),
Spacer(min_height=2),
accept_rules_row,
Spacer(min_height=0.5),
Text(self.message, margin_left=2, margin_right=2, style=TextStyle(fill=self.session.theme.success_color if self.is_success else self.session.theme.danger_color, font_size=1), overflow="wrap", justify="center"),
Spacer(min_height=0.5),
button
)
return Column(
MainViewContentBox(
Column(
Spacer(min_height=1),
content,
Spacer(min_height=1)
)
),
align_y=0
)