updating the core for actual builds and working tests
This commit is contained in:
parent
e82a9c161b
commit
a94ad65914
|
@ -1,11 +1,13 @@
|
||||||
use super::model::Model;
|
use super::model::Model;
|
||||||
use miette::{Result, miette, IntoDiagnostic};
|
use miette::{miette, IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{query_as, SqliteConnection};
|
use sqlx::{query_as, SqliteConnection};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -26,12 +28,17 @@ impl Model<Image> {
|
||||||
let _ = self.add_item(image);
|
let _ = self.add_item(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("There was an error in converting images: {e}"),
|
Err(e) => {
|
||||||
|
error!("There was an error in converting images: {e}")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_image_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Image> {
|
pub async fn get_image_from_db(
|
||||||
|
database_id: i32,
|
||||||
|
db: &mut SqliteConnection,
|
||||||
|
) -> Result<Image> {
|
||||||
Ok(query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
|
Ok(query_as!(Image, r#"SELECT title as "title!", file_path as "path!", id as "id: i32" from images where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +59,7 @@ mod test {
|
||||||
pub async fn test_db_and_model() {
|
pub async fn test_db_and_model() {
|
||||||
let mut image_model: Model<Image> = Model {
|
let mut image_model: Model<Image> = Model {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
db: crate::core::model::get_db().await
|
db: crate::core::model::get_db().await,
|
||||||
};
|
};
|
||||||
image_model.load_from_db().await;
|
image_model.load_from_db().await;
|
||||||
dbg!(&image_model.items);
|
dbg!(&image_model.items);
|
||||||
|
@ -70,16 +77,26 @@ mod test {
|
||||||
let image = test_image("A new image".into());
|
let image = test_image("A new image".into());
|
||||||
let mut image_model: Model<Image> = Model {
|
let mut image_model: Model<Image> = Model {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
db: crate::core::model::get_db().await
|
db: crate::core::model::get_db().await,
|
||||||
};
|
};
|
||||||
let result = image_model.add_item(image.clone());
|
let result = image_model.add_item(image.clone());
|
||||||
let new_image = test_image("A newer image".into());
|
let new_image = test_image("A newer image".into());
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
assert_eq!(&image, image_model.find(|i| i.id == 0).unwrap());
|
assert_eq!(
|
||||||
assert_ne!(&new_image, image_model.find(|i| i.id == 0).unwrap());
|
&image,
|
||||||
|
image_model.find(|i| i.id == 0).unwrap()
|
||||||
|
);
|
||||||
|
assert_ne!(
|
||||||
|
&new_image,
|
||||||
|
image_model.find(|i| i.id == 0).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(e) => assert!(false, "There was an error adding the image: {:?}", e),
|
Err(e) => assert!(
|
||||||
|
false,
|
||||||
|
"There was an error adding the image: {:?}",
|
||||||
|
e
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,9 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::presentations::PresKind;
|
use super::presentations::PresKind;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub enum ServiceItemKind {
|
pub enum ServiceItemKind {
|
||||||
#[default]
|
#[default]
|
||||||
Song,
|
Song,
|
||||||
|
@ -22,7 +24,9 @@ impl std::fmt::Display for ServiceItemKind {
|
||||||
Self::Video => "video".to_owned(),
|
Self::Video => "video".to_owned(),
|
||||||
Self::Presentation(PresKind::Html) => "html".to_owned(),
|
Self::Presentation(PresKind::Html) => "html".to_owned(),
|
||||||
Self::Presentation(PresKind::Pdf) => "pdf".to_owned(),
|
Self::Presentation(PresKind::Pdf) => "pdf".to_owned(),
|
||||||
Self::Presentation(PresKind::Generic) => "presentation".to_owned(),
|
Self::Presentation(PresKind::Generic) => {
|
||||||
|
"presentation".to_owned()
|
||||||
|
}
|
||||||
Self::Content => "content".to_owned(),
|
Self::Content => "content".to_owned(),
|
||||||
};
|
};
|
||||||
write!(f, "{s}")
|
write!(f, "{s}")
|
||||||
|
@ -36,7 +40,9 @@ impl TryFrom<String> for ServiceItemKind {
|
||||||
"song" => Ok(Self::Song),
|
"song" => Ok(Self::Song),
|
||||||
"image" => Ok(Self::Image),
|
"image" => Ok(Self::Image),
|
||||||
"video" => Ok(Self::Video),
|
"video" => Ok(Self::Video),
|
||||||
"presentation" => Ok(Self::Presentation(PresKind::Generic)),
|
"presentation" => {
|
||||||
|
Ok(Self::Presentation(PresKind::Generic))
|
||||||
|
}
|
||||||
"html" => Ok(Self::Presentation(PresKind::Html)),
|
"html" => Ok(Self::Presentation(PresKind::Html)),
|
||||||
"pdf" => Ok(Self::Presentation(PresKind::Pdf)),
|
"pdf" => Ok(Self::Presentation(PresKind::Pdf)),
|
||||||
"content" => Ok(Self::Content),
|
"content" => Ok(Self::Content),
|
||||||
|
@ -51,7 +57,9 @@ impl From<ServiceItemKind> for String {
|
||||||
ServiceItemKind::Song => "song".to_owned(),
|
ServiceItemKind::Song => "song".to_owned(),
|
||||||
ServiceItemKind::Video => "video".to_owned(),
|
ServiceItemKind::Video => "video".to_owned(),
|
||||||
ServiceItemKind::Image => "image".to_owned(),
|
ServiceItemKind::Image => "image".to_owned(),
|
||||||
ServiceItemKind::Presentation(_) => "presentation".to_owned(),
|
ServiceItemKind::Presentation(_) => {
|
||||||
|
"presentation".to_owned()
|
||||||
|
}
|
||||||
ServiceItemKind::Content => "content".to_owned(),
|
ServiceItemKind::Content => "content".to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +73,10 @@ pub enum ParseError {
|
||||||
impl Error for ParseError {}
|
impl Error for ParseError {}
|
||||||
|
|
||||||
impl Display for ParseError {
|
impl Display for ParseError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
let message = match self {
|
let message = match self {
|
||||||
Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'",
|
Self::UnknownType => "The type does not exist. It needs to be one of 'song', 'video', 'image', 'presentation', or 'content'",
|
||||||
};
|
};
|
||||||
|
|
|
@ -142,9 +142,11 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list() {
|
fn test_list() {
|
||||||
let lisp = read_to_string("./test_presentation.lisp").expect("oops");
|
let lisp =
|
||||||
|
read_to_string("./test_presentation.lisp").expect("oops");
|
||||||
println!("{lisp}");
|
println!("{lisp}");
|
||||||
let mut parser = Parser::from_str_custom(&lisp, Options::elisp());
|
let mut parser =
|
||||||
|
Parser::from_str_custom(&lisp, Options::elisp());
|
||||||
for atom in parser.value_iter() {
|
for atom in parser.value_iter() {
|
||||||
match atom {
|
match atom {
|
||||||
Ok(atom) => {
|
Ok(atom) => {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
pub mod images;
|
pub mod images;
|
||||||
pub mod kinds;
|
pub mod kinds;
|
||||||
pub mod lisp;
|
pub mod lisp;
|
||||||
|
pub mod model;
|
||||||
pub mod presentations;
|
pub mod presentations;
|
||||||
pub mod service_items;
|
pub mod service_items;
|
||||||
pub mod slide;
|
pub mod slide;
|
||||||
pub mod songs;
|
pub mod songs;
|
||||||
pub mod videos;
|
pub mod videos;
|
||||||
pub mod model;
|
|
||||||
|
|
|
@ -71,9 +71,7 @@ pub async fn get_db() -> SqliteConnection {
|
||||||
data.push("library-db.sqlite3");
|
data.push("library-db.sqlite3");
|
||||||
let mut db_url = String::from("sqlite://");
|
let mut db_url = String::from("sqlite://");
|
||||||
db_url.push_str(data.to_str().unwrap());
|
db_url.push_str(data.to_str().unwrap());
|
||||||
SqliteConnection::connect(&db_url)
|
SqliteConnection::connect(&db_url).await.expect("problems")
|
||||||
.await
|
|
||||||
.expect("problems")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Modeling {
|
pub trait Modeling {
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
use miette::{miette, Result, IntoDiagnostic};
|
use miette::{miette, IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection};
|
use sqlx::{
|
||||||
|
prelude::FromRow, query, sqlite::SqliteRow, Row, SqliteConnection,
|
||||||
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
use super::model::Model;
|
use super::model::Model;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub enum PresKind {
|
pub enum PresKind {
|
||||||
Html,
|
Html,
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -14,7 +18,9 @@ pub enum PresKind {
|
||||||
Generic,
|
Generic,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct Presentation {
|
pub struct Presentation {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -75,7 +81,9 @@ impl Model<Presentation> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("There was an error in converting presentations: {e}"),
|
Err(e) => error!(
|
||||||
|
"There was an error in converting presentations: {e}"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,10 +122,12 @@ mod test {
|
||||||
async fn test_db_and_model() {
|
async fn test_db_and_model() {
|
||||||
let mut presentation_model: Model<Presentation> = Model {
|
let mut presentation_model: Model<Presentation> = Model {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
db: crate::core::model::get_db().await
|
db: crate::core::model::get_db().await,
|
||||||
};
|
};
|
||||||
presentation_model.load_from_db().await;
|
presentation_model.load_from_db().await;
|
||||||
if let Some(presentation) = presentation_model.find(|p| p.id == 54) {
|
if let Some(presentation) =
|
||||||
|
presentation_model.find(|p| p.id == 54)
|
||||||
|
{
|
||||||
let test_presentation = test_presentation();
|
let test_presentation = test_presentation();
|
||||||
assert_eq!(&test_presentation, presentation);
|
assert_eq!(&test_presentation, presentation);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -52,7 +52,9 @@ impl From<&Image> for ServiceItem {
|
||||||
impl From<&Presentation> for ServiceItem {
|
impl From<&Presentation> for ServiceItem {
|
||||||
fn from(presentation: &Presentation) -> Self {
|
fn from(presentation: &Presentation) -> Self {
|
||||||
Self {
|
Self {
|
||||||
kind: ServiceItemKind::Presentation(presentation.kind.clone()),
|
kind: ServiceItemKind::Presentation(
|
||||||
|
presentation.kind.clone(),
|
||||||
|
),
|
||||||
database_id: presentation.id,
|
database_id: presentation.id,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
@ -60,7 +62,10 @@ impl From<&Presentation> for ServiceItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceItemModel {
|
impl ServiceItemModel {
|
||||||
fn add_item(&mut self, item: impl Into<ServiceItem>) -> Result<()> {
|
fn add_item(
|
||||||
|
&mut self,
|
||||||
|
item: impl Into<ServiceItem>,
|
||||||
|
) -> Result<()> {
|
||||||
let service_item: ServiceItem = item.into();
|
let service_item: ServiceItem = item.into();
|
||||||
self.items.push(service_item);
|
self.items.push(service_item);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -103,7 +108,10 @@ mod test {
|
||||||
let mut service_model = ServiceItemModel::default();
|
let mut service_model = ServiceItemModel::default();
|
||||||
match service_model.add_item(&song) {
|
match service_model.add_item(&song) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
assert_eq!(ServiceItemKind::Song, service_model.items[0].kind);
|
assert_eq!(
|
||||||
|
ServiceItemKind::Song,
|
||||||
|
service_model.items[0].kind
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ServiceItemKind::Presentation(PresKind::Html),
|
ServiceItemKind::Presentation(PresKind::Html),
|
||||||
pres_item.kind
|
pres_item.kind
|
||||||
|
|
|
@ -15,7 +15,9 @@ use crate::core::lisp::Symbol;
|
||||||
|
|
||||||
use super::lisp::get_lists;
|
use super::lisp::get_lists;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub enum TextAlignment {
|
pub enum TextAlignment {
|
||||||
TopLeft,
|
TopLeft,
|
||||||
TopCenter,
|
TopCenter,
|
||||||
|
@ -39,7 +41,9 @@ impl From<Value> for TextAlignment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct Background {
|
pub struct Background {
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
pub kind: BackgroundKind,
|
pub kind: BackgroundKind,
|
||||||
|
@ -113,16 +117,23 @@ pub enum ParseError {
|
||||||
impl std::error::Error for ParseError {}
|
impl std::error::Error for ParseError {}
|
||||||
|
|
||||||
impl Display for ParseError {
|
impl Display for ParseError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(
|
||||||
|
&self,
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
) -> std::fmt::Result {
|
||||||
let message = match self {
|
let message = match self {
|
||||||
Self::NonBackgroundFile => "The file is not a recognized image or video type",
|
Self::NonBackgroundFile => {
|
||||||
|
"The file is not a recognized image or video type"
|
||||||
|
}
|
||||||
Self::DoesNotExist => "This file doesn't exist",
|
Self::DoesNotExist => "This file doesn't exist",
|
||||||
};
|
};
|
||||||
write!(f, "Error: {message}")
|
write!(f, "Error: {message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub enum BackgroundKind {
|
pub enum BackgroundKind {
|
||||||
#[default]
|
#[default]
|
||||||
Image,
|
Image,
|
||||||
|
@ -139,7 +150,9 @@ impl From<String> for BackgroundKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct Slide {
|
pub struct Slide {
|
||||||
id: i32,
|
id: i32,
|
||||||
background: Background,
|
background: Background,
|
||||||
|
@ -170,7 +183,9 @@ impl Slide {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct SlideBuilder {
|
pub struct SlideBuilder {
|
||||||
background: Option<Background>,
|
background: Option<Background>,
|
||||||
text: Option<String>,
|
text: Option<String>,
|
||||||
|
@ -187,7 +202,10 @@ impl SlideBuilder {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn background(mut self, background: PathBuf) -> Result<Self, ParseError> {
|
pub(crate) fn background(
|
||||||
|
mut self,
|
||||||
|
background: PathBuf,
|
||||||
|
) -> Result<Self, ParseError> {
|
||||||
let background = Background::try_from(background)?;
|
let background = Background::try_from(background)?;
|
||||||
let _ = self.background.insert(background);
|
let _ = self.background.insert(background);
|
||||||
Ok(self)
|
Ok(self)
|
||||||
|
@ -208,7 +226,10 @@ impl SlideBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn text_alignment(mut self, text_alignment: TextAlignment) -> Self {
|
pub(crate) fn text_alignment(
|
||||||
|
mut self,
|
||||||
|
text_alignment: TextAlignment,
|
||||||
|
) -> Self {
|
||||||
let _ = self.text_alignment.insert(text_alignment);
|
let _ = self.text_alignment.insert(text_alignment);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -218,12 +239,18 @@ impl SlideBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn video_start_time(mut self, video_start_time: f32) -> Self {
|
pub(crate) fn video_start_time(
|
||||||
|
mut self,
|
||||||
|
video_start_time: f32,
|
||||||
|
) -> Self {
|
||||||
let _ = self.video_start_time.insert(video_start_time);
|
let _ = self.video_start_time.insert(video_start_time);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn video_end_time(mut self, video_end_time: f32) -> Self {
|
pub(crate) fn video_end_time(
|
||||||
|
mut self,
|
||||||
|
video_end_time: f32,
|
||||||
|
) -> Self {
|
||||||
let _ = self.video_end_time.insert(video_end_time);
|
let _ = self.video_end_time.insert(video_end_time);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -281,7 +308,11 @@ impl Image {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_image_bg(atom: &Value, image_map: &mut HashMap<String, String>, map_index: usize) {
|
fn build_image_bg(
|
||||||
|
atom: &Value,
|
||||||
|
image_map: &mut HashMap<String, String>,
|
||||||
|
map_index: usize,
|
||||||
|
) {
|
||||||
// This needs to be the cons that contains (image . ...)
|
// This needs to be the cons that contains (image . ...)
|
||||||
// the image is a symbol and the rest are keywords and other maps
|
// the image is a symbol and the rest are keywords and other maps
|
||||||
if atom.is_symbol() {
|
if atom.is_symbol() {
|
||||||
|
@ -289,7 +320,9 @@ fn build_image_bg(atom: &Value, image_map: &mut HashMap<String, String>, map_ind
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for atom in atom.list_iter().unwrap().map(|a| a.as_cons().unwrap()) {
|
for atom in
|
||||||
|
atom.list_iter().unwrap().map(|a| a.as_cons().unwrap())
|
||||||
|
{
|
||||||
if atom.car() == &Value::Symbol("image".into()) {
|
if atom.car() == &Value::Symbol("image".into()) {
|
||||||
build_image_bg(atom.cdr(), image_map, map_index);
|
build_image_bg(atom.cdr(), image_map, map_index);
|
||||||
} else {
|
} else {
|
||||||
|
@ -345,7 +378,11 @@ fn build_slides(
|
||||||
dbg!(¤t_symbol);
|
dbg!(¤t_symbol);
|
||||||
match value {
|
match value {
|
||||||
Value::Cons(v) => {
|
Value::Cons(v) => {
|
||||||
slide_builder = build_slides(&v, current_symbol.clone(), slide_builder);
|
slide_builder = build_slides(
|
||||||
|
&v,
|
||||||
|
current_symbol.clone(),
|
||||||
|
slide_builder,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Value::Nil => {
|
Value::Nil => {
|
||||||
dbg!(Value::Nil);
|
dbg!(Value::Nil);
|
||||||
|
@ -361,7 +398,8 @@ fn build_slides(
|
||||||
}
|
}
|
||||||
Value::Symbol(symbol) => {
|
Value::Symbol(symbol) => {
|
||||||
dbg!(symbol);
|
dbg!(symbol);
|
||||||
current_symbol = Symbol::from_str(symbol).unwrap_or_default();
|
current_symbol =
|
||||||
|
Symbol::from_str(symbol).unwrap_or_default();
|
||||||
}
|
}
|
||||||
Value::Keyword(keyword) => {
|
Value::Keyword(keyword) => {
|
||||||
dbg!(keyword);
|
dbg!(keyword);
|
||||||
|
@ -399,16 +437,19 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_lexp_serialize() {
|
fn test_lexp_serialize() {
|
||||||
let lisp = read_to_string("./test_presentation.lisp").expect("oops");
|
let lisp =
|
||||||
|
read_to_string("./test_presentation.lisp").expect("oops");
|
||||||
println!("{lisp}");
|
println!("{lisp}");
|
||||||
let mut parser = Parser::from_str_custom(&lisp, Options::elisp());
|
let mut parser =
|
||||||
|
Parser::from_str_custom(&lisp, Options::elisp());
|
||||||
for atom in parser.value_iter() {
|
for atom in parser.value_iter() {
|
||||||
match atom {
|
match atom {
|
||||||
Ok(atom) => {
|
Ok(atom) => {
|
||||||
let symbol = Symbol::None;
|
let symbol = Symbol::None;
|
||||||
let slide_builder = SlideBuilder::new();
|
let slide_builder = SlideBuilder::new();
|
||||||
atom.as_cons()
|
atom.as_cons().map(|c| {
|
||||||
.map(|c| build_slides(c, symbol, slide_builder));
|
build_slides(c, symbol, slide_builder)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
dbg!(e);
|
dbg!(e);
|
||||||
|
@ -432,7 +473,8 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ron_deserialize() {
|
fn test_ron_deserialize() {
|
||||||
let slide = read_to_string("./test_presentation.ron").expect("Problem getting file read");
|
let slide = read_to_string("./test_presentation.ron")
|
||||||
|
.expect("Problem getting file read");
|
||||||
match ron::from_str::<Vec<Slide>>(&slide) {
|
match ron::from_str::<Vec<Slide>>(&slide) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
dbg!(s);
|
dbg!(s);
|
||||||
|
|
|
@ -3,15 +3,20 @@ use std::{collections::HashMap, path::PathBuf};
|
||||||
use cosmic::{executor, iced::Executor};
|
use cosmic::{executor, iced::Executor};
|
||||||
use miette::{miette, IntoDiagnostic, Result};
|
use miette::{miette, IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{query, query_as, sqlite::SqliteRow, FromRow, Row, SqliteConnection};
|
use sqlx::{
|
||||||
|
query, query_as, sqlite::SqliteRow, FromRow, Row,
|
||||||
|
SqliteConnection,
|
||||||
|
};
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
model::{Model},
|
model::Model,
|
||||||
slide::{Background, TextAlignment},
|
slide::{Background, TextAlignment},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct Song {
|
pub struct Song {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -27,9 +32,11 @@ pub struct Song {
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSE_KEYWORDS: [&str; 24] = [
|
const VERSE_KEYWORDS: [&str; 24] = [
|
||||||
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6", "Verse 7", "Verse 8",
|
"Verse 1", "Verse 2", "Verse 3", "Verse 4", "Verse 5", "Verse 6",
|
||||||
"Chorus 1", "Chorus 2", "Chorus 3", "Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4",
|
"Verse 7", "Verse 8", "Chorus 1", "Chorus 2", "Chorus 3",
|
||||||
"Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1", "Other 2", "Other 3", "Other 4",
|
"Chorus 4", "Bridge 1", "Bridge 2", "Bridge 3", "Bridge 4",
|
||||||
|
"Intro 1", "Intro 2", "Ending 1", "Ending 2", "Other 1",
|
||||||
|
"Other 2", "Other 3", "Other 4",
|
||||||
];
|
];
|
||||||
|
|
||||||
impl FromRow<'_, SqliteRow> for Song {
|
impl FromRow<'_, SqliteRow> for Song {
|
||||||
|
@ -54,7 +61,6 @@ impl FromRow<'_, SqliteRow> for Song {
|
||||||
Ok(background) => Some(background),
|
Ok(background) => Some(background),
|
||||||
Err(_) => None,
|
Err(_) => None,
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
text_alignment: Some({
|
text_alignment: Some({
|
||||||
let horizontal_alignment: String = row.try_get(3)?;
|
let horizontal_alignment: String = row.try_get(3)?;
|
||||||
|
@ -67,8 +73,12 @@ impl FromRow<'_, SqliteRow> for Song {
|
||||||
("left", "center") => TextAlignment::MiddleLeft,
|
("left", "center") => TextAlignment::MiddleLeft,
|
||||||
("left", "bottom") => TextAlignment::BottomLeft,
|
("left", "bottom") => TextAlignment::BottomLeft,
|
||||||
("center", "top") => TextAlignment::TopCenter,
|
("center", "top") => TextAlignment::TopCenter,
|
||||||
("center", "center") => TextAlignment::MiddleCenter,
|
("center", "center") => {
|
||||||
("center", "bottom") => TextAlignment::BottomCenter,
|
TextAlignment::MiddleCenter
|
||||||
|
}
|
||||||
|
("center", "bottom") => {
|
||||||
|
TextAlignment::BottomCenter
|
||||||
|
}
|
||||||
("right", "top") => TextAlignment::TopRight,
|
("right", "top") => TextAlignment::TopRight,
|
||||||
("right", "center") => TextAlignment::MiddleRight,
|
("right", "center") => TextAlignment::MiddleRight,
|
||||||
("right", "bottom") => TextAlignment::BottomRight,
|
("right", "bottom") => TextAlignment::BottomRight,
|
||||||
|
@ -81,7 +91,10 @@ impl FromRow<'_, SqliteRow> for Song {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_song_from_db(index: i32, db: &mut SqliteConnection) -> Result<Song> {
|
pub async fn get_song_from_db(
|
||||||
|
index: i32,
|
||||||
|
db: &mut SqliteConnection,
|
||||||
|
) -> Result<Song> {
|
||||||
let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await.into_diagnostic()?;
|
let row = query(r#"SELECT verse_order as "verse_order!", font_size as "font_size!: i32", background_type as "background_type!", horizontal_text_alignment as "horizontal_text_alignment!", vertical_text_alignment as "vertical_text_alignment!", title as "title!", font as "font!", background as "background!", lyrics as "lyrics!", ccli as "ccli!", author as "author!", audio as "audio!", id as "id: i32" from songs where id = $1"#).bind(index).fetch_one(db).await.into_diagnostic()?;
|
||||||
Ok(Song::from_row(&row).into_diagnostic()?)
|
Ok(Song::from_row(&row).into_diagnostic()?)
|
||||||
}
|
}
|
||||||
|
@ -96,14 +109,16 @@ impl Model<Song> {
|
||||||
match Song::from_row(&song) {
|
match Song::from_row(&song) {
|
||||||
Ok(song) => {
|
Ok(song) => {
|
||||||
let _ = self.add_item(song);
|
let _ = self.add_item(song);
|
||||||
},
|
}
|
||||||
Err(e) => error!("Could not convert song: {e}"),
|
Err(e) => {
|
||||||
|
error!("Could not convert song: {e}")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
},
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("There was an error in converting songs: {e}");
|
error!("There was an error in converting songs: {e}");
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +130,11 @@ impl Song {
|
||||||
return Err(miette!("There is no lyrics here"));
|
return Err(miette!("There is no lyrics here"));
|
||||||
} else if self.verse_order.is_none() {
|
} else if self.verse_order.is_none() {
|
||||||
return Err(miette!("There is no verse_order here"));
|
return Err(miette!("There is no verse_order here"));
|
||||||
} else if self.verse_order.clone().is_some_and(|v| v.is_empty()) {
|
} else if self
|
||||||
|
.verse_order
|
||||||
|
.clone()
|
||||||
|
.is_some_and(|v| v.is_empty())
|
||||||
|
{
|
||||||
return Err(miette!("There is no verse_order here"));
|
return Err(miette!("There is no verse_order here"));
|
||||||
}
|
}
|
||||||
if let Some(raw_lyrics) = self.lyrics.clone() {
|
if let Some(raw_lyrics) = self.lyrics.clone() {
|
||||||
|
@ -145,16 +164,21 @@ impl Song {
|
||||||
let mut verse_name = "";
|
let mut verse_name = "";
|
||||||
debug!(verse = verse);
|
debug!(verse = verse);
|
||||||
for word in VERSE_KEYWORDS {
|
for word in VERSE_KEYWORDS {
|
||||||
let end_verse = verse.get(1..2).unwrap_or_default();
|
let end_verse =
|
||||||
let beg_verse = verse.get(0..1).unwrap_or_default();
|
verse.get(1..2).unwrap_or_default();
|
||||||
if word.starts_with(beg_verse) && word.ends_with(end_verse) {
|
let beg_verse =
|
||||||
|
verse.get(0..1).unwrap_or_default();
|
||||||
|
if word.starts_with(beg_verse)
|
||||||
|
&& word.ends_with(end_verse)
|
||||||
|
{
|
||||||
verse_name = word;
|
verse_name = word;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(lyric) = lyric_map.get(verse_name) {
|
if let Some(lyric) = lyric_map.get(verse_name) {
|
||||||
if lyric.contains("\n\n") {
|
if lyric.contains("\n\n") {
|
||||||
let split_lyrics: Vec<&str> = lyric.split("\n\n").collect();
|
let split_lyrics: Vec<&str> =
|
||||||
|
lyric.split("\n\n").collect();
|
||||||
for lyric in split_lyrics {
|
for lyric in split_lyrics {
|
||||||
if lyric.is_empty() {
|
if lyric.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
|
@ -246,11 +270,12 @@ From the day
|
||||||
You saved my soul"
|
You saved my soul"
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
song.verse_order = "O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2"
|
song.verse_order =
|
||||||
.to_string()
|
"O1 V1 C1 C2 O2 V2 C3 C2 O2 B1 C2 C2 E1 O2"
|
||||||
.split(' ')
|
.to_string()
|
||||||
.map(|s| Some(s.to_string()))
|
.split(' ')
|
||||||
.collect();
|
.map(|s| Some(s.to_string()))
|
||||||
|
.collect();
|
||||||
let lyrics = song.get_lyrics();
|
let lyrics = song.get_lyrics();
|
||||||
match lyrics {
|
match lyrics {
|
||||||
Ok(lyrics) => {
|
Ok(lyrics) => {
|
||||||
|
@ -265,7 +290,7 @@ You saved my soul"
|
||||||
async fn model() -> Model<Song> {
|
async fn model() -> Model<Song> {
|
||||||
let song_model: Model<Song> = Model {
|
let song_model: Model<Song> = Model {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
db: crate::core::model::get_db().await
|
db: crate::core::model::get_db().await,
|
||||||
};
|
};
|
||||||
song_model
|
song_model
|
||||||
}
|
}
|
||||||
|
@ -302,7 +327,10 @@ You saved my soul"
|
||||||
song_model.load_from_db().await;
|
song_model.load_from_db().await;
|
||||||
|
|
||||||
match song_model.update_item(song, 2) {
|
match song_model.update_item(song, 2) {
|
||||||
Ok(()) => assert_eq!(&cloned_song, song_model.find(|s| s.id == 7).unwrap()),
|
Ok(()) => assert_eq!(
|
||||||
|
&cloned_song,
|
||||||
|
song_model.find(|s| s.id == 7).unwrap()
|
||||||
|
),
|
||||||
Err(e) => assert!(false, "{e}"),
|
Err(e) => assert!(false, "{e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use super::model::Model;
|
use super::model::Model;
|
||||||
use cosmic::{executor, iced::Executor};
|
use cosmic::{executor, iced::Executor};
|
||||||
use miette::{Result, miette, IntoDiagnostic};
|
use miette::{miette, IntoDiagnostic, Result};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::{query_as, SqliteConnection};
|
use sqlx::{query_as, SqliteConnection};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(
|
||||||
|
Clone, Debug, Default, PartialEq, Serialize, Deserialize,
|
||||||
|
)]
|
||||||
pub struct Video {
|
pub struct Video {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
@ -25,12 +27,17 @@ impl Model<Video> {
|
||||||
let _ = self.add_item(video);
|
let _ = self.add_item(video);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => error!("There was an error in converting videos: {e}"),
|
Err(e) => {
|
||||||
|
error!("There was an error in converting videos: {e}")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_video_from_db(database_id: i32, db: &mut SqliteConnection) -> Result<Video> {
|
pub async fn get_video_from_db(
|
||||||
|
database_id: i32,
|
||||||
|
db: &mut SqliteConnection,
|
||||||
|
) -> Result<Video> {
|
||||||
Ok(query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
|
Ok(query_as!(Video, r#"SELECT title as "title!", file_path as "path!", start_time as "start_time!: f32", end_time as "end_time!: f32", loop as "looping!", id as "id: i32" from videos where id = ?"#, database_id).fetch_one(db).await.into_diagnostic()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +58,7 @@ mod test {
|
||||||
async fn test_db_and_model() {
|
async fn test_db_and_model() {
|
||||||
let mut video_model: Model<Video> = Model {
|
let mut video_model: Model<Video> = Model {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
db: crate::core::model::get_db().await
|
db: crate::core::model::get_db().await,
|
||||||
};
|
};
|
||||||
video_model.load_from_db().await;
|
video_model.load_from_db().await;
|
||||||
if let Some(video) = video_model.find(|v| v.id == 73) {
|
if let Some(video) = video_model.find(|v| v.id == 73) {
|
||||||
|
@ -70,16 +77,26 @@ mod test {
|
||||||
let video = test_video("A new video".into());
|
let video = test_video("A new video".into());
|
||||||
let mut video_model: Model<Video> = Model {
|
let mut video_model: Model<Video> = Model {
|
||||||
items: vec![],
|
items: vec![],
|
||||||
db: crate::core::model::get_db().await
|
db: crate::core::model::get_db().await,
|
||||||
};
|
};
|
||||||
let result = video_model.add_item(video.clone());
|
let result = video_model.add_item(video.clone());
|
||||||
let new_video = test_video("A newer video".into());
|
let new_video = test_video("A newer video".into());
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
assert_eq!(&video, video_model.find(|v| v.id == 0).unwrap());
|
assert_eq!(
|
||||||
assert_ne!(&new_video, video_model.find(|v| v.id == 0).unwrap());
|
&video,
|
||||||
|
video_model.find(|v| v.id == 0).unwrap()
|
||||||
|
);
|
||||||
|
assert_ne!(
|
||||||
|
&new_video,
|
||||||
|
video_model.find(|v| v.id == 0).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(e) => assert!(false, "There was an error adding the video: {:?}", e),
|
Err(e) => assert!(
|
||||||
|
false,
|
||||||
|
"There was an error adding the video: {:?}",
|
||||||
|
e
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue