more things, but mostly starting to add library management
Some checks are pending
/ test (push) Waiting to run
Some checks are pending
/ test (push) Waiting to run
This commit is contained in:
parent
3fe77c93e2
commit
645411b59c
13 changed files with 341 additions and 260 deletions
|
|
@ -1,3 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use cosmic::{
|
||||
iced::{
|
||||
alignment::Vertical, clipboard::dnd::DndAction,
|
||||
|
|
@ -7,9 +9,10 @@ use cosmic::{
|
|||
iced_widget::{column, row as rowm, text as textm},
|
||||
theme,
|
||||
widget::{
|
||||
button, container, horizontal_space, icon, mouse_area,
|
||||
responsive, row, scrollable, text, text_input, Container,
|
||||
DndSource, Space, Widget,
|
||||
button, container, context_menu, horizontal_space, icon,
|
||||
menu::{self, Action as MenuAction},
|
||||
mouse_area, responsive, row, scrollable, text, text_input,
|
||||
Container, DndSource, Space,
|
||||
},
|
||||
Element, Task,
|
||||
};
|
||||
|
|
@ -41,6 +44,29 @@ pub(crate) struct Library {
|
|||
pub dragged_item: Option<(LibraryKind, i32)>,
|
||||
editing_item: Option<(LibraryKind, i32)>,
|
||||
db: SqlitePool,
|
||||
menu_keys: std::collections::HashMap<menu::KeyBind, MenuMessage>,
|
||||
context_menu: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Copy)]
|
||||
enum MenuMessage {
|
||||
Delete((LibraryKind, i32)),
|
||||
Open,
|
||||
None,
|
||||
}
|
||||
|
||||
impl MenuAction for MenuMessage {
|
||||
type Message = Message;
|
||||
|
||||
fn message(&self) -> Self::Message {
|
||||
match self {
|
||||
MenuMessage::Delete((kind, index)) => {
|
||||
Message::DeleteItem((*kind, *index))
|
||||
}
|
||||
MenuMessage::Open => todo!(),
|
||||
MenuMessage::None => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum Action {
|
||||
|
|
@ -53,7 +79,7 @@ pub(crate) enum Action {
|
|||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Message {
|
||||
AddItem,
|
||||
RemoveItem,
|
||||
DeleteItem((LibraryKind, i32)),
|
||||
OpenItem(Option<(LibraryKind, i32)>),
|
||||
HoverLibrary(Option<LibraryKind>),
|
||||
OpenLibrary(Option<LibraryKind>),
|
||||
|
|
@ -69,6 +95,7 @@ pub(crate) enum Message {
|
|||
UpdatePresentation(Presentation),
|
||||
PresentationChanged,
|
||||
Error(String),
|
||||
OpenContext(i32),
|
||||
None,
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +117,8 @@ impl<'a> Library {
|
|||
dragged_item: None,
|
||||
editing_item: None,
|
||||
db,
|
||||
menu_keys: HashMap::new(),
|
||||
context_menu: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,7 +130,16 @@ impl<'a> Library {
|
|||
match message {
|
||||
Message::AddItem => (),
|
||||
Message::None => (),
|
||||
Message::RemoveItem => (),
|
||||
Message::DeleteItem((kind, index)) => {
|
||||
match kind {
|
||||
LibraryKind::Song => todo!(),
|
||||
LibraryKind::Video => todo!(),
|
||||
LibraryKind::Image => todo!(),
|
||||
LibraryKind::Presentation => {
|
||||
self.presentation_library.remove_item(index);
|
||||
}
|
||||
};
|
||||
}
|
||||
Message::OpenItem(item) => {
|
||||
debug!(?item);
|
||||
self.editing_item = item;
|
||||
|
|
@ -144,7 +182,7 @@ impl<'a> Library {
|
|||
Task::future(self.db.acquire()).and_then(
|
||||
move |conn| update_in_db(&song, conn),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
|
|
@ -181,7 +219,7 @@ impl<'a> Library {
|
|||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
|
|
@ -215,7 +253,7 @@ impl<'a> Library {
|
|||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
Err(_) => todo!(),
|
||||
}
|
||||
|
|
@ -254,6 +292,9 @@ impl<'a> Library {
|
|||
}
|
||||
Message::PresentationChanged => (),
|
||||
Message::Error(_) => (),
|
||||
Message::OpenContext(index) => {
|
||||
self.context_menu = Some(index);
|
||||
}
|
||||
}
|
||||
Action::None
|
||||
}
|
||||
|
|
@ -264,7 +305,7 @@ impl<'a> Library {
|
|||
let video_library = self.library_item(&self.video_library);
|
||||
let presentation_library =
|
||||
self.library_item(&self.presentation_library);
|
||||
|
||||
|
||||
column![
|
||||
text::heading("Library").center().width(Length::Fill),
|
||||
cosmic::iced::widget::horizontal_rule(1),
|
||||
|
|
@ -374,28 +415,46 @@ impl<'a> Library {
|
|||
let visual_item = self
|
||||
.single_item(index, item, model)
|
||||
.map(|()| Message::None);
|
||||
DndSource::<Message, ServiceItem>::new(
|
||||
mouse_area(visual_item)
|
||||
.on_drag(Message::DragItem(service_item.clone()))
|
||||
.on_enter(Message::HoverItem(
|
||||
Some((
|
||||
model.kind,
|
||||
index as i32,
|
||||
)),
|
||||
))
|
||||
.on_double_click(
|
||||
Message::OpenItem(Some((
|
||||
model.kind,
|
||||
index as i32,
|
||||
))),
|
||||
)
|
||||
.on_exit(Message::HoverItem(None))
|
||||
.on_press(Message::SelectItem(
|
||||
Some((
|
||||
model.kind,
|
||||
index as i32,
|
||||
)),
|
||||
)),
|
||||
DndSource::<Message, ServiceItem>::new({
|
||||
let mouse_area = Element::from(mouse_area(visual_item)
|
||||
.on_drag(Message::DragItem(service_item.clone()))
|
||||
.on_enter(Message::HoverItem(
|
||||
Some((
|
||||
model.kind,
|
||||
index as i32,
|
||||
)),
|
||||
))
|
||||
.on_double_click(
|
||||
Message::OpenItem(Some((
|
||||
model.kind,
|
||||
index as i32,
|
||||
))),
|
||||
)
|
||||
.on_right_press(Message::OpenContext(index as i32))
|
||||
.on_exit(Message::HoverItem(None))
|
||||
.on_press(Message::SelectItem(
|
||||
Some((
|
||||
model.kind,
|
||||
index as i32,
|
||||
)),
|
||||
)));
|
||||
if let Some(context_id) = self.context_menu {
|
||||
if index == context_id as usize {
|
||||
let context_menu = context_menu(
|
||||
mouse_area,
|
||||
self.context_menu.map_or_else(|| None, |id| {
|
||||
Some(menu::items(&self.menu_keys,
|
||||
vec![menu::Item::Button("Delete", None, MenuMessage::Delete((model.kind, index as i32)))]))
|
||||
})
|
||||
);
|
||||
Element::from(context_menu)
|
||||
} else {
|
||||
Element::from(mouse_area)
|
||||
}
|
||||
} else {
|
||||
Element::from(mouse_area)
|
||||
}
|
||||
}
|
||||
)
|
||||
.action(DndAction::Copy)
|
||||
.drag_icon({
|
||||
|
|
@ -403,8 +462,8 @@ impl<'a> Library {
|
|||
move |i| {
|
||||
let state = State::None;
|
||||
let icon = match model {
|
||||
LibraryKind::Song => icon::from_name(
|
||||
"folder-music-symbolic",
|
||||
LibraryKind::Song => icon::from_name(
|
||||
"folder-music-symbolic",
|
||||
).symbolic(true)
|
||||
,
|
||||
LibraryKind::Video => icon::from_name("folder-videos-symbolic"),
|
||||
|
|
@ -481,11 +540,10 @@ impl<'a> Library {
|
|||
.accent_text_color()
|
||||
.into()
|
||||
}
|
||||
} else if let Some((library, selected)) = self.selected_item
|
||||
} else if let Some((library, selected)) =
|
||||
self.selected_item
|
||||
{
|
||||
if model.kind == library
|
||||
&& selected == index as i32
|
||||
{
|
||||
if model.kind == library && selected == index as i32 {
|
||||
theme::active().cosmic().control_0().into()
|
||||
} else {
|
||||
theme::active()
|
||||
|
|
@ -563,6 +621,7 @@ impl<'a> Library {
|
|||
.into()
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_async)]
|
||||
pub async fn search_items(
|
||||
&self,
|
||||
query: String,
|
||||
|
|
@ -573,14 +632,18 @@ impl<'a> Library {
|
|||
.items
|
||||
.iter()
|
||||
.filter(|song| song.title.to_lowercase().contains(&query))
|
||||
.map(super::super::core::content::Content::to_service_item)
|
||||
.map(
|
||||
super::super::core::content::Content::to_service_item,
|
||||
)
|
||||
.collect();
|
||||
let videos: Vec<ServiceItem> = self
|
||||
.video_library
|
||||
.items
|
||||
.iter()
|
||||
.filter(|vid| vid.title.to_lowercase().contains(&query))
|
||||
.map(super::super::core::content::Content::to_service_item)
|
||||
.map(
|
||||
super::super::core::content::Content::to_service_item,
|
||||
)
|
||||
.collect();
|
||||
let images: Vec<ServiceItem> = self
|
||||
.image_library
|
||||
|
|
@ -589,14 +652,18 @@ impl<'a> Library {
|
|||
.filter(|image| {
|
||||
image.title.to_lowercase().contains(&query)
|
||||
})
|
||||
.map(super::super::core::content::Content::to_service_item)
|
||||
.map(
|
||||
super::super::core::content::Content::to_service_item,
|
||||
)
|
||||
.collect();
|
||||
let presentations: Vec<ServiceItem> = self
|
||||
.presentation_library
|
||||
.items
|
||||
.iter()
|
||||
.filter(|pres| pres.title.to_lowercase().contains(&query))
|
||||
.map(super::super::core::content::Content::to_service_item)
|
||||
.map(
|
||||
super::super::core::content::Content::to_service_item,
|
||||
)
|
||||
.collect();
|
||||
items.extend(videos);
|
||||
items.extend(images);
|
||||
|
|
|
|||
|
|
@ -221,7 +221,8 @@ impl Presenter {
|
|||
let offset = AbsoluteOffset {
|
||||
x: {
|
||||
if self.current_slide_index > 2 {
|
||||
(self.current_slide_index as f32).mul_add(187.5, -187.5)
|
||||
(self.current_slide_index as f32)
|
||||
.mul_add(187.5, -187.5)
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,29 @@
|
|||
use std::{io, path::PathBuf, sync::Arc};
|
||||
|
||||
use cosmic::{
|
||||
Element, Task,
|
||||
dialog::file_chooser::open::Dialog,
|
||||
iced::{
|
||||
font::{Family, Stretch, Style, Weight},
|
||||
Font, Length,
|
||||
font::{Family, Stretch, Style, Weight},
|
||||
},
|
||||
iced_wgpu::graphics::text::cosmic_text::fontdb,
|
||||
iced_widget::row,
|
||||
theme,
|
||||
widget::{
|
||||
button, column, combo_box, container, horizontal_space, icon, text, text_editor, text_input,
|
||||
button, column, combo_box, container, horizontal_space, icon,
|
||||
text, text_editor, text_input,
|
||||
},
|
||||
Element, Task,
|
||||
};
|
||||
use dirs::font_dir;
|
||||
use iced_video_player::Video;
|
||||
use tracing::{debug, error};
|
||||
|
||||
use crate::{
|
||||
core::{service_items::ServiceTrait, songs::Song},
|
||||
Background, BackgroundKind, core::songs::Song,
|
||||
ui::slide_editor::SlideEditor,
|
||||
Background, BackgroundKind,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SongEditor {
|
||||
pub song: Option<Song>,
|
||||
|
|
@ -244,8 +243,7 @@ impl SongEditor {
|
|||
Message::ChangeBackground(Ok(path)) => {
|
||||
debug!(?path);
|
||||
if let Some(mut song) = self.song.clone() {
|
||||
let background =
|
||||
Background::try_from(path).ok();
|
||||
let background = Background::try_from(path).ok();
|
||||
self.background_video(&background);
|
||||
song.background = background;
|
||||
return self.update_song(song);
|
||||
|
|
@ -258,7 +256,7 @@ impl SongEditor {
|
|||
return Action::Task(Task::perform(
|
||||
pick_background(),
|
||||
Message::ChangeBackground,
|
||||
))
|
||||
));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,15 +121,18 @@ impl From<&str> for Font {
|
|||
}
|
||||
|
||||
impl Font {
|
||||
#[must_use] pub fn get_name(&self) -> String {
|
||||
#[must_use]
|
||||
pub fn get_name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
#[must_use] pub const fn get_weight(&self) -> Weight {
|
||||
#[must_use]
|
||||
pub const fn get_weight(&self) -> Weight {
|
||||
self.weight
|
||||
}
|
||||
|
||||
#[must_use] pub const fn get_style(&self) -> Style {
|
||||
#[must_use]
|
||||
pub const fn get_style(&self) -> Style {
|
||||
self.style
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +151,8 @@ impl Font {
|
|||
self
|
||||
}
|
||||
|
||||
#[must_use] pub const fn size(mut self, size: u8) -> Self {
|
||||
#[must_use]
|
||||
pub const fn size(mut self, size: u8) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
}
|
||||
|
|
@ -236,7 +240,10 @@ impl TextSvg {
|
|||
self
|
||||
}
|
||||
|
||||
pub const fn alignment(mut self, alignment: TextAlignment) -> Self {
|
||||
pub const fn alignment(
|
||||
mut self,
|
||||
alignment: TextAlignment,
|
||||
) -> Self {
|
||||
self.alignment = alignment;
|
||||
self
|
||||
}
|
||||
|
|
@ -272,8 +279,8 @@ impl TextSvg {
|
|||
let middle_position = size.height / 2.0;
|
||||
let line_spacing = 10.0;
|
||||
let text_and_line_spacing = font_size + line_spacing;
|
||||
let starting_y_position =
|
||||
half_lines.mul_add(-text_and_line_spacing, middle_position);
|
||||
let starting_y_position = half_lines
|
||||
.mul_add(-text_and_line_spacing, middle_position);
|
||||
|
||||
let text_pieces: Vec<String> = self
|
||||
.text
|
||||
|
|
@ -282,7 +289,10 @@ impl TextSvg {
|
|||
.map(|(index, text)| {
|
||||
format!(
|
||||
"<tspan x=\"50%\" y=\"{}\">{}</tspan>",
|
||||
(index as f32).mul_add(text_and_line_spacing, starting_y_position),
|
||||
(index as f32).mul_add(
|
||||
text_and_line_spacing,
|
||||
starting_y_position
|
||||
),
|
||||
text
|
||||
)
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue