making song_editor actually function

This commit is contained in:
Chris Cochrun 2025-09-19 09:16:11 -05:00
parent 7d8c2243d8
commit 2222a88470
2 changed files with 81 additions and 68 deletions

View file

@ -8,11 +8,12 @@ use cosmic::{
Font, Length, Font, Length,
}, },
iced_wgpu::graphics::text::cosmic_text::fontdb, iced_wgpu::graphics::text::cosmic_text::fontdb,
iced_widget::row, iced_widget::{column, row},
theme, theme,
widget::{ widget::{
button, column, combo_box, container, horizontal_space, icon, button, combo_box, container, horizontal_space, icon,
scrollable, text, text_editor, text_input, progress_bar, scrollable, text, text_editor, text_input,
vertical_space,
}, },
Element, Task, Element, Task,
}; };
@ -21,7 +22,7 @@ use iced_video_player::Video;
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
use crate::{ use crate::{
core::{service_items::ServiceTrait, songs::Song}, core::{service_items::ServiceTrait, slide::Slide, songs::Song},
ui::{ ui::{
presenter::slide_view, slide_editor::SlideEditor, text_svg, presenter::slide_view, slide_editor::SlideEditor, text_svg,
}, },
@ -47,6 +48,7 @@ pub struct SongEditor {
video: Option<Video>, video: Option<Video>,
current_font: Font, current_font: Font,
ccli: String, ccli: String,
song_as_slide: Option<Vec<Slide>>,
slide_state: SlideEditor, slide_state: SlideEditor,
} }
@ -70,6 +72,7 @@ pub enum Message {
Edit(bool), Edit(bool),
None, None,
ChangeAuthor(String), ChangeAuthor(String),
PauseVideo,
} }
impl SongEditor { impl SongEditor {
@ -80,8 +83,7 @@ impl SongEditor {
.faces() .faces()
.map(|f| { .map(|f| {
let id = f.id; let id = f.id;
let font_base_name: String = let font_base_name: String = f.families[0].0.clone();
f.families.iter().map(|f| f.0.clone()).collect();
let font_weight = f.weight; let font_weight = f.weight;
let font_style = f.style; let font_style = f.style;
let font_stretch = f.stretch; let font_stretch = f.stretch;
@ -114,18 +116,30 @@ impl SongEditor {
"65".to_string(), "65".to_string(),
"70".to_string(), "70".to_string(),
"80".to_string(), "80".to_string(),
"90".to_string(),
"100".to_string(),
"110".to_string(),
"120".to_string(),
"130".to_string(),
"140".to_string(),
"150".to_string(),
"160".to_string(),
"170".to_string(),
]; ];
let font_texts = fonts.iter().map(|f| f.1.clone()).collect(); let mut font_texts: Vec<String> =
fonts.iter().map(|f| f.1.to_string()).collect();
font_texts.dedup();
font_texts.sort();
Self { Self {
song: None, song: None,
font_db, font_db,
fonts, fonts,
fonts_combo: combo_box::State::new(font_texts), fonts_combo: combo_box::State::new(font_texts),
title: "Death was Arrested".to_owned(), title: "Death was Arrested".to_string(),
font: "Quicksand".to_owned(), font: "Quicksand".to_string(),
font_size: 16, font_size: 16,
font_sizes: combo_box::State::new(font_sizes), font_sizes: combo_box::State::new(font_sizes),
verse_order: "Death was Arrested".to_owned(), verse_order: "Death was Arrested".to_string(),
lyrics: text_editor::Content::new(), lyrics: text_editor::Content::new(),
editing: false, editing: false,
author: "North Point Worship".into(), author: "North Point Worship".into(),
@ -133,8 +147,9 @@ impl SongEditor {
background: None, background: None,
video: None, video: None,
current_font: cosmic::font::default(), current_font: cosmic::font::default(),
ccli: "8".to_owned(), ccli: "8".to_string(),
slide_state: SlideEditor::default(), slide_state: SlideEditor::default(),
song_as_slide: None,
} }
} }
pub fn update(&mut self, message: Message) -> Action { pub fn update(&mut self, message: Message) -> Action {
@ -174,33 +189,12 @@ impl SongEditor {
self.background = song.background; self.background = song.background;
} }
Message::ChangeFont(font) => { Message::ChangeFont(font) => {
let font_id = self
.fonts
.iter()
.filter(|f| f.1 == font)
.map(|f| f.0)
.next();
if let Some(id) = font_id
&& let Some(face) = self.font_db.face(id)
{
self.font = face.post_script_name.clone();
// self.current_font = Font::from(face);
}
self.font = font.clone(); self.font = font.clone();
if let Some(song) = &mut self.song {
let font_name = font.into_boxed_str(); song.font = Some(font);
let family = Family::Name(Box::leak(font_name)); let song = song.to_owned();
let weight = Weight::Bold; return self.update_song(song);
let stretch = Stretch::Normal; }
let style = Style::Normal;
let font = Font {
family,
weight,
stretch,
style,
};
self.current_font = font;
// return self.update_song(song);
} }
Message::ChangeFontSize(size) => { Message::ChangeFontSize(size) => {
self.font_size = size; self.font_size = size;
@ -269,25 +263,55 @@ impl SongEditor {
Message::ChangeBackground, Message::ChangeBackground,
)); ));
} }
Message::PauseVideo => {
if let Some(video) = &mut self.video {
let paused = video.paused();
video.set_paused(!paused);
};
}
_ => (), _ => (),
} }
Action::None Action::None
} }
pub fn view(&self) -> Element<Message> { pub fn view(&self) -> Element<Message> {
let video_elements = if let Some(video) = &self.video {
let play_button = button::icon(if video.paused() {
icon::from_name("media-playback-start")
} else {
icon::from_name("media-playback-pause")
})
.on_press(Message::PauseVideo);
let video_track = progress_bar(
0.0..=video.duration().as_secs_f32(),
video.position().as_secs_f32(),
)
.height(cosmic::theme::spacing().space_s)
.width(Length::Fill);
container(
row![play_button, video_track]
.align_y(Vertical::Center)
.spacing(cosmic::theme::spacing().space_m),
)
.padding(cosmic::theme::spacing().space_s)
.center_x(Length::FillPortion(2))
} else {
container(vertical_space())
};
let slide_preview = container(self.slide_preview()) let slide_preview = container(self.slide_preview())
.width(Length::FillPortion(2)); .width(Length::FillPortion(2));
let column = column::with_children(vec![ let slide_section = column![video_elements, slide_preview]
.spacing(cosmic::theme::spacing().space_s);
let column = column![
self.toolbar(), self.toolbar(),
row![ row![
container(self.left_column()) container(self.left_column())
.center_x(Length::FillPortion(2)), .center_x(Length::FillPortion(2)),
container(slide_preview) container(slide_section)
.center_x(Length::FillPortion(3)) .center_x(Length::FillPortion(2))
] ],
.into(), ]
])
.spacing(theme::active().cosmic().space_l()); .spacing(theme::active().cosmic().space_l());
column.into() column.into()
} }
@ -324,7 +348,7 @@ impl SongEditor {
}) })
.collect(); .collect();
scrollable( scrollable(
column::with_children(slides) cosmic::widget::column::with_children(slides)
.spacing(theme::active().cosmic().space_l()), .spacing(theme::active().cosmic().space_l()),
) )
.height(Length::Fill) .height(Length::Fill)
@ -359,37 +383,26 @@ order",
.on_input(Message::ChangeVerseOrder); .on_input(Message::ChangeVerseOrder);
let lyric_title = text("Lyrics"); let lyric_title = text("Lyrics");
let lyric_input = column::with_children(vec![ let lyric_input = column![
lyric_title.into(), lyric_title,
text_editor(&self.lyrics) text_editor(&self.lyrics)
.on_action(Message::ChangeLyrics) .on_action(Message::ChangeLyrics)
.height(Length::Fill) .height(Length::Fill)
.into(), ]
])
.spacing(5); .spacing(5);
column::with_children(vec![ column![title_input, author_input, verse_input, lyric_input,]
title_input.into(), .spacing(25)
author_input.into(), .width(Length::FillPortion(2))
verse_input.into(), .into()
lyric_input.into(),
])
.spacing(25)
.width(Length::FillPortion(2))
.into()
} }
fn toolbar(&self) -> Element<Message> { fn toolbar(&self) -> Element<Message> {
let selected_font = &self.font; let selected_font = &self.font;
let selected_font_size = { let selected_font_size = if self.font_size > 0 {
let font_size_position = self Some(&self.font_size.to_string())
.font_sizes } else {
.options() None
.iter()
.position(|s| *s == self.font_size.to_string());
self.font_sizes
.options()
.get(font_size_position.unwrap_or_default())
}; };
let font_selector = combo_box( let font_selector = combo_box(
&self.fonts_combo, &self.fonts_combo,

View file

@ -249,7 +249,7 @@ impl TextSvg {
} }
pub fn build(mut self) -> Self { pub fn build(mut self) -> Self {
debug!("starting..."); // debug!("starting...");
let mut path = dirs::data_local_dir().unwrap(); let mut path = dirs::data_local_dir().unwrap();
path.push(PathBuf::from("lumina")); path.push(PathBuf::from("lumina"));
@ -312,7 +312,7 @@ impl TextSvg {
path.set_extension("png"); path.set_extension("png");
if path.exists() { if path.exists() {
debug!("cached"); // debug!("cached");
let handle = Handle::from_path(path); let handle = Handle::from_path(path);
self.handle = Some(handle); self.handle = Some(handle);
return self; return self;