adding the beginning of a better verse editor for clarity
Some checks failed
/ test (push) Has been cancelled
Some checks failed
/ test (push) Has been cancelled
This commit is contained in:
parent
a08be9ee0d
commit
a8027ec7b9
4 changed files with 169 additions and 24 deletions
|
|
@ -115,6 +115,22 @@ impl Verse {
|
|||
Verse::Other { lyric, .. } => lyric.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_lyrics(&mut self, lyrics: String) {
|
||||
match self {
|
||||
Verse::Verse { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::PreChorus { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::Chorus { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::PostChorus { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::Bridge { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::Intro { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::Outro { number: _, lyric } => *lyric = lyrics,
|
||||
Verse::Instrumental { number: _, lyric } => {
|
||||
*lyric = lyrics
|
||||
}
|
||||
Verse::Other { number: _, lyric } => *lyric = lyrics,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Verse {
|
||||
|
|
@ -784,6 +800,14 @@ impl Song {
|
|||
Err(miette!("There are no lyrics"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_verse(&mut self, index: usize, verse: Verse) {
|
||||
if let Some(verses) = self.verses.as_mut() {
|
||||
if let Some(old_verse) = verses.get_mut(index) {
|
||||
*old_verse = verse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
// pub mod slide_text;
|
||||
pub mod draggable;
|
||||
pub mod verse_editor;
|
||||
|
|
|
|||
81
src/ui/widgets/verse_editor.rs
Normal file
81
src/ui/widgets/verse_editor.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue