diff --git a/Cargo.lock b/Cargo.lock index e6ea356..26ca2e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1538,7 +1538,7 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tyt" -version = "1.2.1" +version = "1.3.0" dependencies = [ "alphanumeric-sort", "arboard", diff --git a/src/backend/core.rs b/src/backend/core.rs index 9ec3acb..ddb4fd0 100644 --- a/src/backend/core.rs +++ b/src/backend/core.rs @@ -1,7 +1,6 @@ use crate::{ backend::{ data::{channel::Channel, channel_list::ChannelList, video::Video}, - draw::draw, io::config::Config, io::{history::History, write_config, FileType::DbFile}, Action, @@ -12,10 +11,7 @@ use crate::{ }, notification::{notify_error, notify_open}, }; -use std::{ - process::{Command, Stdio}, - sync::mpsc::{channel, Receiver, Sender}, -}; +use std::process::{Command, Stdio}; #[derive(Clone, Debug)] pub enum FetchState { @@ -51,8 +47,6 @@ pub(crate) struct Core { pub(crate) current_screen: Screen, channel_list: ChannelList, pub(crate) playback_history: History, - pub(crate) status_sender: Sender, - pub(crate) status_receiver: Receiver, } impl Core { @@ -77,16 +71,12 @@ impl Core { let playback_history = History::load(); - let (status_sender, status_receiver) = channel(); - let core = Core { terminal, config, current_screen: Channels, channel_list, playback_history, - status_sender, - status_receiver, }; Ok(core) @@ -98,18 +88,10 @@ impl Core { } /// receive all status updates from status channel - pub(crate) fn update_status_line(&mut self) -> bool { - let mut changed = false; - - for item in self.status_receiver.try_iter() { - changed = true; - - if let Some(channel) = self.channel_list.get_unfiltered_mut_by_id(&item.text) { - channel.fetch_state = item.state.clone(); - } + pub(crate) fn update_status_line(&mut self, item: StateUpdate) { + if let Some(channel) = self.channel_list.get_unfiltered_mut_by_id(&item.text) { + channel.fetch_state = item.state.clone(); } - - changed } pub(crate) fn update_at_start(&self) -> bool { @@ -222,9 +204,9 @@ impl Core { }(); } - pub(crate) fn draw(&self) { - draw(self.into()); - } + // pub(crate) fn draw(&self) { + // draw(self.into()); + // } pub fn toggle_filter(&mut self) { self.channel_list.toggle_filter(); @@ -246,6 +228,10 @@ impl Core { &self.channel_list } + pub fn channel_list_mut(&mut self) -> &mut ChannelList { + &mut self.channel_list + } + pub(crate) fn get_selected_channel_index(&self) -> Option { self.channel_list.selected() } diff --git a/src/backend/data/channel/mod.rs b/src/backend/data/channel/mod.rs index 32b6b14..1b5ac8e 100644 --- a/src/backend/data/channel/mod.rs +++ b/src/backend/data/channel/mod.rs @@ -113,10 +113,15 @@ impl Channel { &self.tag } + #[allow(dead_code)] pub fn state(&self) -> ListState { self.list_state.clone() } + pub fn state_mut(&mut self) -> &mut ListState { + &mut self.list_state + } + pub fn push(&mut self, video: Video) { self.videos.push(video); } diff --git a/src/backend/data/channel_list.rs b/src/backend/data/channel_list.rs index bef9114..5b59dd6 100644 --- a/src/backend/data/channel_list.rs +++ b/src/backend/data/channel_list.rs @@ -99,8 +99,12 @@ impl ChannelList { self.list_state.selected() } - pub(crate) fn state(&self) -> ListState { - self.list_state.clone() + pub(crate) fn state(&self) -> &ListState { + &self.list_state + } + + pub(crate) fn state_mut(&mut self) -> &mut ListState { + &mut self.list_state } pub(crate) fn push(&mut self, channel: Channel) { diff --git a/src/backend/draw.rs b/src/backend/draw.rs index a632913..ca03054 100644 --- a/src/backend/draw.rs +++ b/src/backend/draw.rs @@ -1,12 +1,9 @@ use crate::backend::{ core::Core, - data::{channel::Channel, channel_list::ChannelList}, - io::{history::History, config::Config}, Screen, Screen::*, - Terminal, }; -use std::{thread, rc::Rc}; +use std::{thread, rc::Rc, sync::{RwLock, Arc}}; use tui::widgets::ListItem; use tui::{ layout::{Alignment, Constraint::*, Direction, Layout, Rect}, @@ -19,35 +16,6 @@ use tui::{ const INFO_LINE: &str = "q close; o open video/select; Enter/l select; Esc/h go back; m mark; M unmark"; -pub struct AppState { - channel: Option, - channel_list: ChannelList, - history: History, - screen: Screen, - terminal: Terminal, - config: Config, -} - -impl From<&Core> for AppState { - fn from(core: &Core) -> Self { - let channel = core.get_selected_channel().cloned(); - let channel_list = core.channel_list().clone(); - let history = core.playback_history.clone(); - let screen = core.current_screen.clone(); - let terminal = core.terminal.clone(); - let config = core.config.clone(); - - AppState { - channel, - channel_list, - history, - screen, - terminal, - config, - } - } -} - #[derive(Default)] struct Widget<'a> { title: String, @@ -139,44 +107,63 @@ impl AppLayout { } #[allow(clippy::unnecessary_unwrap)] -pub fn draw(app: AppState) { +pub fn draw(core: Arc>) { thread::spawn(move || { - let channels = app.channel_list.clone(); + let ( + channels, + current_screen, + app_title, + terminal, + history, + ) = { + let core_read_lock = core.read().unwrap(); + ( + core_read_lock.channel_list().clone(), + core_read_lock.current_screen.clone(), + core_read_lock.config.app_title.clone(), + core_read_lock.terminal.term.clone(), + core_read_lock.playback_history.clone(), + ) + }; - let channel_symbol = match app.screen { + let channel_symbol = match current_screen { Channels => ">> ", Videos => "-", }; let chan_widget = Widget::builder() - .with_title(&format!(" {} ", app.config.app_title)) + .with_title(&format!(" {} ", app_title)) .with_symbol(channel_symbol) .with_list(channels.get_spans_list()); - let _ = app.terminal.term.clone().lock().unwrap().draw(|f| { - let layout = AppLayout::load(f, &app.screen); - - f.render_stateful_widget( - chan_widget.render(), - layout.channels(), - &mut channels.state(), - ); + let _ = terminal.lock().unwrap().draw(|f| { + let layout = AppLayout::load(f, ¤t_screen); - if let Some(channel) = app.channel { - let video_widget = Widget::builder() - .with_title(&format!(" {} ", channel.name())) - .with_symbol(">> ") - .with_list(channel.get_spans_list()); + if let Ok(mut core_write_lock) = core.try_write() { f.render_stateful_widget( - video_widget.render(), - layout.videos(), - &mut channel.state(), + chan_widget.render(), + layout.channels(), + core_write_lock.channel_list_mut().state_mut(), ); + + if let Some(channel) = core_write_lock.get_selected_channel_mut() { + let c = channel.clone(); + let video_widget = Widget::builder() + .with_title(&format!(" {} ", channel.name())) + .with_symbol(">> ") + .with_list(c.get_spans_list()); + + f.render_stateful_widget( + video_widget.render(), + layout.videos(), + channel.state_mut(), + ); + } } let history_widget = Widget::builder() .with_title(" Playback History ") - .with_list(app.history.to_list_items()); + .with_list(history.to_list_items()); f.render_widget(history_widget.render(), layout.history()); diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 504eb05..644c442 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,7 +1,7 @@ pub(crate) mod core; pub(crate) mod data; -mod draw; +pub mod draw; pub(super) mod io; pub(super) mod dearrow; diff --git a/src/main.rs b/src/main.rs index 41a103b..5571934 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,10 @@ mod backend; mod events; -use crate::backend::{core::Core, data::Data, Action::*, Error, Screen::*}; +use std::sync::mpsc::channel; +use std::sync::{RwLock, Arc}; + +use crate::backend::{core::Core, draw::draw, data::Data, Action::*, Error, Screen::*}; use crate::notification::*; use arboard::Clipboard; use events::*; @@ -10,135 +13,158 @@ use termion::event::Key; mod notification; fn main() -> Result<(), Error> { - let mut core = match Core::load() { + let core = match Core::load() { Ok(core) => core, Err(error) => { return Err(error); } }; + let core = Arc::new(RwLock::new(core)); + let events = Events::new(); let mut tick_counter = 0; - let data = Data::init(core.status_sender.clone()); + let (status_sender, status_receiver) = channel(); + + let data = Data::init(status_sender); - if core.update_at_start() { - data.update(&core.config); + eprintln!("#"); + if core.read().unwrap().update_at_start() { + data.update(&core.read().unwrap().config); } + loop { + eprintln!("loop"); let event = events.next(); if let Ok(c) = data.try_recv() { - core.update_channel(c); - core.save(); + let core_write_lock = core.try_write(); + if let Ok(mut core) = core_write_lock { + core.update_channel(c); + core.save(); + } } - match event.unwrap() { - Event::Input(input) => match input { - Key::Char('q') => { - // ----------------- close ----------------------- - match core.get_current_screen() { - Channels => break, - Videos => { - core.action(Leave); - core.draw(); + let core_pointer = Arc::clone(&core); + let core_write_lock = core.write(); + + if let Ok(mut core) = core_write_lock { + match event.unwrap() { + Event::Input(input) => match input { + Key::Char('q') => { + // ----------------- close ----------------------- + match core.get_current_screen() { + Channels => break, + Videos => { + core.action(Leave); + draw(core_pointer); + } } } - } - Key::Esc | Key::Char('h') | Key::Left => { - // ---------------------- back -------------- - match core.get_current_screen() { - Channels => {} - Videos => { - core.action(Leave); + Key::Esc | Key::Char('h') | Key::Left => { + // ---------------------- back -------------- + match core.get_current_screen() { + Channels => {} + Videos => { + core.action(Leave); + } } + draw(core_pointer); } - core.draw(); - } - Key::Char('j') | Key::Down => { - // ---------------------- Down --------------------- - core.action(Down); - core.draw(); - } - Key::Char('k') | Key::Up => { - core.action(Up); - core.draw(); - } - Key::Char('n') => { - core.action(NextChannel); - core.draw(); - } - Key::Char('p') => { - core.action(PrevChannel); - core.draw(); - } - Key::Char('f') => { - match core.get_current_screen() { - Channels => {} - Videos => { - core.action(SetVideoFav); - } + Key::Char('j') | Key::Down => { + // ---------------------- Down --------------------- + core.action(Down); + draw(core_pointer); } - core.draw(); - } - Key::Char('\n') | Key::Char('l') | Key::Right | Key::Char('o') => { - match core.get_current_screen() { - Channels => { - core.action(Enter); - } - Videos => { - core.action(Open); + Key::Char('k') | Key::Up => { + core.action(Up); + draw(core_pointer); + } + Key::Char('n') => { + core.action(NextChannel); + draw(core_pointer); + } + Key::Char('p') => { + core.action(PrevChannel); + draw(core_pointer); + } + Key::Char('f') => { + match core.get_current_screen() { + Channels => {} + Videos => { + core.action(SetVideoFav); + } } + draw(core_pointer); } - core.draw(); - } - Key::Char('m') => { - core.action(Mark(true)); - core.draw(); - } - Key::Char('M') => { - core.action(Mark(false)); - core.draw(); - } - Key::Char('r') => { - /* update_channel_list(channel_update_sender.clone()); */ - data.update(&core.config); - core.action(Leave); - } - Key::Char('t') => { - // core.set_show_empty(!core.get_show_empty()); - core.toggle_filter(); - core.draw(); - } - Key::Char('c') => match core.get_current_screen() { - Channels => (), - Videos => { - let link = core.get_selected_video_link(); - notify_link(&link); - - let mut clipboard = Clipboard::new().unwrap(); - if let Err(err) = clipboard.set_text(link) { - notify_error(&format!("{:?}", err)); + Key::Char('\n') | Key::Char('l') | Key::Right | Key::Char('o') => { + match core.get_current_screen() { + Channels => { + core.action(Enter); + } + Videos => { + core.action(Open); + } } + draw(core_pointer); + } + Key::Char('m') => { + core.action(Mark(true)); + draw(core_pointer); } + Key::Char('M') => { + core.action(Mark(false)); + draw(core_pointer); + } + Key::Char('r') => { + /* update_channel_list(channel_update_sender.clone()); */ + data.update(&core.config); + core.action(Leave); + } + Key::Char('t') => { + // core.set_show_empty(!core.get_show_empty()); + core.toggle_filter(); + draw(core_pointer); + } + Key::Char('c') => match core.get_current_screen() { + Channels => (), + Videos => { + let link = core.get_selected_video_link(); + notify_link(&link); + + let mut clipboard = Clipboard::new().unwrap(); + if let Err(err) = clipboard.set_text(link) { + notify_error(&format!("{:?}", err)); + } + } + }, + _ => {} }, - _ => {} - }, - Event::Tick => { - if tick_counter == 0 { - let actually_updated = core.update_status_line(); - if actually_updated { - core.draw(); - tick_counter = 4; + Event::Tick => { + + let mut changed = false; + + if tick_counter == 0 { + + for item in status_receiver.try_iter() { + changed = true; + core.update_status_line(item) + } + + if changed { + tick_counter = 4; + } + + } else { + tick_counter -= 1 } - } else { - tick_counter -= 1 - } - if core.terminal.update_size() { - core.draw(); + if core.terminal.update_size() || changed { + draw(core_pointer); + } } } }