diff --git a/src/handlers/app.rs b/src/handlers/app.rs index 9613e43..a83cb3a 100644 --- a/src/handlers/app.rs +++ b/src/handlers/app.rs @@ -18,8 +18,9 @@ use crate::{ user_input::events::{Event, Key}, }, terminal::TerminalAction, + twitch::oauth::FollowingList, ui::{ - components::{utils::centered_rect, Component, Components}, + components::{Component, Components}, statics::LINE_BUFFER_CAPACITY, }, }; @@ -58,7 +59,7 @@ macro_rules! shared { } impl App { - pub fn new(config: CompleteConfig) -> Self { + pub fn new(config: CompleteConfig, following: FollowingList) -> Self { let shared_config = shared!(config.clone()); let shared_config_borrow = shared_config.borrow(); @@ -83,6 +84,7 @@ impl App { storage.clone(), filters.clone(), messages.clone(), + following, ); Self { @@ -124,11 +126,7 @@ impl App { } } - if self.components.following.is_focused() { - let rect = centered_rect(60, 60, 20, size); - - self.components.following.draw(f, rect, None); - } else if self.components.debug.is_focused() { + if self.components.debug.is_focused() { let new_rect = Rect::new(size.x, size.y + 1, size.width - 1, size.height - 2); let rect = Layout::default() @@ -144,8 +142,6 @@ impl App { if let Event::Input(key) = event { if self.components.debug.is_focused() { return self.components.debug.event(event); - } else if self.components.following.is_focused() { - return self.components.following.event(event); } match key { @@ -153,9 +149,6 @@ impl App { Key::Ctrl('d') => { self.components.debug.toggle_focus(); } - Key::Char('f') => { - self.components.following.toggle_focus(); - } _ => { return match self.state { State::Dashboard => self.components.dashboard.event(event), diff --git a/src/main.rs b/src/main.rs index 9cf1418..08e1ca9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ clippy::too_many_lines )] -use crate::emotes::graphics_protocol::get_terminal_cell_size; +use crate::{emotes::graphics_protocol::get_terminal_cell_size, twitch::oauth::get_following}; use clap::Parser; use color_eyre::eyre::{Result, WrapErr}; use log::{info, warn}; @@ -72,10 +72,9 @@ async fn main() -> Result<()> { let (terminal_tx, twitch_rx) = broadcast::channel(100); let (emotes_tx, emotes_rx) = mpsc::channel(1); - let mut app = App::new(config.clone()); + let following = get_following(&config.twitch.clone()).await; - // TODO: Move this into the following file. - app.components.following.get_following().await; + let mut app = App::new(config.clone(), following); info!("Started tokio communication channels."); diff --git a/src/twitch/oauth.rs b/src/twitch/oauth.rs index 2c7acf8..7bd4c28 100644 --- a/src/twitch/oauth.rs +++ b/src/twitch/oauth.rs @@ -5,6 +5,8 @@ use reqwest::{ }; use serde::Deserialize; +use crate::handlers::config::TwitchConfig; + #[derive(Deserialize)] #[allow(dead_code)] pub struct ClientId { @@ -112,3 +114,14 @@ pub async fn get_user_following(client: &Client, user_id: i32) -> FollowingList .await .unwrap() } + +pub async fn get_following(twitch_config: &TwitchConfig) -> FollowingList { + let oauth_token = twitch_config.token.clone(); + let app_user = twitch_config.username.clone(); + + let client = get_twitch_client(oauth_token).await.unwrap(); + + let user_id = get_channel_id(&client, &app_user).await.unwrap(); + + get_user_following(&client, user_id).await +} diff --git a/src/ui/components/chat.rs b/src/ui/components/chat.rs index 6874864..a2d6946 100644 --- a/src/ui/components/chat.rs +++ b/src/ui/components/chat.rs @@ -27,9 +27,10 @@ use crate::{ }, }, terminal::TerminalAction, + twitch::oauth::FollowingList, ui::components::{ - utils::centered_rect, ChannelSwitcherWidget, ChatInputWidget, Component, - MessageSearchWidget, + following::FollowingWidget, utils::centered_rect, ChannelSwitcherWidget, ChatInputWidget, + Component, MessageSearchWidget, }, utils::text::{title_line, TitleStyle}, }; @@ -40,6 +41,7 @@ pub struct ChatWidget { chat_input: ChatInputWidget, channel_input: ChannelSwitcherWidget, search_input: MessageSearchWidget, + following: FollowingWidget, filters: SharedFilters, pub scroll_offset: Scrolling, // theme: Theme, @@ -51,10 +53,12 @@ impl ChatWidget { messages: SharedMessages, storage: &SharedStorage, filters: SharedFilters, + following: FollowingList, ) -> Self { let chat_input = ChatInputWidget::new(config.clone(), storage.clone()); let channel_input = ChannelSwitcherWidget::new(config.clone(), storage.clone()); let search_input = MessageSearchWidget::new(config.clone()); + let following = FollowingWidget::new(config.clone(), following); let scroll_offset = Scrolling::new(config.borrow().frontend.inverted_scrolling); @@ -64,6 +68,7 @@ impl ChatWidget { chat_input, channel_input, search_input, + following, filters, scroll_offset, } @@ -328,6 +333,9 @@ impl Component for ChatWidget { } else if self.search_input.is_focused() { self.search_input .draw(f, v_chunks.next().copied().unwrap(), None); + } else if self.following.is_focused() { + self.following + .draw(f, centered_rect(60, 60, 20, f.size()), None); } } @@ -342,6 +350,8 @@ impl Component for ChatWidget { self.channel_input.event(event) } else if self.search_input.is_focused() { self.search_input.event(event) + } else if self.following.is_focused() { + self.following.event(event) } else { match key { Key::Char('i' | 'c') => self.chat_input.toggle_focus(), @@ -349,6 +359,7 @@ impl Component for ChatWidget { Key::Char('/') => self.chat_input.toggle_focus_with("/"), Key::Char('s') => self.channel_input.toggle_focus(), Key::Ctrl('f') => self.search_input.toggle_focus(), + Key::Char('f') => self.following.toggle_focus(), Key::Ctrl('t') => self.filters.borrow_mut().toggle(), Key::Ctrl('r') => self.filters.borrow_mut().reverse(), Key::Char('S') => return Some(TerminalAction::SwitchState(State::Dashboard)), diff --git a/src/ui/components/dashboard.rs b/src/ui/components/dashboard.rs index 8cd8871..5454e75 100644 --- a/src/ui/components/dashboard.rs +++ b/src/ui/components/dashboard.rs @@ -18,11 +18,13 @@ use crate::{ user_input::events::{Event, Key}, }, terminal::TerminalAction, - twitch::TwitchAction, + twitch::{oauth::FollowingList, TwitchAction}, ui::components::{utils::centered_rect, ChannelSwitcherWidget, Component}, utils::styles::DASHBOARD_TITLE_COLOR, }; +use super::following::FollowingWidget; + const DASHBOARD_TITLE: [&str; 5] = [ " __ _ __ __ __ _ ", " / /__ __(_) /______/ /_ / /___ __(_)", @@ -35,16 +37,23 @@ pub struct DashboardWidget { config: SharedCompleteConfig, storage: SharedStorage, channel_input: ChannelSwitcherWidget, + following: FollowingWidget, } impl DashboardWidget { - pub fn new(config: SharedCompleteConfig, storage: SharedStorage) -> Self { + pub fn new( + config: SharedCompleteConfig, + storage: SharedStorage, + following: FollowingList, + ) -> Self { let channel_input = ChannelSwitcherWidget::new(config.clone(), storage.clone()); + let following = FollowingWidget::new(config.clone(), following); Self { config, storage, channel_input, + following, } } @@ -215,6 +224,9 @@ impl Component for DashboardWidget { if self.channel_input.is_focused() { self.channel_input .draw(f, centered_rect(60, 20, 3, f.size()), emotes); + } else if self.following.is_focused() { + self.following + .draw(f, centered_rect(60, 60, 20, f.size()), None); } } @@ -222,12 +234,15 @@ impl Component for DashboardWidget { if let Event::Input(key) = event { if self.channel_input.is_focused() { return self.channel_input.event(event); + } else if self.following.is_focused() { + return self.following.event(event); } match key { Key::Ctrl('p') => panic!("Manual panic triggered by user."), Key::Char('q') => return Some(TerminalAction::Quit), Key::Char('s') => self.channel_input.toggle_focus(), + Key::Char('f') => self.following.toggle_focus(), Key::Enter => { let action = TerminalAction::Enter(TwitchAction::Join( self.config.borrow().twitch.channel.clone(), diff --git a/src/ui/components/following.rs b/src/ui/components/following.rs index d3c5041..c7becbf 100644 --- a/src/ui/components/following.rs +++ b/src/ui/components/following.rs @@ -16,10 +16,7 @@ use crate::{ user_input::events::{Event, Key}, }, terminal::TerminalAction, - twitch::{ - oauth::{get_channel_id, get_twitch_client, get_user_following, FollowingList}, - TwitchAction, - }, + twitch::{oauth::FollowingList, TwitchAction}, ui::{components::Component, statics::NAME_MAX_CHARACTERS}, utils::text::{title_line, TitleStyle}, }; @@ -33,11 +30,11 @@ pub struct FollowingWidget { } impl FollowingWidget { - pub fn new(config: SharedCompleteConfig) -> Self { + pub fn new(config: SharedCompleteConfig, following: FollowingList) -> Self { Self { config, focused: false, - following: FollowingList::default(), + following, state: TableState::default(), } } @@ -68,17 +65,6 @@ impl FollowingWidget { self.state.select(None); } - pub async fn get_following(&mut self) { - let oauth_token = self.config.borrow().twitch.token.clone(); - let app_user = self.config.borrow().twitch.username.clone(); - - let client = get_twitch_client(oauth_token).await.unwrap(); - - let user_id = get_channel_id(&client, &app_user).await.unwrap(); - - self.following = get_user_following(&client, user_id).await; - } - pub const fn is_focused(&self) -> bool { self.focused } diff --git a/src/ui/components/mod.rs b/src/ui/components/mod.rs index 14ae650..71e6fcb 100644 --- a/src/ui/components/mod.rs +++ b/src/ui/components/mod.rs @@ -33,10 +33,9 @@ use crate::{ user_input::events::{Event, Key}, }, terminal::TerminalAction, + twitch::oauth::FollowingList, }; -use self::following::FollowingWidget; - pub trait Component { #[allow(unused_variables)] fn draw(&mut self, f: &mut Frame, area: Rect, emotes: Option<&mut Emotes>) { @@ -61,7 +60,6 @@ pub struct Components { // Partial window widgets pub tabs: StateTabsWidget, pub debug: DebugWidget, - pub following: FollowingWidget, // Full window widgets pub chat: ChatWidget, @@ -76,14 +74,20 @@ impl Components { storage: SharedStorage, filters: SharedFilters, messages: SharedMessages, + following: FollowingList, ) -> Self { Self { tabs: StateTabsWidget::new(config.clone()), debug: DebugWidget::new(config.clone()), - following: FollowingWidget::new(config.clone()), - chat: ChatWidget::new(config.clone(), messages, &storage, filters), - dashboard: DashboardWidget::new(config.clone(), storage), + chat: ChatWidget::new( + config.clone(), + messages, + &storage, + filters, + following.clone(), + ), + dashboard: DashboardWidget::new(config.clone(), storage, following), help: HelpWidget::new(config.clone()), error: ErrorWidget::new(), }