use core::time::Duration; use iced::Subscription; use iced::Clipboard; use iced::Command; use iced::Application; use iced::Container; use iced::Row; use iced::Element; use iced::Length; use iced::Align; use iced::executor; use iced_futures::time; use iced_native::subscription; use iced_native::keyboard; use iced_native::event::Event; mod lyrics; mod styles; mod file_select; use styles::Theme; use file_select::FileSelector; #[derive(Clone, Debug)] pub struct DelyriumApp { lyrics_component: lyrics::Lyrics, theme: Theme, mode: AppMode, file_selector: file_select::FileSelector, } #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum AppMode { FileSelect, Main } #[derive(Clone, Debug)] pub enum Message { LyricChanged { line_no: usize, new_value: String, }, LineAdvanced(usize), PasteSent, Tick, } impl Application for DelyriumApp { type Message = Message; type Executor = executor::Default; type Flags = (); fn new(_: Self::Flags) -> (Self, Command) { ( DelyriumApp { lyrics_component: lyrics::Lyrics::new(), theme: Theme::default(), mode: AppMode::FileSelect, file_selector: FileSelector::default(), }, Command::none(), ) } fn title(&self) -> String { String::from("Delyrium") } fn update(&mut self, message: Message, clipboard: &mut Clipboard) -> Command{ match message { Message::LyricChanged { line_no, new_value } => { self.lyrics_component.update_line(new_value, line_no); }, Message::LineAdvanced(current_line) => { self.lyrics_component.advance_line(current_line); }, Message::PasteSent => { let clip_text = clipboard.read().unwrap_or(String::new()); let clip_pasted_len = clip_text.chars() .filter(|c| *c != '\r' && *c != '\n') .count(); let line = self.lyrics_component.current_line_mut().1; line.value.truncate(line.value.len() - clip_pasted_len); self.lyrics_component.insert_text(clip_text); }, Message::Tick => { match self.mode { AppMode::FileSelect => { self.file_selector.tick(); }, _ => { }, } } } Command::none() } fn view(&mut self) -> Element { match self.mode { AppMode::Main => { Container::new( Row::new() .push(self.lyrics_component.view(self.theme)) ) .align_y(Align::Center) .style(self.theme) .height(Length::Fill) .into() }, AppMode::FileSelect => { self.file_selector.view() } } } fn subscription(&self) -> Subscription { let runtime_events = subscription::events_with(|event, _| { match event { Event::Keyboard(keyboard::Event::KeyPressed {key_code, modifiers}) => { match (key_code, modifiers) { ( keyboard::KeyCode::V, keyboard::Modifiers { control, .. } ) if control == true => { Some(Message::PasteSent) } _ => { None } } } _ => { None } } }); let fps30 = time::every(Duration::from_millis(1000 / 30)).map(|_| Message::Tick); match self.mode { AppMode::FileSelect => { Subscription::batch([ runtime_events, fps30 ]) }, AppMode::Main => runtime_events, } } }