diff --git a/AGENTS.md b/AGENTS.md index 003cacf..7651ae5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,7 @@ To ensure clean code structure and organization: - All new screens should be generated in their own file and cliss within the @app/screens/ directory. - Larger functionality requests should be broken down in reusable functions for single pieces of functionality. - When updating or adding functionality, ensure relevant usage information is added to the project README. +- This application uses a redis cache for data pulled from the MLB-StatsAPI library. If new functionality requires new data_service requests ensure these requests leverage the application caching strategy with reasonable TTLs. ## Testing Instructions - All changes MUST have their style verified. Use pylint as described in @.github/workflows/pylint.yml after making any code changes. Ensure tests are included in linting checks. diff --git a/app/widgets/animations.py b/app/widgets/animations.py index 794913d..a8d7986 100644 --- a/app/widgets/animations.py +++ b/app/widgets/animations.py @@ -6,8 +6,9 @@ from pytermgui.animations import Direction -# pylint: disable=too-many-arguments,too-many-positional-arguments -def slide_transition(window, manager, widgets, title, duration=290, on_finish=None): +# pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals +def slide_transition(window, manager, widgets, title, duration=290, on_finish=None, + new_width=None, new_height=None): """ Performs a slide-out and slide-in transition for a window. @@ -18,17 +19,21 @@ def slide_transition(window, manager, widgets, title, duration=290, on_finish=No title (str): The new title to set after sliding out. duration (int): Duration of each slide stage in milliseconds. on_finish (callable, optional): Callback to run when the entire transition finishes. + new_width (int, optional): The target width for the window. + new_height (int, optional): The target height for the window. """ - static_width = window.width - static_height = window.height + # Use provided dimensions or fallback to current ones + target_width = new_width if new_width is not None else window.width + target_height = new_height if new_height is not None else window.height - target_x = (manager.terminal.width - static_width) // 2 + # Calculate starting position for slide-in (centered) + final_target_x = (manager.terminal.width - target_width) // 2 _, start_y = window.pos off_screen_right = manager.terminal.width - def slide_step(anim, off_x): + def slide_step(anim, off_x, current_target_x): """Updates the window position based on animation state and off-screen target.""" - curr_x = int(target_x + (off_x - target_x) * anim.state) + curr_x = int(current_target_x + (off_x - current_target_x) * anim.state) window.pos = (curr_x, start_y) return False @@ -41,15 +46,15 @@ def on_slide_out_finish(_): """Updates window content and starts the slide-in animation using Direction.BACKWARD.""" window.set_widgets(widgets) window.set_title(title) - window.width = static_width - window.height = static_height + window.width = target_width + window.height = target_height window.styles.border = "green" window.styles.corner = "green" ptg.animator.animate_float( duration=duration, direction=Direction.BACKWARD, - on_step=lambda anim: slide_step(anim, off_screen_right), + on_step=lambda anim: slide_step(anim, off_screen_right, final_target_x), on_finish=on_slide_in_finish ) diff --git a/mlb_cli.py b/mlb_cli.py index f8a0068..f12b3a1 100644 --- a/mlb_cli.py +++ b/mlb_cli.py @@ -15,6 +15,11 @@ ) from app.widgets import CalendarWidget, slide_transition +# TODO: Consider making this dynamic as opposed to a hardcoded value. +# This value ensures a the initial calendar view is correct, assuming +# a 3 month view. +INITIAL_HEIGHT = 36 + class MLBApp: """ @@ -22,6 +27,8 @@ class MLBApp: """ # pylint: disable=too-many-instance-attributes + # pylint: disable=too-many-instance-attributes + def __init__(self): """Initializes the application state and UI components.""" fetch_teams() @@ -54,13 +61,19 @@ def set_window_data(self, widgets, title, page_name, on_finish=None): on_finish() return + # Calculate required height based on content + max_height = self.manager.terminal.height - 2 + temp_window = ptg.Window(*widgets, width=self.static_width) + temp_window.set_title(title) + target_height = min(max_height, temp_window.height) + self.active_page = page_name if not self.is_initialized: self.is_initialized = True self.main_window.set_widgets(widgets) self.main_window.set_title(title) self.main_window.width = self.static_width - self.main_window.height = self.static_height + self.main_window.height = target_height self.main_window.styles.border = "green" self.main_window.styles.corner = "green" self.main_window.center() @@ -68,7 +81,14 @@ def set_window_data(self, widgets, title, page_name, on_finish=None): on_finish() return - slide_transition(self.main_window, self.manager, widgets, title, on_finish=on_finish) + slide_transition( + self.main_window, + self.manager, + widgets, + title, + on_finish=on_finish, + new_height=target_height + ) def update_to_schedule(self, *_args, **_kwargs): """Transitions the main window to show the schedule for current_date.""" @@ -278,7 +298,7 @@ def exit_app(self, *_args, **_kwargs): def run(self): """Starts the application main loop.""" with self.manager: - self.static_height = min(50, self.manager.terminal.height - 2) + self.static_height = min(INITIAL_HEIGHT, self.manager.terminal.height - 2) self.main_window = ptg.Window( width=self.static_width, diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d032614 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.pylint.messages_control] +disable = ["fixme"] \ No newline at end of file diff --git a/tests/test_mlb_cli.py b/tests/test_mlb_cli.py index 126fd22..cfd7b56 100644 --- a/tests/test_mlb_cli.py +++ b/tests/test_mlb_cli.py @@ -18,6 +18,8 @@ def setUp(self): patch('mlb_cli.ptg.WindowManager') as mock_manager: self.app = MLBApp() self.app.manager = mock_manager.return_value + self.app.manager.terminal.width = 100 + self.app.manager.terminal.height = 40 self.app.main_window = MagicMock(spec=ptg.Window) self.app.main_window.__iter__.return_value = iter([])