diff --git a/src/application.rs b/src/application.rs new file mode 100644 index 0000000..d701a86 --- /dev/null +++ b/src/application.rs @@ -0,0 +1,80 @@ +use std::{path::PathBuf, sync::Arc}; + +use iced::{ + executor, + widget::{button, column, row, text, text_editor}, + Application, Command, Element, Theme, +}; + +use crate::{ + file::{default_file, load_file, pick_file}, + Error, +}; + +#[derive(Debug, Clone)] +pub enum Message { + Open, + Edit(text_editor::Action), + FileOpened(Result<(PathBuf, Arc), Error>), +} + +pub struct BookManagerApp { + book_path: Option, + book_content: text_editor::Content, + io_error: Option, +} + +impl Application for BookManagerApp { + type Executor = executor::Default; + type Flags = (); + type Message = Message; + type Theme = Theme; + + fn new(_flags: Self::Flags) -> (Self, Command) { + ( + Self { + book_path: None, + book_content: text_editor::Content::new(), + io_error: None, + }, + Command::perform(load_file(default_file()), Message::FileOpened), + ) + } + + fn title(&self) -> String { + String::from("Thief Book Manager") + } + + fn update(&mut self, message: Self::Message) -> Command { + match message { + Message::Edit(action) => self.book_content.perform(action), + Message::FileOpened(result) => match result { + Ok((path, content)) => { + self.book_content = text_editor::Content::with_text(&content); + self.book_path = Some(path); + } + Err(error) => self.io_error = Some(error), + }, + Message::Open => { + return Command::perform(pick_file(), Message::FileOpened); + } + } + + Command::none() + } + + fn view(&self) -> Element<'_, Self::Message> { + let hello_world = text("Hello, world!"); + let controls = row![button("Open").on_press(Message::Open)]; + let active_editor = text_editor(&self.book_content).on_action(Message::Edit); + + column![hello_world, controls, active_editor] + .spacing(10) + .padding(10) + .into() + } + + fn theme(&self) -> Theme { + Theme::Dark + } +} diff --git a/src/file.rs b/src/file.rs new file mode 100644 index 0000000..01796b4 --- /dev/null +++ b/src/file.rs @@ -0,0 +1,25 @@ +use std::{path::PathBuf, sync::Arc}; + +use crate::Error; + +pub async fn load_file(path: PathBuf) -> Result<(PathBuf, Arc), Error> { + let content = tokio::fs::read_to_string(&path) + .await + .map(Arc::new) + .map_err(|error| error.kind()) + .map_err(Error::IO)?; + Ok((path, content)) +} + +pub async fn pick_file() -> Result<(PathBuf, Arc), Error> { + let file_handle = rfd::AsyncFileDialog::new() + .set_title("Choose a file...") + .pick_file() + .await + .ok_or(Error::DialogClosed)?; + load_file(file_handle.path().to_owned()).await +} + +pub fn default_file() -> PathBuf { + PathBuf::from(format!("{}/src/main.rs", env!("CARGO_MANIFEST_DIR"))) +} diff --git a/src/main.rs b/src/main.rs index 6c07273..effbee3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,78 +1,10 @@ -use std::{io, path::PathBuf, sync::Arc}; +mod application; +mod file; -use iced::{ - executor, - widget::{button, column, row, text, text_editor}, - Application, Command, Element, Settings, Theme, -}; +use std::io; -#[derive(Debug, Clone)] -enum Message { - Open, - Edit(text_editor::Action), - FileOpened(Result<(PathBuf, Arc), Error>), -} - -struct BookManagerApp { - book_path: Option, - book_content: text_editor::Content, - io_error: Option, -} - -impl Application for BookManagerApp { - type Executor = executor::Default; - type Flags = (); - type Message = Message; - type Theme = Theme; - - fn new(_flags: Self::Flags) -> (Self, Command) { - ( - Self { - book_path: None, - book_content: text_editor::Content::new(), - io_error: None, - }, - Command::perform(load_file(default_file()), Message::FileOpened), - ) - } - - fn title(&self) -> String { - String::from("Thief Book Manager") - } - - fn update(&mut self, message: Self::Message) -> Command { - match message { - Message::Edit(action) => self.book_content.perform(action), - Message::FileOpened(result) => match result { - Ok((path, content)) => { - self.book_content = text_editor::Content::with_text(&content); - self.book_path = Some(path); - } - Err(error) => self.io_error = Some(error), - }, - Message::Open => { - return Command::perform(pick_file(), Message::FileOpened); - } - } - - Command::none() - } - - fn view(&self) -> Element<'_, Self::Message> { - let hello_world = text("Hello, world!"); - let controls = row![button("Open").on_press(Message::Open)]; - let active_editor = text_editor(&self.book_content).on_action(Message::Edit); - - column![hello_world, controls, active_editor] - .spacing(10) - .padding(10) - .into() - } - - fn theme(&self) -> Theme { - Theme::Dark - } -} +use application::BookManagerApp; +use iced::{Application, Settings}; fn main() -> iced::Result { BookManagerApp::run(Settings::default()) @@ -83,25 +15,3 @@ enum Error { DialogClosed, IO(io::ErrorKind), } - -async fn load_file(path: PathBuf) -> Result<(PathBuf, Arc), Error> { - let content = tokio::fs::read_to_string(&path) - .await - .map(Arc::new) - .map_err(|error| error.kind()) - .map_err(Error::IO)?; - Ok((path, content)) -} - -async fn pick_file() -> Result<(PathBuf, Arc), Error> { - let file_handle = rfd::AsyncFileDialog::new() - .set_title("Choose a file...") - .pick_file() - .await - .ok_or(Error::DialogClosed)?; - load_file(file_handle.path().to_owned()).await -} - -fn default_file() -> PathBuf { - PathBuf::from(format!("{}/src/main.rs", env!("CARGO_MANIFEST_DIR"))) -}