adding the beginning of a better verse editor for clarity
Some checks failed
/ test (push) Has been cancelled

This commit is contained in:
Chris Cochrun 2026-01-13 15:23:21 -06:00
parent a08be9ee0d
commit a8027ec7b9
4 changed files with 169 additions and 24 deletions

View file

@ -26,7 +26,10 @@ use crate::{
songs::{Song, Verse},
},
ui::{
presenter::slide_view, slide_editor::SlideEditor, text_svg,
presenter::slide_view,
slide_editor::SlideEditor,
text_svg,
widgets::verse_editor::{self, VerseEditor},
},
};
@ -52,6 +55,7 @@ pub struct SongEditor {
stroke_sizes: combo_box::State<i32>,
stroke_size: i32,
stroke_open: bool,
verses: Option<Vec<VerseEditor>>,
}
pub enum Action {
@ -79,6 +83,7 @@ pub enum Message {
UpdateStrokeSize(i32),
OpenStroke,
CloseStroke,
VerseEditorMessage((usize, verse_editor::Message)),
}
impl SongEditor {
@ -144,6 +149,7 @@ impl SongEditor {
stroke_sizes: combo_box::State::new(stroke_sizes),
stroke_size: 0,
stroke_open: false,
verses: None,
}
}
pub fn update(&mut self, message: Message) -> Action {
@ -202,6 +208,11 @@ impl SongEditor {
},
|slides| Message::UpdateSlides(slides),
);
self.verses = song.verses.map(|vec| {
vec.into_iter()
.map(|verse| VerseEditor::new(verse))
.collect()
});
return Action::Task(task);
}
Message::ChangeFont(font) => {
@ -306,7 +317,33 @@ impl SongEditor {
Message::CloseStroke => {
self.stroke_open = false;
}
_ => (),
Message::VerseEditorMessage((index, message)) => {
if let Some(verses) = self.verses.as_mut() {
if let Some(verse) = verses.get_mut(index) {
match verse.update(message) {
verse_editor::Action::Task(task) => {
return Action::Task(task.map(
move |m| {
Message::VerseEditorMessage((
index, m,
))
},
));
}
verse_editor::Action::UpdateVerse(
verse,
) => {
if let Some(song) = self.song.as_mut()
{
song.update_verse(index, verse);
}
}
verse_editor::Action::None => (),
}
}
}
}
Message::None => (),
}
Action::None
}
@ -395,6 +432,17 @@ impl SongEditor {
}
fn left_column(&self) -> Element<Message> {
let cosmic::cosmic_theme::Spacing {
space_xxs,
space_xs,
space_s,
space_m,
space_l,
space_xl,
space_xxl,
..
} = theme::spacing();
let title_input = text_input("song", &self.title)
.on_input(Message::ChangeTitle)
.label("Song Title");
@ -420,22 +468,19 @@ order",
]
.spacing(5);
let verse_list = self.song.clone().map(|song| {
if let Some(verses) = song.verses.map(|verses| {
verses
.iter()
.map(|verse| text(verse.get_name()))
.collect()
}) {
verses
} else {
vec![]
}
});
let verse_list = if let Some(verse_list) = verse_list {
Element::from(row(verse_list
.into_iter()
.map(|v| Element::from(v))))
let verse_list = if let Some(verse_list) = &self.verses {
Element::from(
column(verse_list.into_iter().enumerate().map(
|(index, v)| {
v.view().map(move |message| {
Message::VerseEditorMessage((
index, message,
))
})
},
))
.spacing(space_l),
)
} else {
Element::from(horizontal_space())
};
@ -669,12 +714,6 @@ order",
}
}
fn verses_editor<'a>(verse: Verse) -> Element<'a, Message> {
let verse_title = text(verse.get_name());
let lyric = text(verse.get_lyric());
todo!()
}
impl Default for SongEditor {
fn default() -> Self {
let mut fontdb = fontdb::Database::new();

View file

@ -1,2 +1,3 @@
// pub mod slide_text;
pub mod draggable;
pub mod verse_editor;

View file

@ -0,0 +1,81 @@
use cosmic::{
Apply, Element, Task,
iced::{Length, alignment::Vertical},
iced_widget::{column, row},
theme,
widget::{container, icon, text, text_editor},
};
use crate::core::songs::Verse;
#[derive(Debug)]
pub struct VerseEditor {
verse: Verse,
content: text_editor::Content,
}
#[derive(Debug, Clone)]
pub enum Message {
ChangeText(text_editor::Action),
None,
}
pub enum Action {
Task(Task<Message>),
UpdateVerse(Verse),
None,
}
impl VerseEditor {
pub fn new(verse: Verse) -> Self {
let text = verse.get_lyric();
Self {
verse,
content: text_editor::Content::with_text(&text),
}
}
pub fn update(&mut self, message: Message) -> Action {
match message {
Message::ChangeText(action) => {
self.content.perform(action);
let lyrics = self.content.text();
self.verse.set_lyrics(lyrics);
let verse = self.verse.clone();
Action::UpdateVerse(verse)
}
Message::None => Action::None,
}
}
pub fn view(&self) -> Element<Message> {
let cosmic::cosmic_theme::Spacing {
space_xxs,
space_xs,
space_s,
space_m,
space_l,
space_xl,
space_xxl,
..
} = theme::spacing();
let verse_title =
text::heading(self.verse.get_name()).size(space_m);
let editor = text_editor(&self.content)
.on_action(Message::ChangeText)
.padding(space_s)
.height(Length::Fill);
let drag_handle = icon::from_name("object-rows")
.prefer_svg(true)
.size(space_xxl);
let row = row![drag_handle, editor]
.spacing(space_s)
.align_y(Vertical::Center);
container(column![verse_title, row].spacing(space_s))
.padding(space_s)
.class(theme::Container::Card)
.into()
}
}