diff --git a/src/buffer.rs b/src/buffer.rs index 0bc113e2e..ca5f7a02c 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -1,4 +1,4 @@ -use data::{buffer, config, history}; +use data::{buffer, history}; use iced::Command; use self::channel::Channel; @@ -89,12 +89,9 @@ impl Buffer { history: &'a history::Manager, settings: &'a buffer::Settings, is_focused: bool, - load_config_error: &'a Option, ) -> Element<'a, Message> { match self { - Buffer::Empty(state) => { - empty::view(state, clients, load_config_error).map(Message::Empty) - } + Buffer::Empty(state) => empty::view(state, clients).map(Message::Empty), Buffer::Channel(state) => { channel::view(state, clients, history, settings, is_focused).map(Message::Channel) } diff --git a/src/buffer/empty.rs b/src/buffer/empty.rs index 2dba55b23..f1756bf07 100644 --- a/src/buffer/empty.rs +++ b/src/buffer/empty.rs @@ -1,6 +1,6 @@ use core::fmt; -use data::{config, Config}; +use data::Config; use iced::widget::{button, column, container, text, vertical_space}; use iced::{alignment, Length}; @@ -15,13 +15,7 @@ pub enum Message { #[derive(Debug, Clone)] pub enum Event {} -pub fn view<'a>( - _state: &Empty, - clients: &data::client::Map, - // TODO: Make error a separate screen so we don't - // have to pass this all the way down - load_config_error: &'a Option, -) -> Element<'a, Message> { +pub fn view<'a>(_state: &Empty, clients: &data::client::Map) -> Element<'a, Message> { let is_empty = clients.get_channels().is_empty(); let config_dir = is_empty .then(|| { @@ -31,14 +25,7 @@ pub fn view<'a>( }) .flatten(); - let error = load_config_error - .as_ref() - .map(|error| text(error.to_string()).style(theme::Text::Error)); - let title = if is_empty { - text("please create or edit config.yaml in the directory below") - } else { - text("you had me at halloy") - }; + let error = text("you had me at Halloy"); let action = config_dir.map(|path| { button(text(path)) @@ -46,8 +33,7 @@ pub fn view<'a>( .style(theme::Button::Default) }); let content = column![] - .push_maybe(error) - .push(title) + .push(error) .push(vertical_space(14)) .push_maybe(action) .align_items(iced::Alignment::Center); diff --git a/src/main.rs b/src/main.rs index 35fd386d6..24dc2aaf9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use data::config::{self, Config}; use data::stream; use iced::widget::container; use iced::{executor, Application, Command, Length, Subscription}; +use screen::{help, welcome}; use tokio::sync::mpsc; use self::event::{events, Event}; @@ -92,17 +93,19 @@ struct Halloy { config: Config, clients: data::client::Map, stream: Option>, - // TODO: Make this a different screen? - load_config_error: Option, } enum Screen { Dashboard(screen::Dashboard), + Help(screen::Help), + Welcome(screen::Welcome), } #[derive(Debug)] enum Message { Dashboard(dashboard::Message), + Help(help::Message), + Welcome(welcome::Message), Stream(stream::Result), Event(Event), FontsLoaded(Result<(), iced::font::Error>), @@ -115,11 +118,23 @@ impl Application for Halloy { type Theme = theme::Theme; fn new(_flags: ()) -> (Halloy, Command) { - let (config, load_config_error) = match Config::load() { + let (config, config_error) = match Config::load() { Ok(config) => (config, None), Err(error) => (Config::default(), Some(error)), }; - let (screen, command) = screen::Dashboard::new(&config); + + let (screen, command) = match config_error { + Some(error) => match &error { + config::Error::Parse(_) => { + (Screen::Welcome(screen::Welcome::new()), Command::none()) + } + _ => (Screen::Help(screen::Help::new(error)), Command::none()), + }, + None => { + let (screen, command) = screen::Dashboard::new(&config); + (Screen::Dashboard(screen), command) + } + }; let mut clients = data::client::Map::default(); @@ -133,12 +148,11 @@ impl Application for Halloy { ( Halloy { - screen: Screen::Dashboard(screen), + screen, theme: Theme::new_from_palette(config.palette), config, clients, stream: None, - load_config_error, }, Command::batch(vec![ font::load().map(Message::FontsLoaded), @@ -153,18 +167,36 @@ impl Application for Halloy { fn update(&mut self, message: Message) -> Command { match message { - Message::Dashboard(message) => match &mut self.screen { - Screen::Dashboard(dashboard) => { - let command = dashboard.update(message, &mut self.clients, &self.config); - // Retrack after dashboard state changes - let track = dashboard.track(); - - Command::batch(vec![ - command.map(Message::Dashboard), - track.map(Message::Dashboard), - ]) - } - }, + Message::Dashboard(message) => { + let Screen::Dashboard(dashboard) = &mut self.screen else { + return Command::none() + }; + + let command = dashboard.update(message, &mut self.clients, &self.config); + // Retrack after dashboard state changes + let track = dashboard.track(); + + Command::batch(vec![ + command.map(Message::Dashboard), + track.map(Message::Dashboard), + ]) + } + Message::Help(message) => { + let Screen::Help(help) = &mut self.screen else { + return Command::none(); + }; + + let _ = help.update(message); + Command::none() + } + Message::Welcome(message) => { + let Screen::Welcome(welcome) = &mut self.screen else { + return Command::none(); + }; + + let _ = welcome.update(message); + Command::none() + } Message::Stream(Ok(event)) => match event { stream::Event::Ready(sender) => { log::debug!("Client ready to receive connections"); @@ -186,13 +218,13 @@ impl Application for Halloy { Command::none() } stream::Event::MessagesReceived(messages) => { - let Screen::Dashboard(dashboard) = &mut self.screen; - - messages.into_iter().for_each(|(server, encoded)| { - if let Some(message) = self.clients.receive(&server, encoded) { - dashboard.record_message(&server, message); - } - }); + if let Screen::Dashboard(dashboard) = &mut self.screen { + messages.into_iter().for_each(|(server, encoded)| { + if let Some(message) = self.clients.receive(&server, encoded) { + dashboard.record_message(&server, message); + } + }); + } Command::none() } @@ -207,17 +239,20 @@ impl Application for Halloy { Command::none() } Message::Event(event) => { - let Screen::Dashboard(dashboard) = &mut self.screen; - dashboard.handle_event(event).map(Message::Dashboard) + if let Screen::Dashboard(dashboard) = &mut self.screen { + dashboard.handle_event(event).map(Message::Dashboard) + } else { + Command::none() + } } } } fn view(&self) -> Element { let content = match &self.screen { - Screen::Dashboard(dashboard) => dashboard - .view(&self.clients, &self.load_config_error) - .map(Message::Dashboard), + Screen::Dashboard(dashboard) => dashboard.view(&self.clients).map(Message::Dashboard), + Screen::Help(help) => help.view().map(Message::Help), + Screen::Welcome(welcome) => welcome.view().map(Message::Welcome), }; container(content) @@ -232,12 +267,16 @@ impl Application for Halloy { } fn subscription(&self) -> Subscription { - let Screen::Dashboard(dashboard) = &self.screen; + let screen_subscription = match &self.screen { + Screen::Dashboard(dashboard) => dashboard.subscription().map(Message::Dashboard), + Screen::Help(_) => Subscription::none(), + Screen::Welcome(_) => Subscription::none(), + }; Subscription::batch(vec![ events().map(Message::Event), client::run().map(Message::Stream), - dashboard.subscription().map(Message::Dashboard), + screen_subscription, ]) } } diff --git a/src/screen.rs b/src/screen.rs index 3e7d7342b..fff75a1e4 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1,3 +1,7 @@ pub mod dashboard; +pub mod help; +pub mod welcome; pub use dashboard::Dashboard; +pub use help::Help; +pub use welcome::Welcome; diff --git a/src/screen/dashboard.rs b/src/screen/dashboard.rs index 508b712b1..5019a18e1 100644 --- a/src/screen/dashboard.rs +++ b/src/screen/dashboard.rs @@ -1,7 +1,7 @@ pub mod pane; pub mod side_menu; -use data::{config, history, Config, Server}; +use data::{history, Config, Server}; use iced::widget::pane_grid::{self, PaneGrid}; use iced::widget::{container, row}; use iced::{clipboard, subscription, window, Command, Length, Subscription}; @@ -246,25 +246,13 @@ impl Dashboard { Command::none() } - pub fn view<'a>( - &'a self, - clients: &'a data::client::Map, - load_config_error: &'a Option, - ) -> Element<'a, Message> { + pub fn view<'a>(&'a self, clients: &'a data::client::Map) -> Element<'a, Message> { let focus = self.focus; let pane_grid: Element<_> = PaneGrid::new(&self.panes, |id, pane, maximized| { let is_focused = focus == Some(id); let panes = self.panes.len(); - pane.view( - id, - panes, - is_focused, - maximized, - clients, - &self.history, - load_config_error, - ) + pane.view(id, panes, is_focused, maximized, clients, &self.history) }) .on_click(pane::Message::PaneClicked) .on_resize(6, pane::Message::PaneResized) diff --git a/src/screen/dashboard/pane.rs b/src/screen/dashboard/pane.rs index f13908cb7..3784cfec0 100644 --- a/src/screen/dashboard/pane.rs +++ b/src/screen/dashboard/pane.rs @@ -1,4 +1,4 @@ -use data::{config, history, pane}; +use data::{history, pane}; use iced::widget::{button, container, pane_grid, row, text}; use iced::Length; use uuid::Uuid; @@ -48,7 +48,6 @@ impl Pane { maximized: bool, clients: &'a data::client::Map, history: &'a history::Manager, - load_config_error: &'a Option, ) -> widget::Content<'a, Message> { let title_bar_text = match &self.buffer { Buffer::Empty(state) => state.to_string(), @@ -69,13 +68,7 @@ impl Pane { let content = self .buffer - .view( - clients, - history, - &self.settings.buffer, - is_focused, - load_config_error, - ) + .view(clients, history, &self.settings.buffer, is_focused) .map(move |msg| Message::Buffer(id, msg)); widget::Content::new(content) diff --git a/src/screen/help.rs b/src/screen/help.rs new file mode 100644 index 000000000..a587bce41 --- /dev/null +++ b/src/screen/help.rs @@ -0,0 +1,39 @@ +use data::config; +use iced::widget::{column, container, text}; +use iced::{alignment, Length}; + +use crate::widget::Element; + +#[derive(Debug, Clone)] +pub enum Message {} + +#[derive(Debug, Clone)] +pub enum Event {} + +#[derive(Debug, Clone)] +pub struct Help { + error: config::Error, +} + +impl Help { + pub fn new(error: config::Error) -> Self { + Help { error } + } + + pub fn update(&mut self, _message: Message) -> Option { + None + } + + pub fn view<'a>(&self) -> Element<'a, Message> { + let content = column![] + .push(text("halloy help")) + .align_items(iced::Alignment::Center); + + container(content) + .align_x(alignment::Horizontal::Center) + .align_y(alignment::Vertical::Center) + .width(Length::Fill) + .height(Length::Fill) + .into() + } +} diff --git a/src/screen/welcome.rs b/src/screen/welcome.rs new file mode 100644 index 000000000..888df0a8d --- /dev/null +++ b/src/screen/welcome.rs @@ -0,0 +1,37 @@ +use data::config; +use iced::widget::{column, container, text}; +use iced::{alignment, Length}; + +use crate::widget::Element; + +#[derive(Debug, Clone)] +pub enum Message {} + +#[derive(Debug, Clone)] +pub enum Event {} + +#[derive(Debug, Clone)] +pub struct Welcome {} + +impl Welcome { + pub fn new() -> Self { + Welcome {} + } + + pub fn update(&mut self, _message: Message) -> Option { + None + } + + pub fn view<'a>(&self) -> Element<'a, Message> { + let content = column![] + .push(text("halloy welcome")) + .align_items(iced::Alignment::Center); + + container(content) + .align_x(alignment::Horizontal::Center) + .align_y(alignment::Vertical::Center) + .width(Length::Fill) + .height(Length::Fill) + .into() + } +}