Skip to content

Commit

Permalink
Refactor App
Browse files Browse the repository at this point in the history
  • Loading branch information
andschneider committed Apr 12, 2023
1 parent 1a51ab5 commit 4da1ec6
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 173 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

## [0.0.12]

### Changed

- Move API to be async and do api calls concurrently when possible: [Issue 13](https://github.com/mlb-rs/mlbt/issues/13)
- Switch from `tui-rs` to a new (maintained) fork `ratatui`. Thanks `tui-rs`!
- Update dependencies
- Update dependencies and refactor code a bit

### Fixed

- Getting stuck in help menu: [Issue 29](https://github.com/mlb-rs/mlbt/issues/29)

## [0.0.11] - 2022-04-13

Expand Down
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ better-panic = "0.3.0"
chrono = "0.4.24"
chrono-tz = "0.8.2"
crossterm = "0.26.1"
crossbeam-channel = "0.5.7"
crossbeam-channel = "0.5.8"
indexmap = "1.9.3"
mlb-api = { path = "api", version = "0.0.9" }
once_cell = "1.17.1"
Expand Down
2 changes: 1 addition & 1 deletion api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ serde_json = "1.0.95"
[dev-dependencies]
mockito = "1.0.2"
once_cell = "1.17.1"
tokio = { version = "1.26.0", features = ["macros"] }
tokio = { version = "1.27.0", features = ["macros"] }
103 changes: 63 additions & 40 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ use crate::live_game::GameState;
use crate::schedule::ScheduleState;
use crate::standings::StandingsState;
use crate::stats::StatsState;
use crossbeam_channel::{bounded, Receiver, Sender};
use mlb_api::client::{MLBApi, MLBApiBuilder};
use mlb_api::live::LiveResponse;

#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub enum MenuItem {
#[default]
Scoreboard,
Gameday,
Stats,
Expand All @@ -14,7 +17,37 @@ pub enum MenuItem {
DatePicker,
}

pub struct App {
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub enum DebugState {
On,
#[default]
Off,
}

/// A team must be either Home or Away.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub enum HomeOrAway {
#[default]
Home = 0,
Away = 1,
}

/// Get user input for the date and store whether it's valid.
pub struct DateInput {
pub is_valid: bool,
pub text: String,
}

/// Store which panels should be rendered in the Gameday tab.
#[derive(Debug, Copy, Clone)]
pub struct GamedayPanels {
pub info: bool,
pub at_bat: bool,
pub boxscore: bool,
}

#[derive(Default)]
pub struct AppState {
pub active_tab: MenuItem,
pub previous_tab: MenuItem,
pub debug_state: DebugState,
Expand All @@ -25,56 +58,54 @@ pub struct App {
pub boxscore_tab: HomeOrAway,
pub standings: StandingsState,
pub stats: StatsState,
}

pub struct App {
pub full_screen: bool,
// pub settings: AppSettings, // TODO
pub state: AppState,

pub client: MLBApi,
pub redraw_channel: (Sender<()>, Receiver<()>),
pub update_channel: (Sender<MenuItem>, Receiver<MenuItem>),
}

impl App {
pub fn new() -> Self {
Self {
state: AppState::default(),
full_screen: false,
client: MLBApiBuilder::default().build().unwrap(),
redraw_channel: bounded(1),
update_channel: bounded(1),
}
}
pub fn update_live_data(&mut self, live_data: &LiveResponse) {
self.live_game.update(live_data);
self.state.live_game.update(live_data);
}
pub fn update_tab(&mut self, next: MenuItem) {
if self.active_tab != next {
self.previous_tab = self.active_tab;
self.active_tab = next;
self.debug_state = DebugState::Off;
if self.state.active_tab != next {
self.state.previous_tab = self.state.active_tab;
self.state.active_tab = next;
self.state.debug_state = DebugState::Off;
}
}
pub fn exit_help(&mut self) {
if self.active_tab == MenuItem::Help {
self.active_tab = self.previous_tab;
if self.state.active_tab == MenuItem::Help {
self.state.active_tab = self.state.previous_tab;
}
}
pub fn toggle_debug(&mut self) {
match self.debug_state {
DebugState::Off => self.debug_state = DebugState::On,
DebugState::On => self.debug_state = DebugState::Off,
match self.state.debug_state {
DebugState::Off => self.state.debug_state = DebugState::On,
DebugState::On => self.state.debug_state = DebugState::Off,
}
}
pub fn toggle_full_screen(&mut self) {
self.full_screen = !self.full_screen;
}
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum DebugState {
On,
Off,
}

/// A team must be either Home or Away.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub enum HomeOrAway {
#[default]
Home = 0,
Away = 1,
}

/// Get user input for the date and store whether it's valid.
pub struct DateInput {
pub is_valid: bool,
pub text: String,
}

impl Default for DateInput {
fn default() -> Self {
DateInput {
Expand All @@ -84,14 +115,6 @@ impl Default for DateInput {
}
}

/// Store which panels should be rendered in the Gameday tab.
#[derive(Debug, Copy, Clone)]
pub struct GamedayPanels {
pub info: bool,
pub at_bat: bool,
pub boxscore: bool,
}

impl GamedayPanels {
/// Return the number of panels that are active.
pub fn count(&self) -> usize {
Expand Down
4 changes: 2 additions & 2 deletions src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ impl DebugInfo {
where
B: Backend,
{
self.game_id = app.schedule.get_selected_game();
self.game_id = app.state.schedule.get_selected_game();
self.gameday_url = format!("https://www.mlb.com/gameday/{}", self.game_id);
self.terminal_width = f.size().width;
self.terminal_height = f.size().height;
self.gameday_active_views = app.gameday;
self.gameday_active_views = app.state.gameday;
}
}
48 changes: 24 additions & 24 deletions src/draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ where
draw_tabs(f, &main_layout.top_bar, app);
}

match app.active_tab {
match app.state.active_tab {
MenuItem::Scoreboard => draw_scoreboard(f, main_layout.main, app),
MenuItem::DatePicker => {
draw_scoreboard(f, main_layout.main, app);
Expand All @@ -51,12 +51,12 @@ where
f.render_stateful_widget(
StandingsWidget {},
main_layout.main,
&mut app.standings,
&mut app.state.standings,
);
}
MenuItem::Help => draw_help(f, f.size()),
}
if app.debug_state == DebugState::On {
if app.state.debug_state == DebugState::On {
let mut dbi = DebugInfo::new();
dbi.gather_info(f, app);
dbi.render(f, main_layout.main)
Expand Down Expand Up @@ -89,7 +89,7 @@ where
.enumerate()
.map(|(i, t)| {
// underline the active tab
if i == app.active_tab as usize {
if i == app.state.active_tab as usize {
Spans::from(Span::styled(
*t,
Style::default().add_modifier(Modifier::UNDERLINED),
Expand Down Expand Up @@ -137,7 +137,7 @@ where
.split(rect);

// display scores on left side
f.render_stateful_widget(ScheduleWidget {}, chunks[0], &mut app.schedule);
f.render_stateful_widget(ScheduleWidget {}, chunks[0], &mut app.state.schedule);

// display line score and box score on right
draw_border(f, chunks[1], Color::White);
Expand All @@ -150,20 +150,20 @@ where
{
let chunks = LayoutAreas::for_boxscore(rect);

app.live_game.linescore.mini = true;
app.state.live_game.linescore.mini = true;
f.render_stateful_widget(
LineScoreWidget {
active: app.boxscore_tab,
active: app.state.boxscore_tab,
},
chunks[0],
&mut app.live_game.linescore,
&mut app.state.live_game.linescore,
);
f.render_stateful_widget(
TeamBatterBoxscoreWidget {
active: app.boxscore_tab,
active: app.state.boxscore_tab,
},
chunks[1],
&mut app.live_game.boxscore,
&mut app.state.live_game.boxscore,
);
}

Expand All @@ -189,10 +189,10 @@ where
let directions = Paragraph::new(" Press Enter to submit or Esc to cancel");
f.render_widget(directions, lines[1]);

let input = Paragraph::new(format!(" {}", app.date_input.text));
let input = Paragraph::new(format!(" {}", app.state.date_input.text));
f.render_widget(input, lines[2]);

let border = match app.date_input.is_valid {
let border = match app.state.date_input.is_valid {
true => Style::default().fg(Color::Blue),
false => Style::default().fg(Color::Red),
};
Expand All @@ -205,7 +205,7 @@ where

// display cursor
f.set_cursor(
lines[2].x + app.date_input.text.len() as u16 + 1,
lines[2].x + app.state.date_input.text.len() as u16 + 1,
lines[2].y,
)
}
Expand All @@ -214,26 +214,26 @@ fn draw_gameday<B>(f: &mut Frame<B>, rect: Rect, app: &mut App)
where
B: Backend,
{
let mut panels = LayoutAreas::generate_gameday_panels(&app.gameday, rect);
let mut panels = LayoutAreas::generate_gameday_panels(&app.state.gameday, rect);

// I want the panels to be displayed [Info, Heat, Box] from left to right. So pop off
// available panels starting with Box. Since `generate_layouts` takes into account how many
// panels are active, all the pops are guaranteed to unwrap.
if app.gameday.boxscore {
if app.state.gameday.boxscore {
let p = panels.pop().unwrap();
draw_border(f, p, Color::White);
draw_linescore_boxscore(f, p, app);
}
if app.gameday.at_bat {
if app.state.gameday.at_bat {
let p = panels.pop().unwrap();
draw_border(f, p, Color::White);
f.render_stateful_widget(AtBatWidget {}, p, &mut app.live_game.at_bat);
f.render_stateful_widget(AtBatWidget {}, p, &mut app.state.live_game.at_bat);
}
if app.gameday.info {
if app.state.gameday.info {
let p = panels.pop().unwrap();
draw_border(f, p, Color::White);
f.render_stateful_widget(MatchupWidget {}, p, &mut app.live_game.matchup);
f.render_stateful_widget(InningPlaysWidget {}, p, &mut app.live_game.plays);
f.render_stateful_widget(MatchupWidget {}, p, &mut app.state.live_game.matchup);
f.render_stateful_widget(InningPlaysWidget {}, p, &mut app.state.live_game.plays);
}
}

Expand All @@ -244,17 +244,17 @@ where
// TODO by taking into account the width of the options pane I'm basically removing that amount
// of space for columns. If I didn't, you could select columns that would be covered by the
// options pane, but then when its disabled would become visible.
let width = match app.stats.show_options {
let width = match app.state.stats.show_options {
true => rect.width - STATS_OPTIONS_WIDTH,
false => rect.width,
};
app.stats.trim_columns(width);
app.state.stats.trim_columns(width);
f.render_stateful_widget(
StatsWidget {
show_options: app.stats.show_options,
show_options: app.state.stats.show_options,
},
rect,
&mut app.stats,
&mut app.state.stats,
);
}

Expand Down
Loading

0 comments on commit 4da1ec6

Please sign in to comment.