working using the passing of model items around
Moving the model into and out of the db functions creates more messages, but allows for less complexity in the overall library module. This means that the library can just use those functions to change the model and db, but need to remember to readd the items to the model once the function is finished in the async function.
This commit is contained in:
parent
4ad86785e5
commit
4c0123e94e
5 changed files with 476 additions and 447 deletions
|
|
@ -7,13 +7,17 @@ use super::{
|
|||
service_items::ServiceTrait,
|
||||
};
|
||||
use crisp::types::{Keyword, Symbol, Value};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use miette::{IntoDiagnostic, Result, miette};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{
|
||||
Sqlite, SqliteConnection, SqlitePool, pool::PoolConnection,
|
||||
query, query_as,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
mem::replace,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(
|
||||
|
|
@ -254,70 +258,84 @@ impl Model<Image> {
|
|||
}
|
||||
|
||||
pub async fn remove_from_db(
|
||||
db: PoolConnection<Sqlite>,
|
||||
db: Arc<SqlitePool>,
|
||||
mut images: Vec<Image>,
|
||||
id: i32,
|
||||
) -> Result<()> {
|
||||
) -> Result<Vec<Image>> {
|
||||
query!("DELETE FROM images WHERE id = $1", id)
|
||||
.execute(&mut db.detach())
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.map(|_| ())
|
||||
.map(|_| ())?;
|
||||
let index = images
|
||||
.iter()
|
||||
.position(|current_image| current_image.id == id)
|
||||
.ok_or_else(|| miette!("Could not find image in model"))?;
|
||||
images.remove(index);
|
||||
Ok(images)
|
||||
}
|
||||
|
||||
pub async fn add_image_to_db(
|
||||
image: Image,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
let path = image
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
query!(
|
||||
pub async fn add_to_db(
|
||||
new_images: Vec<Image>,
|
||||
mut current_images: Vec<Image>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Image>> {
|
||||
for image in new_images {
|
||||
let path = image
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
|
||||
query!(
|
||||
r#"INSERT INTO images (title, file_path) VALUES ($1, $2)"#,
|
||||
image.title,
|
||||
path,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
Ok(())
|
||||
|
||||
current_images.push(image);
|
||||
}
|
||||
Ok(current_images)
|
||||
}
|
||||
|
||||
pub async fn update_image_in_db(
|
||||
pub async fn update_in_db(
|
||||
image: Image,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
mut images: Vec<Image>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Image>> {
|
||||
let path = image
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
debug!(?image, "should be been updated");
|
||||
let result = query!(
|
||||
|
||||
query!(
|
||||
r#"UPDATE images SET title = $2, file_path = $3 WHERE id = $1"#,
|
||||
image.id,
|
||||
image.title,
|
||||
path,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await.into_diagnostic();
|
||||
.execute(&*db)
|
||||
.await.into_diagnostic()?;
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
debug!("should have been updated");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error! {?e};
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
let current_image = images
|
||||
.iter()
|
||||
.position(|current_image| current_image.id == image.id)
|
||||
.ok_or_else(|| miette!("Could not find image in model"))
|
||||
.map(|index| {
|
||||
images
|
||||
.get_mut(index)
|
||||
.expect("We should have this image already")
|
||||
})?;
|
||||
|
||||
replace(current_image, image);
|
||||
Ok(images)
|
||||
}
|
||||
|
||||
pub async fn get_image_from_db(
|
||||
pub async fn get_from_db(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Image> {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
use cosmic::widget::image::Handle;
|
||||
use crisp::types::{Keyword, Symbol, Value};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use miette::{IntoDiagnostic, Result, miette};
|
||||
use mupdf::{Colorspace, Document, Matrix};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{
|
||||
Row, Sqlite, SqliteConnection, SqlitePool, pool::PoolConnection,
|
||||
prelude::FromRow, query, sqlite::SqliteRow,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
mem::replace,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::{Background, Slide, SlideBuilder, TextAlignment};
|
||||
|
|
@ -406,61 +410,77 @@ impl Model<Presentation> {
|
|||
}
|
||||
|
||||
pub async fn remove_from_db(
|
||||
db: PoolConnection<Sqlite>,
|
||||
db: Arc<SqlitePool>,
|
||||
mut presentations: Vec<Presentation>,
|
||||
id: i32,
|
||||
) -> Result<()> {
|
||||
) -> Result<Vec<Presentation>> {
|
||||
query!("DELETE FROM presentations WHERE id = $1", id)
|
||||
.execute(&mut db.detach())
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.map(|_| ())
|
||||
.map(|_| ())?;
|
||||
|
||||
let index = presentations
|
||||
.iter()
|
||||
.position(|current_presentation| {
|
||||
current_presentation.id == id
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
miette!("Could not find presentation in model")
|
||||
})?;
|
||||
presentations.remove(index);
|
||||
Ok(presentations)
|
||||
}
|
||||
|
||||
pub async fn add_presentation_to_db(
|
||||
pub async fn add_to_db(
|
||||
new_presentations: Vec<Presentation>,
|
||||
mut current_presentations: Vec<Presentation>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Presentation>> {
|
||||
for presentation in new_presentations {
|
||||
let path = presentation
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let html = presentation.kind == PresKind::Html;
|
||||
let (starting_index, ending_index) = if let PresKind::Pdf {
|
||||
starting_index,
|
||||
ending_index,
|
||||
} = presentation.kind
|
||||
{
|
||||
(starting_index, ending_index)
|
||||
} else {
|
||||
(0, 0)
|
||||
};
|
||||
query!(
|
||||
r#"INSERT INTO presentations (title, file_path, html, starting_index, ending_index) VALUES ($1, $2, $3, $4, $5)"#,
|
||||
presentation.title,
|
||||
path,
|
||||
html,
|
||||
starting_index,
|
||||
ending_index
|
||||
)
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
|
||||
current_presentations.push(presentation);
|
||||
}
|
||||
Ok(current_presentations)
|
||||
}
|
||||
|
||||
pub async fn update_in_db(
|
||||
presentation: Presentation,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
mut presentations: Vec<Presentation>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Presentation>> {
|
||||
let path = presentation
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let html = presentation.kind == PresKind::Html;
|
||||
let mut db = db.detach();
|
||||
let (starting_index, ending_index) = if let PresKind::Pdf {
|
||||
starting_index,
|
||||
ending_index,
|
||||
} = presentation.kind
|
||||
{
|
||||
(starting_index, ending_index)
|
||||
} else {
|
||||
(0, 0)
|
||||
};
|
||||
query!(
|
||||
r#"INSERT INTO presentations (title, file_path, html, starting_index, ending_index) VALUES ($1, $2, $3, $4, $5)"#,
|
||||
presentation.title,
|
||||
path,
|
||||
html,
|
||||
starting_index,
|
||||
ending_index
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_presentation_in_db(
|
||||
presentation: Presentation,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
let path = presentation
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let html = presentation.kind == PresKind::Html;
|
||||
let mut db = db.detach();
|
||||
let (starting_index, ending_index) = if let PresKind::Pdf {
|
||||
starting_index: s_index,
|
||||
ending_index: e_index,
|
||||
|
|
@ -472,53 +492,8 @@ pub async fn update_presentation_in_db(
|
|||
(0, 0)
|
||||
};
|
||||
debug!(starting_index, ending_index);
|
||||
let id = presentation.id;
|
||||
if let Err(e) =
|
||||
query!("SELECT id FROM presentations where id = $1", id)
|
||||
.fetch_one(&mut db)
|
||||
.await
|
||||
{
|
||||
if let Ok(ids) = query!("SELECT id FROM presentations")
|
||||
.fetch_all(&mut db)
|
||||
.await
|
||||
{
|
||||
let Some(mut max) = ids.iter().map(|r| r.id).max() else {
|
||||
return Err(miette::miette!("cannot find max id"));
|
||||
};
|
||||
debug!(
|
||||
?e,
|
||||
"Presentation not found adding a new presentation"
|
||||
);
|
||||
max += 1;
|
||||
let result = query!(
|
||||
r#"INSERT into presentations VALUES($1, $2, $3, $4, $5, $6)"#,
|
||||
max,
|
||||
presentation.title,
|
||||
path,
|
||||
html,
|
||||
starting_index,
|
||||
ending_index,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic();
|
||||
|
||||
return match result {
|
||||
Ok(_) => {
|
||||
debug!("presentation should have been added");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error! {?e};
|
||||
Err(e)
|
||||
}
|
||||
};
|
||||
}
|
||||
return Err(miette::miette!("cannot find ids"));
|
||||
}
|
||||
|
||||
debug!(?presentation, "should be been updated");
|
||||
let result = query!(
|
||||
query!(
|
||||
r#"UPDATE presentations SET title = $2, file_path = $3, html = $4, starting_index = $5, ending_index = $6 WHERE id = $1"#,
|
||||
presentation.id,
|
||||
presentation.title,
|
||||
|
|
@ -527,19 +502,25 @@ pub async fn update_presentation_in_db(
|
|||
starting_index,
|
||||
ending_index
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await.into_diagnostic();
|
||||
.execute(&*db)
|
||||
.await.into_diagnostic()?;
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
debug!("should have been updated");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error! {?e};
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
let current_presentation = presentations
|
||||
.iter()
|
||||
.position(|current_presentation| {
|
||||
current_presentation.id == presentation.id
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
miette!("Could not find presentation in model")
|
||||
})
|
||||
.map(|index| {
|
||||
presentations
|
||||
.get_mut(index)
|
||||
.expect("We should have this presentation already")
|
||||
})?;
|
||||
|
||||
replace(current_presentation, presentation);
|
||||
Ok(presentations)
|
||||
}
|
||||
|
||||
pub async fn get_presentation_from_db(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
borrow::Cow, collections::HashMap, option::Option, path::PathBuf,
|
||||
sync::Arc,
|
||||
borrow::Cow, collections::HashMap, mem::replace, option::Option,
|
||||
path::PathBuf, sync::Arc,
|
||||
};
|
||||
|
||||
use cosmic::{
|
||||
|
|
@ -1027,26 +1027,28 @@ pub async fn add_to_db(
|
|||
Ok(songs)
|
||||
}
|
||||
|
||||
pub async fn update_song_in_db(
|
||||
item: Song,
|
||||
songs: Vec<Song>,
|
||||
pub async fn update_in_db(
|
||||
song: Song,
|
||||
mut songs: Vec<Song>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<()> {
|
||||
) -> Result<Vec<Song>> {
|
||||
// self.update_item(item.clone(), index)?;
|
||||
|
||||
// debug!(?item);
|
||||
let verse_order =
|
||||
ron::ser::to_string(&item.verses).into_diagnostic()?;
|
||||
ron::ser::to_string(&song.verses).into_diagnostic()?;
|
||||
|
||||
let audio = item
|
||||
let audio = song
|
||||
.audio
|
||||
.clone()
|
||||
.map(|a| a.to_str().unwrap_or_default().to_string());
|
||||
|
||||
let background = item
|
||||
let background = song
|
||||
.background
|
||||
.clone()
|
||||
.map(|b| b.path.to_str().unwrap_or_default().to_string());
|
||||
|
||||
let lyrics = item.verse_map.map(|map| {
|
||||
let lyrics = song.verse_map.clone().map(|map| {
|
||||
map.iter()
|
||||
.map(|(name, lyric)| {
|
||||
let lyric = lyric.trim_end_matches('\n').to_string();
|
||||
|
|
@ -1057,7 +1059,7 @@ pub async fn update_song_in_db(
|
|||
let lyrics = ron::ser::to_string(&lyrics).into_diagnostic()?;
|
||||
|
||||
let (vertical_alignment, horizontal_alignment) =
|
||||
item.text_alignment.map_or_else(
|
||||
song.text_alignment.map_or_else(
|
||||
|| ("center", "center"),
|
||||
|ta| match ta {
|
||||
TextAlignment::TopLeft => ("top", "left"),
|
||||
|
|
@ -1072,20 +1074,20 @@ pub async fn update_song_in_db(
|
|||
},
|
||||
);
|
||||
|
||||
let stroke_size = item.stroke_size.unwrap_or_default();
|
||||
let shadow_size = item.shadow_size.unwrap_or_default();
|
||||
let stroke_size = song.stroke_size.unwrap_or_default();
|
||||
let shadow_size = song.shadow_size.unwrap_or_default();
|
||||
let (shadow_offset_x, shadow_offset_y) =
|
||||
item.shadow_offset.unwrap_or_default();
|
||||
song.shadow_offset.unwrap_or_default();
|
||||
|
||||
let stroke_color =
|
||||
ron::ser::to_string(&item.stroke_color).into_diagnostic()?;
|
||||
ron::ser::to_string(&song.stroke_color).into_diagnostic()?;
|
||||
let shadow_color =
|
||||
ron::ser::to_string(&item.shadow_color).into_diagnostic()?;
|
||||
ron::ser::to_string(&song.shadow_color).into_diagnostic()?;
|
||||
|
||||
let style =
|
||||
ron::ser::to_string(&item.font_style).into_diagnostic()?;
|
||||
ron::ser::to_string(&song.font_style).into_diagnostic()?;
|
||||
let weight =
|
||||
ron::ser::to_string(&item.font_weight).into_diagnostic()?;
|
||||
ron::ser::to_string(&song.font_weight).into_diagnostic()?;
|
||||
|
||||
// debug!(
|
||||
// ?stroke_size,
|
||||
|
|
@ -1098,15 +1100,15 @@ pub async fn update_song_in_db(
|
|||
|
||||
let result = query!(
|
||||
r#"UPDATE songs SET title = $2, lyrics = $3, author = $4, ccli = $5, verse_order = $6, audio = $7, font = $8, font_size = $9, background = $10, horizontal_text_alignment = $11, vertical_text_alignment = $12, stroke_color = $13, shadow_color = $14, stroke_size = $15, shadow_size = $16, shadow_offset_x = $17, shadow_offset_y = $18, style = $19, weight = $20 WHERE id = $1"#,
|
||||
item.id,
|
||||
item.title,
|
||||
song.id,
|
||||
song.title,
|
||||
lyrics,
|
||||
item.author,
|
||||
item.ccli,
|
||||
song.author,
|
||||
song.ccli,
|
||||
verse_order,
|
||||
audio,
|
||||
item.font,
|
||||
item.font_size,
|
||||
song.font,
|
||||
song.font_size,
|
||||
background,
|
||||
horizontal_alignment,
|
||||
vertical_alignment,
|
||||
|
|
@ -1124,8 +1126,18 @@ pub async fn update_song_in_db(
|
|||
.into_diagnostic()?;
|
||||
|
||||
debug!(rows_affected = ?result.rows_affected());
|
||||
let index = songs
|
||||
.iter()
|
||||
.position(|current_song| current_song.id == song.id)
|
||||
.ok_or_else(|| miette!("Could not find song in model"))?;
|
||||
|
||||
Ok(())
|
||||
replace(
|
||||
songs
|
||||
.get_mut(index)
|
||||
.expect("We have found the song so this shouldn't fail"),
|
||||
song,
|
||||
);
|
||||
Ok(songs)
|
||||
}
|
||||
|
||||
impl Song {
|
||||
|
|
|
|||
|
|
@ -8,13 +8,17 @@ use super::{
|
|||
slide::Slide,
|
||||
};
|
||||
use crisp::types::{Keyword, Symbol, Value};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use miette::{IntoDiagnostic, Result, miette};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::{
|
||||
Sqlite, SqliteConnection, SqlitePool, pool::PoolConnection,
|
||||
query, query_as,
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
mem::replace,
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(
|
||||
|
|
@ -254,52 +258,65 @@ impl Model<Video> {
|
|||
}
|
||||
|
||||
pub async fn remove_from_db(
|
||||
db: PoolConnection<Sqlite>,
|
||||
db: Arc<SqlitePool>,
|
||||
mut videos: Vec<Video>,
|
||||
id: i32,
|
||||
) -> Result<()> {
|
||||
) -> Result<Vec<Video>> {
|
||||
query!("DELETE FROM videos WHERE id = $1", id)
|
||||
.execute(&mut db.detach())
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()
|
||||
.map(|_| ())
|
||||
.map(|_| ())?;
|
||||
|
||||
let index = videos
|
||||
.iter()
|
||||
.position(|current_video| current_video.id == id)
|
||||
.ok_or_else(|| miette!("Could not find video in model"))?;
|
||||
videos.remove(index);
|
||||
Ok(videos)
|
||||
}
|
||||
|
||||
pub async fn add_video_to_db(
|
||||
pub async fn add_to_db(
|
||||
new_videos: Vec<Video>,
|
||||
mut current_videos: Vec<Video>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Video>> {
|
||||
for video in new_videos {
|
||||
let path = video
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
|
||||
query!(
|
||||
r#"INSERT INTO videos (title, file_path, start_time, end_time, loop) VALUES ($1, $2, $3, $4, $5)"#,
|
||||
video.title,
|
||||
path,
|
||||
video.start_time,
|
||||
video.end_time,
|
||||
video.looping
|
||||
)
|
||||
.execute(&*db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
|
||||
current_videos.push(video);
|
||||
}
|
||||
Ok(current_videos)
|
||||
}
|
||||
|
||||
pub async fn update_in_db(
|
||||
video: Video,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
mut videos: Vec<Video>,
|
||||
db: Arc<SqlitePool>,
|
||||
) -> Result<Vec<Video>> {
|
||||
let path = video
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
|
||||
query!(
|
||||
r#"INSERT INTO videos (title, file_path, start_time, end_time, loop) VALUES ($1, $2, $3, $4, $5)"#,
|
||||
video.title,
|
||||
path,
|
||||
video.start_time,
|
||||
video.end_time,
|
||||
video.looping
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_video_in_db(
|
||||
video: Video,
|
||||
db: PoolConnection<Sqlite>,
|
||||
) -> Result<()> {
|
||||
let path = video
|
||||
.path
|
||||
.to_str()
|
||||
.map(std::string::ToString::to_string)
|
||||
.unwrap_or_default();
|
||||
let mut db = db.detach();
|
||||
debug!(?video, "should be been updated");
|
||||
let result = query!(
|
||||
r#"UPDATE videos SET title = $2, file_path = $3, start_time = $4, end_time = $5, loop = $6 WHERE id = $1"#,
|
||||
video.id,
|
||||
video.title,
|
||||
|
|
@ -308,22 +325,24 @@ pub async fn update_video_in_db(
|
|||
video.end_time,
|
||||
video.looping,
|
||||
)
|
||||
.execute(&mut db)
|
||||
.await.into_diagnostic();
|
||||
.execute(&*db)
|
||||
.await.into_diagnostic()?;
|
||||
|
||||
match result {
|
||||
Ok(_) => {
|
||||
debug!("should have been updated");
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error! {?e};
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
let current_video = videos
|
||||
.iter()
|
||||
.position(|current_video| current_video.id == video.id)
|
||||
.ok_or_else(|| miette!("Could not find video in model"))
|
||||
.map(|index| {
|
||||
videos
|
||||
.get_mut(index)
|
||||
.expect("We should have this video already")
|
||||
})?;
|
||||
|
||||
replace(current_video, video);
|
||||
Ok(videos)
|
||||
}
|
||||
|
||||
pub async fn get_video_from_db(
|
||||
pub async fn get_from_db(
|
||||
database_id: i32,
|
||||
db: &mut SqliteConnection,
|
||||
) -> Result<Video> {
|
||||
|
|
|
|||
|
|
@ -26,16 +26,13 @@ use tracing::{debug, error, warn};
|
|||
|
||||
use crate::core::{
|
||||
content::Content,
|
||||
images::{self, Image, add_image_to_db, update_image_in_db},
|
||||
images::{self, Image},
|
||||
kinds::ServiceItemKind,
|
||||
model::{KindWrapper, LibraryKind, Model},
|
||||
presentations::{
|
||||
self, Presentation, add_presentation_to_db,
|
||||
update_presentation_in_db,
|
||||
},
|
||||
presentations::{self, Presentation},
|
||||
service_items::ServiceItem,
|
||||
songs::{self, Song, add_to_db, update_song_in_db},
|
||||
videos::{self, Video, add_video_to_db, update_video_in_db},
|
||||
songs::{self, Song},
|
||||
videos::{self, Video},
|
||||
};
|
||||
|
||||
#[allow(clippy::struct_field_names)]
|
||||
|
|
@ -110,6 +107,9 @@ pub enum Message {
|
|||
AddVideos(Option<Vec<Video>>),
|
||||
AddPresentations(Option<Vec<Presentation>>),
|
||||
AddPresentationSplit(Option<Presentation>),
|
||||
ReaddImages(Vec<Image>),
|
||||
ReaddVideos(Vec<Video>),
|
||||
ReaddPres(Vec<Presentation>),
|
||||
}
|
||||
|
||||
impl<'a> Library {
|
||||
|
|
@ -164,7 +164,7 @@ impl<'a> Library {
|
|||
let songs =
|
||||
self.song_library.items.drain(..).collect();
|
||||
return Action::Task(Task::perform(
|
||||
add_to_db(songs, Arc::clone(&self.db)),
|
||||
songs::add_to_db(songs, Arc::clone(&self.db)),
|
||||
move |res| match res {
|
||||
Ok(songs) => Message::ReaddSongs(songs),
|
||||
Err(e) => {
|
||||
|
|
@ -202,48 +202,33 @@ impl<'a> Library {
|
|||
};
|
||||
}
|
||||
Message::AddVideos(videos) => {
|
||||
debug!(?videos);
|
||||
debug!(?videos, "adding to db");
|
||||
let mut index = self.video_library.items.len();
|
||||
// Check if empty
|
||||
let mut tasks = Vec::new();
|
||||
if let Some(videos) = videos {
|
||||
// let len = videos.len();
|
||||
for video in videos {
|
||||
if let Err(e) =
|
||||
self.video_library.add_item(video.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(self.db.acquire())
|
||||
.map_err(|e| {
|
||||
miette::miette!("Database error: {e}")
|
||||
})
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_video_to_db(
|
||||
video.clone(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
res.map(|_| {
|
||||
Message::OpenItem(Some((
|
||||
LibraryKind::Video,
|
||||
index as i32,
|
||||
)))
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|r| r.unwrap_or(Message::None));
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Video,
|
||||
self.video_library.items.len() as i32 - 1,
|
||||
))));
|
||||
if let Some(new_videos) = videos {
|
||||
let current_videos =
|
||||
self.video_library.items.drain(..).collect();
|
||||
let task = Task::perform(
|
||||
videos::add_to_db(
|
||||
new_videos,
|
||||
current_videos,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|videos| {
|
||||
Message::ReaddVideos(videos)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
);
|
||||
tasks.push(task);
|
||||
}
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
|
|
@ -257,24 +242,24 @@ impl<'a> Library {
|
|||
{
|
||||
error!(?e);
|
||||
}
|
||||
return Action::Task(
|
||||
Task::future(self.db.acquire())
|
||||
.map_err(|e| {
|
||||
miette::miette!("Database error: {e}")
|
||||
let presentations = self
|
||||
.presentation_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
return Action::Task(Task::perform(
|
||||
presentations::add_to_db(
|
||||
vec![presentation.clone()],
|
||||
presentations,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|presentations| {
|
||||
Message::ReaddPres(presentations)
|
||||
})
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_presentation_to_db(
|
||||
presentation.clone(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
res.map(|_| Message::None)
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|r| r.unwrap_or(Message::None)),
|
||||
);
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
Message::AddPresentations(presentations) => {
|
||||
|
|
@ -282,85 +267,65 @@ impl<'a> Library {
|
|||
let mut index = self.presentation_library.items.len();
|
||||
// Check if empty
|
||||
let mut tasks = Vec::new();
|
||||
if let Some(presentations) = presentations {
|
||||
// let len = presentations.len();
|
||||
for presentation in presentations {
|
||||
if let Err(e) = self
|
||||
.presentation_library
|
||||
.add_item(presentation.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(
|
||||
self.db.acquire(),
|
||||
)
|
||||
.map_err(|e| miette::miette!("Database error: {e}"))
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_presentation_to_db(
|
||||
presentation.clone(),
|
||||
db,
|
||||
),
|
||||
move |res| res.map(|_| Message::OpenItem(Some((LibraryKind::Presentation, index as i32))))
|
||||
)
|
||||
}).map(|r| r.unwrap_or(Message::None));
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Presentation,
|
||||
self.presentation_library.items.len() as i32
|
||||
- 1,
|
||||
))));
|
||||
if let Some(new_presentations) = presentations {
|
||||
let current_presentations = self
|
||||
.presentation_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
let task = Task::perform(
|
||||
presentations::add_to_db(
|
||||
new_presentations,
|
||||
current_presentations,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|presentations| {
|
||||
Message::ReaddPres(presentations)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
);
|
||||
tasks.push(task);
|
||||
}
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
}
|
||||
Message::AddImages(images) => {
|
||||
debug!(?images);
|
||||
debug!(?images, "adding to db");
|
||||
let mut index = self.image_library.items.len();
|
||||
// Check if empty
|
||||
let mut tasks = Vec::new();
|
||||
if let Some(images) = images {
|
||||
// let len = images.len();
|
||||
for image in images {
|
||||
if let Err(e) =
|
||||
self.image_library.add_item(image.clone())
|
||||
{
|
||||
error!(?e);
|
||||
}
|
||||
let task = Task::future(self.db.acquire())
|
||||
.map_err(|e| {
|
||||
miette::miette!("Database error: {e}")
|
||||
})
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_image_to_db(
|
||||
image.clone(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
res.map(|_| {
|
||||
Message::OpenItem(Some((
|
||||
LibraryKind::Image,
|
||||
index as i32,
|
||||
)))
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|r| r.unwrap_or(Message::None));
|
||||
tasks.push(task);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
let after_task =
|
||||
Task::done(Message::OpenItem(Some((
|
||||
LibraryKind::Image,
|
||||
self.image_library.items.len() as i32 - 1,
|
||||
))));
|
||||
if let Some(new_images) = images {
|
||||
let current_images =
|
||||
self.image_library.items.drain(..).collect();
|
||||
let task = Task::perform(
|
||||
images::add_to_db(
|
||||
new_images,
|
||||
current_images,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|images| {
|
||||
Message::ReaddImages(images)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
);
|
||||
tasks.push(task);
|
||||
}
|
||||
return Action::Task(
|
||||
Task::batch(tasks).chain(after_task),
|
||||
);
|
||||
|
|
@ -475,11 +440,17 @@ impl<'a> Library {
|
|||
error!("Not editing a song item");
|
||||
return Action::None;
|
||||
}
|
||||
let songs =
|
||||
self.song_library.items.drain(..).collect();
|
||||
|
||||
return Action::Task(Task::perform(
|
||||
self.song_library.update_song(song, &self.db),
|
||||
songs::update_in_db(
|
||||
song,
|
||||
songs,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
|r| {
|
||||
r.map(|_| Message::SongChanged)
|
||||
r.map(|songs| Message::ReaddSongs(songs))
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
));
|
||||
|
|
@ -488,6 +459,9 @@ impl<'a> Library {
|
|||
// self.song_library.update_item(song, index);
|
||||
debug!("song changed");
|
||||
}
|
||||
Message::ReaddImages(images) => {
|
||||
self.image_library.items = images;
|
||||
}
|
||||
Message::UpdateImage(image) => {
|
||||
let Some((kind, index)) = self.editing_item else {
|
||||
error!("Not editing an item");
|
||||
|
|
@ -498,16 +472,25 @@ impl<'a> Library {
|
|||
error!("Not editing a image item");
|
||||
return Action::None;
|
||||
}
|
||||
let images =
|
||||
self.image_library.items.drain(..).collect();
|
||||
|
||||
return Action::Task(Task::perform(
|
||||
self.image_library.update_image(image, &self.db),
|
||||
images::update_in_db(
|
||||
image,
|
||||
images,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
|r| {
|
||||
r.map(|_| Message::ImageChanged)
|
||||
r.map(|images| Message::ReaddImages(images))
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
));
|
||||
}
|
||||
Message::ImageChanged => (),
|
||||
Message::ReaddVideos(videos) => {
|
||||
self.video_library.items = videos;
|
||||
}
|
||||
Message::UpdateVideo(video) => {
|
||||
let Some((kind, index)) = self.editing_item else {
|
||||
error!("Not editing an item");
|
||||
|
|
@ -519,15 +502,25 @@ impl<'a> Library {
|
|||
return Action::None;
|
||||
}
|
||||
|
||||
let videos =
|
||||
self.video_library.items.drain(..).collect();
|
||||
|
||||
return Action::Task(Task::perform(
|
||||
self.video_library.update_video(video, &self.db),
|
||||
videos::update_in_db(
|
||||
video,
|
||||
videos,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
|r| {
|
||||
r.map(|_| Message::VideoChanged)
|
||||
r.map(|videos| Message::ReaddVideos(videos))
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
));
|
||||
}
|
||||
Message::VideoChanged => debug!("vid shoulda changed"),
|
||||
Message::ReaddPres(presentations) => {
|
||||
self.presentation_library.items = presentations;
|
||||
}
|
||||
Message::UpdatePresentation(presentation) => {
|
||||
let Some((kind, _index)) = self.editing_item else {
|
||||
error!("Not editing an item");
|
||||
|
|
@ -539,12 +532,23 @@ impl<'a> Library {
|
|||
return Action::None;
|
||||
}
|
||||
|
||||
let presentations = self
|
||||
.presentation_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
|
||||
return Action::Task(Task::perform(
|
||||
self.presentation_library
|
||||
.update_presentation(presentation, &self.db),
|
||||
presentations::update_in_db(
|
||||
presentation,
|
||||
presentations,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
|r| {
|
||||
r.map(|_| Message::PresentationChanged)
|
||||
.unwrap_or(Message::None)
|
||||
r.map(|presentations| {
|
||||
Message::ReaddPres(presentations)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
));
|
||||
}
|
||||
|
|
@ -627,29 +631,26 @@ impl<'a> Library {
|
|||
.add_item(video.clone())
|
||||
.err()
|
||||
else {
|
||||
let task =
|
||||
Task::future(self.db.acquire())
|
||||
.map_err(|e| {
|
||||
miette::miette!(
|
||||
"Database error: {e}"
|
||||
let videos = self
|
||||
.video_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
let task = Task::perform(
|
||||
videos::add_to_db(
|
||||
vec![video.clone()],
|
||||
videos,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|videos| {
|
||||
Message::ReaddVideos(
|
||||
videos,
|
||||
)
|
||||
})
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_video_to_db(
|
||||
video.clone(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
res.map(|_| {
|
||||
Message::None
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|r| {
|
||||
r.unwrap_or(Message::None)
|
||||
});
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
);
|
||||
tasks.push(task);
|
||||
continue;
|
||||
};
|
||||
|
|
@ -661,29 +662,26 @@ impl<'a> Library {
|
|||
.add_item(image.clone())
|
||||
.err()
|
||||
else {
|
||||
let task =
|
||||
Task::future(self.db.acquire())
|
||||
.map_err(|e| {
|
||||
miette::miette!(
|
||||
"Database error: {e}"
|
||||
let images = self
|
||||
.image_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
let task = Task::perform(
|
||||
images::add_to_db(
|
||||
vec![image.clone()],
|
||||
images,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|images| {
|
||||
Message::ReaddImages(
|
||||
images,
|
||||
)
|
||||
})
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_image_to_db(
|
||||
image.clone(),
|
||||
db,
|
||||
),
|
||||
move |res| {
|
||||
res.map(|_| {
|
||||
Message::None
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|r| {
|
||||
r.unwrap_or(Message::None)
|
||||
});
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
);
|
||||
tasks.push(task);
|
||||
continue;
|
||||
};
|
||||
|
|
@ -697,33 +695,27 @@ impl<'a> Library {
|
|||
.add_item(presentation.clone())
|
||||
.err()
|
||||
else {
|
||||
let task =
|
||||
Task::future(self.db.acquire())
|
||||
.map_err(|e| {
|
||||
miette::miette!(
|
||||
"Database error: {e}"
|
||||
let presentations = self
|
||||
.presentation_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
let task = Task::perform(
|
||||
presentations::add_to_db(
|
||||
vec![presentation.clone()],
|
||||
presentations,
|
||||
Arc::clone(&self.db),
|
||||
),
|
||||
move |res| {
|
||||
res.map(|presentations| {
|
||||
Message::ReaddPres(
|
||||
presentations,
|
||||
)
|
||||
})
|
||||
.and_then(move |db| {
|
||||
Task::perform(
|
||||
add_presentation_to_db(
|
||||
presentation.clone(),
|
||||
db,
|
||||
),
|
||||
{
|
||||
move |res| {
|
||||
res.map(|_| {
|
||||
Message::None
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
})
|
||||
.map(|r| {
|
||||
r.unwrap_or(Message::None)
|
||||
});
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
);
|
||||
tasks.push(task);
|
||||
|
||||
continue;
|
||||
};
|
||||
error!(?e);
|
||||
|
|
@ -1234,6 +1226,7 @@ impl<'a> Library {
|
|||
if let Some(song) =
|
||||
self.song_library.get_item(*index)
|
||||
{
|
||||
let song = song.clone();
|
||||
let songs = self
|
||||
.song_library
|
||||
.items
|
||||
|
|
@ -1263,17 +1256,25 @@ impl<'a> Library {
|
|||
if let Some(video) =
|
||||
self.video_library.get_item(*index)
|
||||
{
|
||||
let video = video.clone();
|
||||
let videos = self
|
||||
.video_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
Task::perform(
|
||||
self.video_library
|
||||
.remove_video(video.id, &self.db),
|
||||
videos::remove_from_db(
|
||||
Arc::clone(&self.db),
|
||||
videos,
|
||||
video.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
r.map(|videos| {
|
||||
Message::ReaddVideos(videos)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
)
|
||||
.map(|m| Ok(m))
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
|
|
@ -1282,21 +1283,25 @@ impl<'a> Library {
|
|||
if let Some(image) =
|
||||
self.image_library.get_item(*index)
|
||||
{
|
||||
debug!(
|
||||
image.id,
|
||||
image.title, "let's remove this image",
|
||||
);
|
||||
let image = image.clone();
|
||||
let images = self
|
||||
.image_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
Task::perform(
|
||||
self.image_library
|
||||
.remove_image(image.id, &self.db),
|
||||
images::remove_from_db(
|
||||
Arc::clone(&self.db),
|
||||
images,
|
||||
image.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
r.map(|images| {
|
||||
Message::ReaddImages(images)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
)
|
||||
.map(|m| Ok(m))
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
|
|
@ -1305,30 +1310,30 @@ impl<'a> Library {
|
|||
if let Some(presentation) =
|
||||
self.presentation_library.get_item(*index)
|
||||
{
|
||||
let presentation = presentation.clone();
|
||||
let presentations = self
|
||||
.presentation_library
|
||||
.items
|
||||
.drain(..)
|
||||
.collect();
|
||||
Task::perform(
|
||||
self.presentation_library
|
||||
.remove_presentation(
|
||||
presentation.id,
|
||||
&self.db,
|
||||
),
|
||||
presentations::remove_from_db(
|
||||
Arc::clone(&self.db),
|
||||
presentations,
|
||||
presentation.id,
|
||||
),
|
||||
|r| {
|
||||
if let Err(e) = r {
|
||||
error!(?e);
|
||||
}
|
||||
Message::None
|
||||
r.map(|presentations| {
|
||||
Message::ReaddPres(presentations)
|
||||
})
|
||||
.unwrap_or(Message::None)
|
||||
},
|
||||
)
|
||||
.map(|m| Ok(m))
|
||||
} else {
|
||||
Task::none()
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|t| {
|
||||
t.map(
|
||||
|r| if let Ok(r) = r { r } else { Message::None },
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
if !tasks.is_empty() {
|
||||
self.selected_items = None;
|
||||
|
|
@ -1428,9 +1433,3 @@ pub fn elide_text(text: impl AsRef<str>, width: f32) -> String {
|
|||
text
|
||||
}
|
||||
}
|
||||
| ||||