Improve persistence in todos

This commit is contained in:
Héctor Ramón Jiménez 2019-11-18 00:13:18 +01:00
parent a803ab240b
commit 63dbf078fe

View File

@ -41,7 +41,10 @@ impl Application for Todos {
type Message = Message; type Message = Message;
fn new() -> (Todos, Command<Message>) { fn new() -> (Todos, Command<Message>) {
(Todos::Loading, Command::perform(load(), Message::Loaded)) (
Todos::Loading,
Command::perform(SavedState::load(), Message::Loaded),
)
} }
fn title(&self) -> String { fn title(&self) -> String {
@ -115,11 +118,12 @@ impl Application for Todos {
state.saving = true; state.saving = true;
Command::perform( Command::perform(
save(SavedState { SavedState {
input_value: state.input_value.clone(), input_value: state.input_value.clone(),
filter: state.filter, filter: state.filter,
tasks: state.tasks.clone(), tasks: state.tasks.clone(),
}), }
.save(),
Message::Saved, Message::Saved,
) )
} else { } else {
@ -483,41 +487,12 @@ struct SavedState {
tasks: Vec<Task>, tasks: Vec<Task>,
} }
fn save_path() -> std::path::PathBuf {
let mut path = if let Some(project_dirs) =
directories::ProjectDirs::from("rs", "Iced", "Todos")
{
project_dirs.data_dir().into()
} else {
std::env::current_dir()
.expect("The current directory is not accessible")
};
path.push("todos.json");
path
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum LoadError { enum LoadError {
FileError, FileError,
FormatError, FormatError,
} }
async fn load() -> Result<SavedState, LoadError> {
use std::io::Read;
let mut contents = String::new();
let mut file =
std::fs::File::open(save_path()).map_err(|_| LoadError::FileError)?;
file.read_to_string(&mut contents)
.map_err(|_| LoadError::FileError)?;
serde_json::from_str(&contents).map_err(|_| LoadError::FormatError)
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
enum SaveError { enum SaveError {
DirectoryError, DirectoryError,
@ -526,26 +501,57 @@ enum SaveError {
FormatError, FormatError,
} }
async fn save(state: SavedState) -> Result<(), SaveError> { impl SavedState {
use std::io::Write; fn path() -> std::path::PathBuf {
let mut path = if let Some(project_dirs) =
directories::ProjectDirs::from("rs", "Iced", "Todos")
{
project_dirs.data_dir().into()
} else {
std::env::current_dir()
.expect("The current directory is not accessible")
};
let json = serde_json::to_string_pretty(&state) path.push("todos.json");
.map_err(|_| SaveError::FormatError)?;
let save_path = save_path(); path
let save_dir = save_path.parent().ok_or(SaveError::DirectoryError)?; }
std::fs::create_dir_all(save_dir).map_err(|_| SaveError::DirectoryError)?; async fn load() -> Result<SavedState, LoadError> {
use std::io::Read;
let mut file = let mut contents = String::new();
std::fs::File::create(save_path).map_err(|_| SaveError::FileError)?;
file.write_all(json.as_bytes()) let mut file = std::fs::File::open(Self::path())
.map_err(|_| SaveError::WriteError)?; .map_err(|_| LoadError::FileError)?;
// This is a simple way to save at most once every couple seconds file.read_to_string(&mut contents)
// We will be able to get rid of it once we implement event subscriptions .map_err(|_| LoadError::FileError)?;
std::thread::sleep(std::time::Duration::from_secs(2));
Ok(()) serde_json::from_str(&contents).map_err(|_| LoadError::FormatError)
}
async fn save(self) -> Result<(), SaveError> {
use std::io::Write;
let json = serde_json::to_string_pretty(&self)
.map_err(|_| SaveError::FormatError)?;
let path = Self::path();
let dir = path.parent().ok_or(SaveError::DirectoryError)?;
std::fs::create_dir_all(dir).map_err(|_| SaveError::DirectoryError)?;
let mut file =
std::fs::File::create(path).map_err(|_| SaveError::FileError)?;
file.write_all(json.as_bytes())
.map_err(|_| SaveError::WriteError)?;
// This is a simple way to save at most once every couple seconds
// We will be able to get rid of it once we implement event subscriptions
std::thread::sleep(std::time::Duration::from_secs(2));
Ok(())
}
} }