You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
5.5 KiB
135 lines
5.5 KiB
""" |
|
Leaderboard Screen |
|
Display global and device leaderboards with rankings and scores |
|
""" |
|
|
|
from .base_screen import BaseScreen |
|
|
|
|
|
class LeaderboardScreen(BaseScreen): |
|
"""Leaderboard display screen implementation""" |
|
|
|
def __init__(self, data_manager, ui_renderer, screen_manager): |
|
super().__init__(data_manager, ui_renderer, screen_manager) |
|
|
|
# Leaderboard state |
|
self.leaderboard_type = "device" # "device" or "global" |
|
self.leaderboard_data = [] |
|
|
|
def render(self) -> None: |
|
"""Render leaderboard screen""" |
|
title = f"{self.leaderboard_type.title()} Leaderboard" |
|
self.ui_renderer.draw_header(title) |
|
|
|
if not self.data_manager.api_enabled: |
|
self.ui_renderer.draw_text("Server offline - No leaderboard available", |
|
320, 150, 'red', 'medium', center=True) |
|
self.ui_renderer.draw_button("← Back", 270, 200, 100, 30, True) |
|
return |
|
|
|
# Controls |
|
toggle_text = f"Type: {self.leaderboard_type.title()} (Left/Right to toggle)" |
|
toggle_selected = (self.selected_index == 0) |
|
self.ui_renderer.draw_button(toggle_text, 120, 90, 400, 25, toggle_selected) |
|
|
|
refresh_selected = (self.selected_index == 1) |
|
back_selected = (self.selected_index == 2) |
|
self.ui_renderer.draw_button("Refresh", 150, 125, 80, 25, refresh_selected) |
|
self.ui_renderer.draw_button("← Back", 250, 125, 80, 25, back_selected) |
|
|
|
# Leaderboard data |
|
if not self.leaderboard_data: |
|
self.ui_renderer.draw_text("No leaderboard data available", 320, 200, |
|
'yellow', 'medium', center=True) |
|
else: |
|
self._render_leaderboard_data() |
|
|
|
self.ui_renderer.draw_footer_help(self.get_help_text()) |
|
|
|
def _render_leaderboard_data(self) -> None: |
|
"""Render the leaderboard data table""" |
|
# Draw leaderboard entries |
|
panel_height = min(250, len(self.leaderboard_data) * 25 + 40) |
|
self.ui_renderer.draw_panel(50, 160, 540, panel_height, 'black', 'gray') |
|
|
|
# Headers |
|
self.ui_renderer.draw_text("Rank", 60, 175, 'light_blue', 'small') |
|
self.ui_renderer.draw_text("Player", 120, 175, 'light_blue', 'small') |
|
self.ui_renderer.draw_text("Score", 350, 175, 'light_blue', 'small') |
|
self.ui_renderer.draw_text("Games", 450, 175, 'light_blue', 'small') |
|
|
|
if self.leaderboard_type == "global": |
|
self.ui_renderer.draw_text("Device", 520, 175, 'light_blue', 'small') |
|
|
|
# Entries |
|
for i, entry in enumerate(self.leaderboard_data): |
|
entry_y = 195 + i * 22 |
|
|
|
# Highlight current user |
|
is_current = (self.data_manager.active_profile and |
|
entry.get('user_id') == self.data_manager.active_profile) |
|
text_color = 'light_green' if is_current else 'light_gray' |
|
|
|
self.ui_renderer.draw_text(str(entry.get('rank', i+1)), 60, entry_y, text_color, 'tiny') |
|
|
|
player_name = entry.get('user_id', 'Unknown')[:20] |
|
self.ui_renderer.draw_text(player_name, 120, entry_y, text_color, 'tiny') |
|
|
|
self.ui_renderer.draw_text(str(entry.get('best_score', 0)), 350, entry_y, text_color, 'tiny') |
|
self.ui_renderer.draw_text(str(entry.get('total_games', 0)), 450, entry_y, text_color, 'tiny') |
|
|
|
if self.leaderboard_type == "global": |
|
device = entry.get('device_id', '')[:8] |
|
self.ui_renderer.draw_text(device, 520, entry_y, text_color, 'tiny') |
|
|
|
def handle_input(self, action: str) -> bool: |
|
"""Handle leaderboard input""" |
|
max_index = 2 # Toggle, Refresh, Back |
|
|
|
if action == 'up': |
|
self.navigate_up() |
|
return True |
|
elif action == 'down': |
|
self.navigate_down(max_index) |
|
return True |
|
elif action == 'left': |
|
if self.selected_index == 0: # Toggle leaderboard type |
|
self.toggle_leaderboard_type() |
|
return True |
|
elif action == 'right': |
|
if self.selected_index == 0: # Toggle leaderboard type |
|
self.toggle_leaderboard_type() |
|
return True |
|
elif action == 'confirm': |
|
self.handle_confirm() |
|
return True |
|
elif action == 'back': |
|
self.handle_back() |
|
return True |
|
|
|
return False |
|
|
|
def toggle_leaderboard_type(self) -> None: |
|
"""Toggle between device and global leaderboard""" |
|
self.leaderboard_type = "global" if self.leaderboard_type == "device" else "device" |
|
self.load_leaderboard_data() |
|
|
|
def handle_confirm(self) -> None: |
|
"""Handle leaderboard actions""" |
|
if self.selected_index == 1: # Refresh |
|
self.load_leaderboard_data() |
|
elif self.selected_index == 2: # Back |
|
self.handle_back() |
|
|
|
def load_leaderboard_data(self) -> None: |
|
"""Load leaderboard data from data manager""" |
|
self.leaderboard_data = self.data_manager.get_leaderboard_data(self.leaderboard_type) |
|
|
|
def reset_state(self) -> None: |
|
"""Reset screen state when entering""" |
|
super().reset_state() |
|
self.load_leaderboard_data() |
|
|
|
def get_help_text(self) -> str: |
|
"""Get help text for leaderboard""" |
|
return "Left/Right: Toggle Type • Enter: Select • Escape: Back"
|
|
|