updating verse_names many times and styling of text_editors
Some checks are pending
/ test (push) Waiting to run

This commit is contained in:
Chris Cochrun 2026-02-04 15:01:01 -06:00
parent ca69112d6d
commit 6c623eadcc
3 changed files with 208 additions and 15 deletions

View file

@ -76,6 +76,70 @@ pub enum VerseName {
}
impl VerseName {
pub fn from_string(name: String) -> Self {
match name.as_str() {
"Verse" => Self::Verse { number: 1 },
"Pre-Chorus" => Self::PreChorus { number: 1 },
"Chorus" => Self::Chorus { number: 1 },
"Post-Chorus" => Self::PostChorus { number: 1 },
"Bridge" => Self::Bridge { number: 1 },
"Intro" => Self::Intro { number: 1 },
"Outro" => Self::Outro { number: 1 },
"Instrumental" => Self::Instrumental { number: 1 },
"Other" => Self::Other { number: 1 },
"Blank" => Self::Blank,
_ => Self::Blank,
}
}
pub fn all_names() -> Vec<String> {
vec![
"Verse".into(),
"Pre-Chorus".into(),
"Chorus".into(),
"Post-Chorus".into(),
"Bridge".into(),
"Intro".into(),
"Outro".into(),
"Instrumental".into(),
"Other".into(),
"Blank".into(),
]
}
pub fn next(&self) -> Self {
match self {
Self::Verse { number } => {
Self::Verse { number: number + 1 }
}
Self::PreChorus { number } => {
Self::PreChorus { number: number + 1 }
}
Self::Chorus { number } => {
Self::Chorus { number: number + 1 }
}
Self::PostChorus { number } => {
Self::PostChorus { number: number + 1 }
}
Self::Bridge { number } => {
Self::Bridge { number: number + 1 }
}
Self::Intro { number } => {
Self::Intro { number: number + 1 }
}
Self::Outro { number } => {
Self::Outro { number: number + 1 }
}
Self::Instrumental { number } => {
Self::Instrumental { number: number + 1 }
}
Self::Other { number } => {
Self::Other { number: number + 1 }
}
Self::Blank => Self::Blank,
}
}
#[must_use]
pub fn get_name(&self) -> String {
match self {
@ -1037,11 +1101,10 @@ impl Song {
VerseName::Bridge { number: 1 }
} else {
if let Some(last_verse) = verses.iter().last()
&& let VerseName::Verse { number } = last_verse {
return VerseName::Verse {
number: number + 1,
};
}
&& let VerseName::Verse { number } = last_verse
{
return VerseName::Verse { number: number + 1 };
}
VerseName::Verse { number: 1 }
}
} else {
@ -1062,6 +1125,40 @@ impl Song {
self.verses = Some(vec![verse]);
};
}
pub(crate) fn verse_name_from_str(
&self,
verse_name: String, // chorus 2
old_verse_name: VerseName, // v4
) -> VerseName {
if old_verse_name.get_name() == verse_name {
return old_verse_name;
};
if let Some(verses) =
self.verse_map.clone().map(|verse_map| {
verse_map.into_keys().collect::<Vec<VerseName>>()
})
{
verses
.into_iter()
.filter(|verse| {
verse
.get_name()
.split_whitespace()
.next()
.unwrap()
== &verse_name
})
.sorted()
.last()
.map_or_else(
|| VerseName::from_string(verse_name),
|verse_name| verse_name.next(),
)
} else {
VerseName::from_string(verse_name)
}
}
}
#[cfg(test)]

View file

@ -441,6 +441,25 @@ impl SongEditor {
},
));
}
verse_editor::Action::UpdateVerseName(
verse_name,
) => {
if let Some(mut song) = self.song.clone()
{
let verse_name = song
.verse_name_from_str(
verse_name,
verse.verse_name.clone(),
);
let lyric = verse.lyric.clone();
song.update_verse(
index, verse_name, lyric,
);
return self.update_song(song);
}
}
verse_editor::Action::UpdateVerse(verse) => {
if let Some(mut song) = self.song.clone()
{

View file

@ -1,28 +1,38 @@
use cosmic::{
Element, Task,
iced_widget::column,
cosmic_theme::palette::WithAlpha,
iced::{Background, Border, Color},
iced_widget::{column, row},
theme,
widget::{container, text, text_editor},
widget::{
button, combo_box, container, horizontal_space, icon, text,
text_editor, text_input,
},
};
use crate::core::songs::VerseName;
#[derive(Debug)]
pub struct VerseEditor {
verse_name: VerseName,
lyric: String,
pub verse_name: VerseName,
pub lyric: String,
content: text_editor::Content,
editing_verse_name: bool,
verse_name_combo: combo_box::State<String>,
}
#[derive(Debug, Clone)]
pub enum Message {
ChangeText(text_editor::Action),
UpdateLyric(text_editor::Action),
UpdateVerseName(String),
EditVerseName,
None,
}
pub enum Action {
Task(Task<Message>),
UpdateVerse((VerseName, String)),
UpdateVerseName(String),
None,
}
@ -33,31 +43,98 @@ impl VerseEditor {
verse_name: verse,
lyric: lyric.clone(),
content: text_editor::Content::with_text(&lyric),
editing_verse_name: false,
verse_name_combo: combo_box::State::new(
VerseName::all_names(),
),
}
}
pub fn update(&mut self, message: Message) -> Action {
match message {
Message::ChangeText(action) => {
Message::UpdateLyric(action) => {
self.content.perform(action);
let lyrics = self.content.text();
self.lyric = lyrics.clone();
let verse = self.verse_name;
Action::UpdateVerse((verse, lyrics))
}
Message::UpdateVerseName(verse_name) => {
Action::UpdateVerseName(verse_name)
}
Message::EditVerseName => {
self.editing_verse_name = !self.editing_verse_name;
Action::None
}
Message::None => Action::None,
}
}
pub fn view(&self) -> Element<Message> {
let cosmic::cosmic_theme::Spacing {
space_s, space_m, ..
space_xxs,
space_s,
space_m,
..
} = theme::spacing();
let delete_button = button::text("Delete")
.trailing_icon(icon::from_name("view-close"))
.class(theme::Button::Destructive)
.on_press(Message::None);
let combo = combo_box(
&self.verse_name_combo,
"Verse 1",
Some(&self.verse_name.get_name()),
Message::UpdateVerseName,
);
let verse_title =
text::heading(self.verse_name.get_name()).size(space_m);
row![combo, horizontal_space(), delete_button];
let lyric = text_editor(&self.content)
.on_action(Message::ChangeText)
.padding(space_s)
.on_action(Message::UpdateLyric)
.padding(space_m)
.class(cosmic::theme::iced::TextEditor::Custom(Box::new(
move |t, s| {
let neutral = t.cosmic().palette.neutral_9;
let mut base_style = text_editor::Style {
background: Background::Color(
t.cosmic()
.background
.small_widget
.with_alpha(0.25)
.into(),
),
border: Border::default()
.rounded(space_s)
.width(2)
.color(t.cosmic().bg_component_divider()),
icon: t
.cosmic()
.primary_component_color()
.into(),
placeholder: neutral.with_alpha(0.7).into(),
value: neutral.into(),
selection: t.cosmic().accent.base.into(),
};
let hovered_border = Border::default()
.rounded(space_s)
.width(3)
.color(t.cosmic().accent.hover);
match s {
text_editor::Status::Active => base_style,
text_editor::Status::Hovered => {
base_style.border = hovered_border;
base_style
}
text_editor::Status::Focused => {
base_style.border = hovered_border;
base_style
}
text_editor::Status::Disabled => base_style,
}
},
)))
// .style(|theme, status| {
// let mut style =
// text_editor::default(theme, status);