fixed lots of bugs by return Action enums in song_editor and library
Instead of dealing with a complication of every return from a component being a Task<Message>, I create an Action enum that only contains Tasks when needed and other specific actions that the overarching App should handle to interact with other parts of it.
This commit is contained in:
parent
e5981d006b
commit
66e33be26c
|
@ -71,7 +71,9 @@
|
||||||
];
|
];
|
||||||
in rec
|
in rec
|
||||||
{
|
{
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell.override {
|
||||||
|
stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.clangStdenv;
|
||||||
|
} {
|
||||||
nativeBuildInputs = nbi;
|
nativeBuildInputs = nbi;
|
||||||
buildInputs = bi;
|
buildInputs = bi;
|
||||||
LD_LIBRARY_PATH = "$LD_LIBRARY_PATH:${
|
LD_LIBRARY_PATH = "$LD_LIBRARY_PATH:${
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
use cosmic::dialog::ashpd::url::Url;
|
||||||
use crisp::types::{Keyword, Symbol, Value};
|
use crisp::types::{Keyword, Symbol, Value};
|
||||||
|
use iced_video_player::Video;
|
||||||
use miette::{miette, Result};
|
use miette::{miette, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
use tracing::{debug, error};
|
use tracing::error;
|
||||||
|
|
||||||
use super::songs::Song;
|
use super::songs::Song;
|
||||||
|
|
||||||
|
@ -49,6 +51,20 @@ pub struct Background {
|
||||||
pub kind: BackgroundKind,
|
pub kind: BackgroundKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Background> for Video {
|
||||||
|
type Error = ParseError;
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
value: Background,
|
||||||
|
) -> std::result::Result<Self, Self::Error> {
|
||||||
|
Video::new(
|
||||||
|
&Url::from_file_path(value.path)
|
||||||
|
.map_err(|_| ParseError::BackgroundNotVideo)?,
|
||||||
|
)
|
||||||
|
.map_err(|_| ParseError::BackgroundNotVideo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for Background {
|
impl TryFrom<String> for Background {
|
||||||
type Error = ParseError;
|
type Error = ParseError;
|
||||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||||
|
@ -137,6 +153,7 @@ pub enum ParseError {
|
||||||
NonBackgroundFile,
|
NonBackgroundFile,
|
||||||
DoesNotExist,
|
DoesNotExist,
|
||||||
CannotCanonicalize,
|
CannotCanonicalize,
|
||||||
|
BackgroundNotVideo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for ParseError {}
|
impl std::error::Error for ParseError {}
|
||||||
|
@ -154,6 +171,9 @@ impl Display for ParseError {
|
||||||
Self::CannotCanonicalize => {
|
Self::CannotCanonicalize => {
|
||||||
"Could not canonicalize this file"
|
"Could not canonicalize this file"
|
||||||
}
|
}
|
||||||
|
Self::BackgroundNotVideo => {
|
||||||
|
"This background isn't a video"
|
||||||
|
}
|
||||||
};
|
};
|
||||||
write!(f, "Error: {message}")
|
write!(f, "Error: {message}")
|
||||||
}
|
}
|
||||||
|
|
|
@ -533,7 +533,8 @@ impl Song {
|
||||||
}
|
}
|
||||||
lyric_list.push(lyric.to_string());
|
lyric_list.push(lyric.to_string());
|
||||||
} else {
|
} else {
|
||||||
error!("NOT WORKING!");
|
// error!("NOT WORKING!");
|
||||||
|
()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// for lyric in lyric_list.iter() {
|
// for lyric in lyric_list.iter() {
|
||||||
|
|
149
src/main.rs
149
src/main.rs
|
@ -2,6 +2,7 @@ use clap::{command, Parser};
|
||||||
use core::model::{get_db, LibraryKind};
|
use core::model::{get_db, LibraryKind};
|
||||||
use core::service_items::{ServiceItem, ServiceItemModel};
|
use core::service_items::{ServiceItem, ServiceItemModel};
|
||||||
use core::slide::*;
|
use core::slide::*;
|
||||||
|
use core::songs::Song;
|
||||||
use cosmic::app::context_drawer::ContextDrawer;
|
use cosmic::app::context_drawer::ContextDrawer;
|
||||||
use cosmic::app::{Core, Settings, Task};
|
use cosmic::app::{Core, Settings, Task};
|
||||||
use cosmic::iced::clipboard::dnd::DndAction;
|
use cosmic::iced::clipboard::dnd::DndAction;
|
||||||
|
@ -28,6 +29,7 @@ use crisp::types::Value;
|
||||||
use lisp::parse_lisp;
|
use lisp::parse_lisp;
|
||||||
use miette::{miette, Result};
|
use miette::{miette, Result};
|
||||||
use sqlx::{SqliteConnection, SqlitePool};
|
use sqlx::{SqliteConnection, SqlitePool};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tracing::{debug, level_filters::LevelFilter};
|
use tracing::{debug, level_filters::LevelFilter};
|
||||||
|
@ -97,6 +99,7 @@ struct App {
|
||||||
file: PathBuf,
|
file: PathBuf,
|
||||||
presenter: Presenter,
|
presenter: Presenter,
|
||||||
windows: Vec<window::Id>,
|
windows: Vec<window::Id>,
|
||||||
|
service: BTreeMap<ServiceItem, Vec<Slide>>,
|
||||||
slides: Vec<Slide>,
|
slides: Vec<Slide>,
|
||||||
current_slide: Slide,
|
current_slide: Slide,
|
||||||
presentation_open: bool,
|
presentation_open: bool,
|
||||||
|
@ -191,6 +194,7 @@ impl cosmic::Application for App {
|
||||||
presenter,
|
presenter,
|
||||||
core,
|
core,
|
||||||
nav_model,
|
nav_model,
|
||||||
|
service: BTreeMap::new(),
|
||||||
file: PathBuf::default(),
|
file: PathBuf::default(),
|
||||||
windows,
|
windows,
|
||||||
slides,
|
slides,
|
||||||
|
@ -417,86 +421,26 @@ impl cosmic::Application for App {
|
||||||
self.process_key_press(key, modifiers)
|
self.process_key_press(key, modifiers)
|
||||||
}
|
}
|
||||||
Message::SongEditor(message) => {
|
Message::SongEditor(message) => {
|
||||||
debug!(?message);
|
// debug!(?message);
|
||||||
let library_task = if let Some(mut song) =
|
match self.song_editor.update(message) {
|
||||||
self.song_editor.song.clone()
|
song_editor::Action::Task(task) => {
|
||||||
{
|
task.map(|m| {
|
||||||
match message {
|
cosmic::app::Message::App(
|
||||||
song_editor::Message::ChangeFont(
|
Message::SongEditor(m),
|
||||||
ref font,
|
)
|
||||||
) => {
|
|
||||||
song.font = Some(font.to_string());
|
|
||||||
self.song_editor.song =
|
|
||||||
Some(song.clone());
|
|
||||||
}
|
|
||||||
song_editor::Message::ChangeFontSize(
|
|
||||||
font_size,
|
|
||||||
) => {
|
|
||||||
song.font_size = Some(font_size as i32);
|
|
||||||
self.song_editor.song =
|
|
||||||
Some(song.clone());
|
|
||||||
}
|
|
||||||
song_editor::Message::ChangeTitle(
|
|
||||||
ref title,
|
|
||||||
) => {
|
|
||||||
song.title = title.to_string();
|
|
||||||
self.song_editor.song =
|
|
||||||
Some(song.clone());
|
|
||||||
}
|
|
||||||
song_editor::Message::ChangeVerseOrder(
|
|
||||||
ref vo,
|
|
||||||
) => {
|
|
||||||
let verse_order = vo
|
|
||||||
.split(" ")
|
|
||||||
.into_iter()
|
|
||||||
.map(|s| s.to_owned())
|
|
||||||
.collect();
|
|
||||||
song.verse_order = Some(verse_order);
|
|
||||||
self.song_editor.song =
|
|
||||||
Some(song.clone());
|
|
||||||
}
|
|
||||||
song_editor::Message::ChangeLyrics(
|
|
||||||
ref action,
|
|
||||||
) => {
|
|
||||||
self.song_editor
|
|
||||||
.lyrics
|
|
||||||
.perform(action.clone());
|
|
||||||
let lyrics =
|
|
||||||
self.song_editor.lyrics.text();
|
|
||||||
song.lyrics = Some(lyrics.to_string());
|
|
||||||
self.song_editor.song =
|
|
||||||
Some(song.clone());
|
|
||||||
}
|
|
||||||
song_editor::Message::ChangeAuthor(
|
|
||||||
ref author,
|
|
||||||
) => {
|
|
||||||
song.author = Some(author.to_string());
|
|
||||||
self.song_editor.song =
|
|
||||||
Some(song.clone());
|
|
||||||
}
|
|
||||||
song_editor::Message::Edit(_) => todo!(),
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(library) = &mut self.library {
|
|
||||||
let task = library.update(
|
|
||||||
library::Message::UpdateSong(song),
|
|
||||||
);
|
|
||||||
task.map(|_m| {
|
|
||||||
cosmic::app::Message::App(Message::None)
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
song_editor::Action::UpdateSong(song) => {
|
||||||
|
if let Some(library) = &mut self.library {
|
||||||
|
self.update(Message::Library(
|
||||||
|
library::Message::UpdateSong(song),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
Task::none()
|
song_editor::Action::None => Task::none(),
|
||||||
};
|
}
|
||||||
let song_editor_task =
|
|
||||||
self.song_editor.update(message).map(|m| {
|
|
||||||
debug!(?m);
|
|
||||||
cosmic::app::Message::App(Message::None)
|
|
||||||
});
|
|
||||||
Task::batch(vec![song_editor_task, library_task])
|
|
||||||
}
|
}
|
||||||
Message::Present(message) => {
|
Message::Present(message) => {
|
||||||
// debug!(?message);
|
// debug!(?message);
|
||||||
|
@ -506,12 +450,12 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.presenter.update(message).map(|x| {
|
self.presenter.update(message).map(|x| {
|
||||||
debug!(?x);
|
// debug!(?x);
|
||||||
cosmic::app::Message::App(Message::None)
|
cosmic::app::Message::App(Message::None)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Message::Library(message) => {
|
Message::Library(message) => {
|
||||||
|
<<<<<<< HEAD
|
||||||
// debug!(?message);
|
// debug!(?message);
|
||||||
let (mut kind, mut index): (LibraryKind, i32) =
|
let (mut kind, mut index): (LibraryKind, i32) =
|
||||||
(LibraryKind::Song, 0);
|
(LibraryKind::Song, 0);
|
||||||
|
@ -531,24 +475,47 @@ impl cosmic::Application for App {
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
=======
|
||||||
|
let mut song = Song::default();
|
||||||
|
>>>>>>> 93b021e (fixed lots of bugs by return Action enums in song_editor and library)
|
||||||
if let Some(library) = &mut self.library {
|
if let Some(library) = &mut self.library {
|
||||||
if opened_item {
|
match library.update(message) {
|
||||||
if let Some(song) = library.get_song(index) {
|
library::Action::OpenItem(None) => {
|
||||||
self.editor_mode = Some(EditorMode::Song);
|
return Task::none();
|
||||||
let _ = self.song_editor.update(
|
}
|
||||||
song_editor::Message::ChangeSong(
|
library::Action::Task(task) => {
|
||||||
song.clone(),
|
return task.map(|message| {
|
||||||
),
|
cosmic::app::Message::App(
|
||||||
|
Message::Library(message),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
library::Action::None => return Task::none(),
|
||||||
|
library::Action::OpenItem(Some((
|
||||||
|
kind,
|
||||||
|
index,
|
||||||
|
))) => {
|
||||||
|
debug!(
|
||||||
|
"Should get song at index: {:?}",
|
||||||
|
index
|
||||||
|
);
|
||||||
|
let Some(lib_song) =
|
||||||
|
library.get_song(index)
|
||||||
|
else {
|
||||||
|
return Task::none();
|
||||||
|
};
|
||||||
|
self.editor_mode = Some(kind.into());
|
||||||
|
song = lib_song.to_owned();
|
||||||
|
debug!(
|
||||||
|
"Should change songs to: {:?}",
|
||||||
|
song
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
library.update(message).map(|x| {
|
|
||||||
debug!(?x);
|
|
||||||
cosmic::app::Message::App(Message::None)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
|
self.update(Message::SongEditor(
|
||||||
|
song_editor::Message::ChangeSong(song),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Message::File(file) => {
|
Message::File(file) => {
|
||||||
self.file = file;
|
self.file = file;
|
||||||
|
|
|
@ -11,8 +11,10 @@ use cosmic::{
|
||||||
Element, Task,
|
Element, Task,
|
||||||
};
|
};
|
||||||
use miette::{miette, IntoDiagnostic, Result};
|
use miette::{miette, IntoDiagnostic, Result};
|
||||||
use sqlx::{SqliteConnection, SqlitePool};
|
use sqlx::{
|
||||||
use tracing::{debug, error};
|
pool::PoolConnection, Sqlite, SqliteConnection, SqlitePool,
|
||||||
|
};
|
||||||
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
use crate::core::{
|
use crate::core::{
|
||||||
content::Content,
|
content::Content,
|
||||||
|
@ -39,6 +41,12 @@ pub(crate) struct Library {
|
||||||
db: SqlitePool,
|
db: SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) enum Action {
|
||||||
|
OpenItem(Option<(LibraryKind, i32)>),
|
||||||
|
Task(Task<Message>),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) enum Message {
|
pub(crate) enum Message {
|
||||||
AddItem,
|
AddItem,
|
||||||
|
@ -85,85 +93,76 @@ impl<'a> Library {
|
||||||
self.song_library.get_item(index)
|
self.song_library.get_item(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&'a mut self, message: Message) -> Task<Message> {
|
pub fn update(&'a mut self, message: Message) -> Action {
|
||||||
match message {
|
match message {
|
||||||
Message::AddItem => Task::none(),
|
Message::AddItem => (),
|
||||||
Message::None => Task::none(),
|
Message::None => (),
|
||||||
Message::RemoveItem => Task::none(),
|
Message::RemoveItem => (),
|
||||||
Message::OpenItem(item) => {
|
Message::OpenItem(item) => {
|
||||||
debug!(?item);
|
debug!(?item);
|
||||||
self.editing_item = item;
|
self.editing_item = item;
|
||||||
Task::none()
|
return Action::OpenItem(item);
|
||||||
}
|
}
|
||||||
Message::HoverLibrary(library_kind) => {
|
Message::HoverLibrary(library_kind) => {
|
||||||
self.library_hovered = library_kind;
|
self.library_hovered = library_kind;
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::OpenLibrary(library_kind) => {
|
Message::OpenLibrary(library_kind) => {
|
||||||
self.library_open = library_kind;
|
self.library_open = library_kind;
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::HoverItem(item) => {
|
Message::HoverItem(item) => {
|
||||||
self.hovered_item = item;
|
self.hovered_item = item;
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::SelectItem(item) => {
|
Message::SelectItem(item) => {
|
||||||
self.selected_item = item;
|
self.selected_item = item;
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::UpdateSong(song) => {
|
Message::UpdateSong(song) => {
|
||||||
let Some((kind, index)) = self.editing_item else {
|
let Some((kind, index)) = self.editing_item else {
|
||||||
error!("Not editing an item");
|
error!("Not editing an item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
if kind != LibraryKind::Song {
|
if kind != LibraryKind::Song {
|
||||||
error!("Not editing a song item");
|
error!("Not editing a song item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.song_library
|
.song_library
|
||||||
.update_item(song.clone(), index)
|
.update_item(song.clone(), index)
|
||||||
{
|
{
|
||||||
Ok(_) => Task::future(self.db.acquire())
|
Ok(_) => {
|
||||||
.and_then(move |conn| {
|
return Action::Task(
|
||||||
Task::perform(
|
Task::future(self.db.acquire()).and_then(
|
||||||
update_song_in_db(song.clone(), conn)
|
move |conn| update_in_db(&song, conn),
|
||||||
.map(|r| match r {
|
),
|
||||||
Ok(_) => {}
|
|
||||||
Err(e) => {
|
|
||||||
error!(?e);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|_| Message::SongChanged,
|
|
||||||
)
|
)
|
||||||
}),
|
}
|
||||||
Err(_) => todo!(),
|
Err(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SongChanged => {
|
Message::SongChanged => {
|
||||||
// self.song_library.update_item(song, index);
|
// self.song_library.update_item(song, index);
|
||||||
debug!("song changed");
|
debug!("song changed");
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::UpdateImage(image) => {
|
Message::UpdateImage(image) => {
|
||||||
let Some((kind, index)) = self.editing_item else {
|
let Some((kind, index)) = self.editing_item else {
|
||||||
error!("Not editing an item");
|
error!("Not editing an item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
if kind != LibraryKind::Image {
|
if kind != LibraryKind::Image {
|
||||||
error!("Not editing a image item");
|
error!("Not editing a image item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.image_library
|
.image_library
|
||||||
.update_item(image.clone(), index)
|
.update_item(image.clone(), index)
|
||||||
{
|
{
|
||||||
Ok(_) => Task::future(self.db.acquire())
|
Ok(_) => {
|
||||||
.and_then(move |conn| {
|
return Action::Task(
|
||||||
|
Task::future(self.db.acquire()).and_then(
|
||||||
|
move |conn| {
|
||||||
Task::perform(
|
Task::perform(
|
||||||
update_image_in_db(
|
update_image_in_db(
|
||||||
image.clone(),
|
image.clone(),
|
||||||
|
@ -171,28 +170,33 @@ impl<'a> Library {
|
||||||
),
|
),
|
||||||
|_| Message::ImageChanged,
|
|_| Message::ImageChanged,
|
||||||
)
|
)
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
Err(_) => todo!(),
|
Err(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ImageChanged => todo!(),
|
Message::ImageChanged => (),
|
||||||
Message::UpdateVideo(video) => {
|
Message::UpdateVideo(video) => {
|
||||||
let Some((kind, index)) = self.editing_item else {
|
let Some((kind, index)) = self.editing_item else {
|
||||||
error!("Not editing an item");
|
error!("Not editing an item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
if kind != LibraryKind::Video {
|
if kind != LibraryKind::Video {
|
||||||
error!("Not editing a video item");
|
error!("Not editing a video item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.video_library
|
.video_library
|
||||||
.update_item(video.clone(), index)
|
.update_item(video.clone(), index)
|
||||||
{
|
{
|
||||||
Ok(_) => Task::future(self.db.acquire())
|
Ok(_) => {
|
||||||
.and_then(move |conn| {
|
return Action::Task(
|
||||||
|
Task::future(self.db.acquire()).and_then(
|
||||||
|
move |conn| {
|
||||||
Task::perform(
|
Task::perform(
|
||||||
update_video_in_db(
|
update_video_in_db(
|
||||||
video.clone(),
|
video.clone(),
|
||||||
|
@ -200,28 +204,32 @@ impl<'a> Library {
|
||||||
),
|
),
|
||||||
|_| Message::VideoChanged,
|
|_| Message::VideoChanged,
|
||||||
)
|
)
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
Err(_) => todo!(),
|
Err(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::VideoChanged => todo!(),
|
Message::VideoChanged => (),
|
||||||
Message::UpdatePresentation(presentation) => {
|
Message::UpdatePresentation(presentation) => {
|
||||||
let Some((kind, index)) = self.editing_item else {
|
let Some((kind, index)) = self.editing_item else {
|
||||||
error!("Not editing an item");
|
error!("Not editing an item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
if kind != LibraryKind::Presentation {
|
if kind != LibraryKind::Presentation {
|
||||||
error!("Not editing a presentation item");
|
error!("Not editing a presentation item");
|
||||||
return Task::none();
|
return Action::None;
|
||||||
};
|
};
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.presentation_library
|
.presentation_library
|
||||||
.update_item(presentation.clone(), index)
|
.update_item(presentation.clone(), index)
|
||||||
{
|
{
|
||||||
Ok(_) => Task::future(self.db.acquire())
|
Ok(_) => return Action::Task(
|
||||||
.and_then(move |conn| {
|
Task::future(self.db.acquire()).and_then(
|
||||||
|
move |conn| {
|
||||||
Task::perform(
|
Task::perform(
|
||||||
update_presentation_in_db(
|
update_presentation_in_db(
|
||||||
presentation.clone(),
|
presentation.clone(),
|
||||||
|
@ -229,13 +237,16 @@ impl<'a> Library {
|
||||||
),
|
),
|
||||||
|_| Message::PresentationChanged,
|
|_| Message::PresentationChanged,
|
||||||
)
|
)
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
Err(_) => todo!(),
|
Err(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::PresentationChanged => todo!(),
|
Message::PresentationChanged => (),
|
||||||
Message::Error(_) => todo!(),
|
Message::Error(_) => (),
|
||||||
}
|
};
|
||||||
|
Action::None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Element<Message> {
|
pub fn view(&self) -> Element<Message> {
|
||||||
|
@ -508,6 +519,30 @@ impl<'a> Library {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_in_db(
|
||||||
|
song: &Song,
|
||||||
|
conn: PoolConnection<Sqlite>,
|
||||||
|
) -> Task<Message> {
|
||||||
|
let song_title = song.title.clone();
|
||||||
|
warn!("Should have updated song: {:?}", song_title);
|
||||||
|
Task::perform(
|
||||||
|
update_song_in_db(song.to_owned(), conn).map(
|
||||||
|
move |r| match r {
|
||||||
|
Ok(_) => {
|
||||||
|
warn!(
|
||||||
|
"Should have updated song: {:?}",
|
||||||
|
song_title
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(?e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
|_| Message::SongChanged,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fn add_db() -> Result<SqlitePool> {
|
async fn add_db() -> Result<SqlitePool> {
|
||||||
let mut data = dirs::data_local_dir().unwrap();
|
let mut data = dirs::data_local_dir().unwrap();
|
||||||
data.push("lumina");
|
data.push("lumina");
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::core::model::LibraryKind;
|
||||||
|
|
||||||
pub mod double_ended_slider;
|
pub mod double_ended_slider;
|
||||||
pub mod library;
|
pub mod library;
|
||||||
pub mod presenter;
|
pub mod presenter;
|
||||||
|
@ -11,3 +13,14 @@ pub enum EditorMode {
|
||||||
Presentation,
|
Presentation,
|
||||||
Slide,
|
Slide,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<LibraryKind> for EditorMode {
|
||||||
|
fn from(value: LibraryKind) -> Self {
|
||||||
|
match value {
|
||||||
|
LibraryKind::Song => Self::Song,
|
||||||
|
LibraryKind::Video => Self::Video,
|
||||||
|
LibraryKind::Image => Self::Image,
|
||||||
|
LibraryKind::Presentation => Self::Presentation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::path::PathBuf;
|
use std::{io, path::PathBuf};
|
||||||
|
|
||||||
use cosmic::{
|
use cosmic::{
|
||||||
iced::{
|
iced::{
|
||||||
|
@ -17,11 +17,11 @@ use cosmic::{
|
||||||
};
|
};
|
||||||
use dirs::font_dir;
|
use dirs::font_dir;
|
||||||
use iced_video_player::Video;
|
use iced_video_player::Video;
|
||||||
use tracing::debug;
|
use tracing::{debug, error};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
core::{service_items::ServiceTrait, songs::Song},
|
core::{service_items::ServiceTrait, songs::Song},
|
||||||
Background,
|
Background, BackgroundKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::presenter::slide_view;
|
use super::presenter::slide_view;
|
||||||
|
@ -45,6 +45,12 @@ pub struct SongEditor {
|
||||||
ccli: String,
|
ccli: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Action {
|
||||||
|
Task(Task<Message>),
|
||||||
|
UpdateSong(Song),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
ChangeSong(Song),
|
ChangeSong(Song),
|
||||||
|
@ -54,7 +60,8 @@ pub enum Message {
|
||||||
ChangeTitle(String),
|
ChangeTitle(String),
|
||||||
ChangeVerseOrder(String),
|
ChangeVerseOrder(String),
|
||||||
ChangeLyrics(text_editor::Action),
|
ChangeLyrics(text_editor::Action),
|
||||||
ChangeBackground,
|
ChangeBackground(Result<PathBuf, SongError>),
|
||||||
|
PickBackground,
|
||||||
Edit(bool),
|
Edit(bool),
|
||||||
None,
|
None,
|
||||||
ChangeAuthor(String),
|
ChangeAuthor(String),
|
||||||
|
@ -144,7 +151,7 @@ impl SongEditor {
|
||||||
ccli: "8".to_owned(),
|
ccli: "8".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update(&mut self, message: Message) -> Task<Message> {
|
pub fn update(&mut self, message: Message) -> Action {
|
||||||
match message {
|
match message {
|
||||||
Message::ChangeSong(song) => {
|
Message::ChangeSong(song) => {
|
||||||
self.song = Some(song.clone());
|
self.song = Some(song.clone());
|
||||||
|
@ -178,12 +185,6 @@ impl SongEditor {
|
||||||
text_editor::Content::with_text(&lyrics)
|
text_editor::Content::with_text(&lyrics)
|
||||||
};
|
};
|
||||||
self.background = song.background;
|
self.background = song.background;
|
||||||
|
|
||||||
Task::none()
|
|
||||||
}
|
|
||||||
Message::UpdateSong(song) => {
|
|
||||||
self.song = Some(song);
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::ChangeFont(font) => {
|
Message::ChangeFont(font) => {
|
||||||
self.font = font.clone();
|
self.font = font.clone();
|
||||||
|
@ -200,20 +201,24 @@ impl SongEditor {
|
||||||
style,
|
style,
|
||||||
};
|
};
|
||||||
self.current_font = font;
|
self.current_font = font;
|
||||||
Task::none()
|
// return self.update_song(song);
|
||||||
}
|
}
|
||||||
Message::ChangeFontSize(size) => {
|
Message::ChangeFontSize(size) => {
|
||||||
if let Some(size) = self.font_sizes.get(size) {
|
if let Some(size) = self.font_sizes.get(size) {
|
||||||
if let Ok(size) = size.parse() {
|
if let Ok(size) = size.parse() {
|
||||||
debug!(font_size = size);
|
debug!(font_size = size);
|
||||||
self.font_size = size;
|
self.font_size = size;
|
||||||
|
// return self.update_song(song);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::ChangeTitle(title) => {
|
Message::ChangeTitle(title) => {
|
||||||
self.title = title.clone();
|
self.title = title.clone();
|
||||||
Task::none()
|
if let Some(song) = &mut self.song {
|
||||||
|
song.title = title;
|
||||||
|
let song = song.to_owned();
|
||||||
|
return self.update_song(song);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::ChangeVerseOrder(verse_order) => {
|
Message::ChangeVerseOrder(verse_order) => {
|
||||||
self.verse_order = verse_order.clone();
|
self.verse_order = verse_order.clone();
|
||||||
|
@ -224,9 +229,7 @@ impl SongEditor {
|
||||||
.map(|s| s.to_owned())
|
.map(|s| s.to_owned())
|
||||||
.collect();
|
.collect();
|
||||||
song.verse_order = Some(verse_order);
|
song.verse_order = Some(verse_order);
|
||||||
self.update(Message::UpdateSong(song))
|
return self.update_song(song);
|
||||||
} else {
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ChangeLyrics(action) => {
|
Message::ChangeLyrics(action) => {
|
||||||
|
@ -236,61 +239,50 @@ impl SongEditor {
|
||||||
|
|
||||||
if let Some(mut song) = self.song.clone() {
|
if let Some(mut song) = self.song.clone() {
|
||||||
song.lyrics = Some(lyrics);
|
song.lyrics = Some(lyrics);
|
||||||
self.update(Message::UpdateSong(song))
|
return self.update_song(song);
|
||||||
} else {
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Edit(edit) => {
|
Message::Edit(edit) => {
|
||||||
debug!(edit);
|
debug!(edit);
|
||||||
self.editing = edit;
|
self.editing = edit;
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
Message::None => Task::none(),
|
|
||||||
Message::ChangeAuthor(author) => {
|
Message::ChangeAuthor(author) => {
|
||||||
debug!(author);
|
debug!(author);
|
||||||
self.author = author.clone();
|
self.author = author.clone();
|
||||||
if let Some(mut song) = self.song.clone() {
|
if let Some(mut song) = self.song.clone() {
|
||||||
song.author = Some(author);
|
song.author = Some(author);
|
||||||
self.update(Message::UpdateSong(song))
|
return self.update_song(song);
|
||||||
} else {
|
|
||||||
Task::none()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ChangeBackground => {
|
Message::ChangeBackground(Ok(path)) => {
|
||||||
let background = rfd::FileDialog::new()
|
debug!(?path);
|
||||||
.pick_file()
|
|
||||||
.and_then(|f| {
|
|
||||||
Background::try_from(f)
|
|
||||||
.map_or(None, |f| Some(f))
|
|
||||||
});
|
|
||||||
|
|
||||||
debug!(?background);
|
|
||||||
if let Some(mut song) = self.song.clone() {
|
if let Some(mut song) = self.song.clone() {
|
||||||
song.background = background.clone();
|
let background =
|
||||||
self.update(Message::UpdateSong(song))
|
Background::try_from(path.clone()).ok();
|
||||||
} else {
|
if let Some(background) = background {
|
||||||
Task::none()
|
if background.kind == BackgroundKind::Video {
|
||||||
}
|
let video =
|
||||||
|
Video::try_from(background).ok();
|
||||||
// todo!()
|
debug!(?video);
|
||||||
|
self.video = video;
|
||||||
// if let Some(mut song) = self.song.clone() {
|
|
||||||
// Task::future(
|
|
||||||
// rfd::AsyncFileDialog::new().pick_file(),
|
|
||||||
// )
|
|
||||||
// .and_then(move |f| {
|
|
||||||
// song.background = f
|
|
||||||
// .path()
|
|
||||||
// .try_into()
|
|
||||||
// .map_or(None, |b| Some(b));
|
|
||||||
// Task::none()
|
|
||||||
// })
|
|
||||||
// } else {
|
|
||||||
// Task::none()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
song.background = path.try_into().ok();
|
||||||
|
return self.update_song(song);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::ChangeBackground(Err(error)) => {
|
||||||
|
error!(?error);
|
||||||
|
}
|
||||||
|
Message::PickBackground => {
|
||||||
|
return Action::Task(Task::perform(
|
||||||
|
pick_background(),
|
||||||
|
Message::ChangeBackground,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
Action::None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Element<Message> {
|
pub fn view(&self) -> Element<Message> {
|
||||||
|
@ -411,7 +403,7 @@ order",
|
||||||
)
|
)
|
||||||
.label("Background")
|
.label("Background")
|
||||||
.tooltip("Select an image or video background")
|
.tooltip("Select an image or video background")
|
||||||
.on_press(Message::ChangeBackground)
|
.on_press(Message::PickBackground)
|
||||||
.padding(10);
|
.padding(10);
|
||||||
|
|
||||||
row![
|
row![
|
||||||
|
@ -426,6 +418,11 @@ order",
|
||||||
pub fn editing(&self) -> bool {
|
pub fn editing(&self) -> bool {
|
||||||
self.editing
|
self.editing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_song(&mut self, song: Song) -> Action {
|
||||||
|
self.song = Some(song.clone());
|
||||||
|
Action::UpdateSong(song)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SongEditor {
|
impl Default for SongEditor {
|
||||||
|
@ -433,3 +430,18 @@ impl Default for SongEditor {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn pick_background() -> Result<PathBuf, SongError> {
|
||||||
|
rfd::AsyncFileDialog::new()
|
||||||
|
.set_title("Choose a background...")
|
||||||
|
.pick_file()
|
||||||
|
.await
|
||||||
|
.ok_or(SongError::DialogClosed)
|
||||||
|
.map(|file| file.path().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SongError {
|
||||||
|
DialogClosed,
|
||||||
|
IOError(io::ErrorKind),
|
||||||
|
}
|
||||||
|
|
2
todo.org
2
todo.org
|
@ -1,6 +1,8 @@
|
||||||
#+TITLE: The Task list for Lumina
|
#+TITLE: The Task list for Lumina
|
||||||
|
|
||||||
|
|
||||||
|
* TODO Change return type of all components to an Action enum instead of the Task<Message> type
|
||||||
|
|
||||||
* TODO Need to fix tests now that the basic app is working
|
* TODO Need to fix tests now that the basic app is working
|
||||||
|
|
||||||
* TODO Build library to see all available songs, images, videos, presentations, and slides
|
* TODO Build library to see all available songs, images, videos, presentations, and slides
|
||||||
|
|
Loading…
Reference in a new issue