diff --git a/amadeus/i18n/en/amadeus.ftl b/amadeus/i18n/en/amadeus.ftl index aaaeaad607df84ea2cb0888f1dbb9623384e4bc5..9c4207ccd3ab6b08b4870590f4da76b6b93dcedd 100644 --- a/amadeus/i18n/en/amadeus.ftl +++ b/amadeus/i18n/en/amadeus.ftl @@ -15,6 +15,7 @@ page-id = Page { $num } empty-queue = Empty Queue empty-history = Empty History empty-playlists = Empty playlists +empty-playlist = Empty playlists { $name } next-kara = Next kara prev-kara = Previous kara diff --git a/amadeus/i18n/es-ES/amadeus.ftl b/amadeus/i18n/es-ES/amadeus.ftl index 0aacad98a95eb84847d01dfed3d3ac59c47a9d63..91078f9aa6181753e247139d537f09ecef72f074 100644 --- a/amadeus/i18n/es-ES/amadeus.ftl +++ b/amadeus/i18n/es-ES/amadeus.ftl @@ -15,6 +15,7 @@ page-id = Pagina { $num } empty-queue = No hay nada en la cola de reproducción empty-history = No has escuchado nada recientemente empty-playlists = No tienes listas de reproducción +empty-playlist = No hay nada en la lista { $name } next-kara = Póxima kara prev-kara = Previo kara diff --git a/amadeus/i18n/fr-FR/amadeus.ftl b/amadeus/i18n/fr-FR/amadeus.ftl index 8e1af80c132eaef627391841110450f18ad76f1d..9b53636cf2dbc2466aeb332f5b4f3edd0f306c49 100644 --- a/amadeus/i18n/fr-FR/amadeus.ftl +++ b/amadeus/i18n/fr-FR/amadeus.ftl @@ -15,6 +15,7 @@ page-id = Page { $num } empty-queue = La queue est vide empty-history = L'historique est vide empty-playlists = Il n'y a pas de listes de lecture de disponibles +empty-playlist = La liste de lecture { $name } est vide next-kara = Kara suivant prev-kara = Kara précédent diff --git a/amadeus/rsc/icons/fontawesome/goback.svg b/amadeus/rsc/icons/fontawesome/goback.svg new file mode 100644 index 0000000000000000000000000000000000000000..30ecb4886c24e04aa0b329555ccd719075ba6865 --- /dev/null +++ b/amadeus/rsc/icons/fontawesome/goback.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/></svg> diff --git a/amadeus/src/app.rs b/amadeus/src/app.rs index 003e1056301e8047905238e5683e70070d54e3de..7f98e9e6a706e948b737e215ec22993c861547f1 100644 --- a/amadeus/src/app.rs +++ b/amadeus/src/app.rs @@ -74,6 +74,9 @@ pub struct AppModel { /// Informations about the lektord server. lektord_state: LektordState, + /// The selected playlist in the playlists tab. + selected_playlist: Option<KId>, + /// The store where we cache the playlists, queue, history, etc. store: Store, @@ -176,6 +179,10 @@ pub enum Message { OpenKaraInfo(KId), ToggleContextPage(ContextPage), + // Playlist selection stuff + SelectPlaylist(KId), + UnSelectPlaylist, + // Update the configuration UpdateConfig(ConfigMessage), @@ -223,6 +230,7 @@ impl Application for AppModel { context_page: Default::default(), lektord_state: LektordState::Disconnected, + selected_playlist: None, store: Store::default(), search_filter: Filter::default(), search_results: Vec::default(), @@ -335,16 +343,15 @@ impl Application for AppModel { /// Describes the interface based on the current state of the application model. fn view(&self) -> Element<Self::Message> { let page = match self.nav.active_data::<Page>().copied() { - Some(Page::Home) => pages::home::view().into(), - Some(Page::Queue) => pages::queue::view(&self.store).into(), - Some(Page::History) => pages::history::view(&self.store).into(), - Some(Page::Search) => pages::search::view(self).into(), - Some(Page::Playlists) => pages::playlists::view(&self.store).into(), - Some(Page::Playlist(id)) => pages::playlist::view(&self.store, id).into(), - page => pages::not_found(page).into(), + Some(Page::Home) => pages::home::view(), + Some(Page::Queue) => pages::queue::view(&self.store), + Some(Page::History) => pages::history::view(&self.store), + Some(Page::Search) => pages::search::view(self), + Some(Page::Playlists) => pages::playlists::view(&self.store, self.selected_playlist), + page => pages::not_found(page), }; - widget::column() + widget::column::with_capacity(2) .push(page) .push(bottom_bar::view(self)) .apply(widget::container) @@ -415,14 +422,22 @@ impl Application for AppModel { cosmic::command::future(async move { requests::search_karas(&*config.read().await, SearchFrom::Database, filters) .await - .map(Message::QueryWithFiltersResults) - .map(cosmic::app::message::app) + .map(|res| cosmic::app::message::app(Message::QueryWithFiltersResults(res))) .unwrap_or_else(|err| { log::error!("failed to query with filters: {err}"); cosmic::app::message::none() }) }) } + + Message::SelectPlaylist(kid) => { + self.selected_playlist = Some(kid); + Task::none() + } + Message::UnSelectPlaylist => { + self.selected_playlist = None; + Task::none() + } } } diff --git a/amadeus/src/app/pages.rs b/amadeus/src/app/pages.rs index c79b3c02417d49bdbd3e771c16dcd8fc4e6b7c25..2957cd3c75c5902868817cdab07419e1de716180 100644 --- a/amadeus/src/app/pages.rs +++ b/amadeus/src/app/pages.rs @@ -8,16 +8,13 @@ use cosmic::{ Alignment, Length, }, prelude::*, - style, theme, - widget::{self, icon, nav_bar, Icon}, + style, theme, widget, }; use derive_more::Display; -use lektor_payloads::KId; use std::marker; pub mod history; pub mod home; -pub mod playlist; pub mod playlists; pub mod queue; pub mod search; @@ -41,27 +38,26 @@ pub enum Page { #[display("{}", fl!("playlists"))] Playlists, - - #[display("{}", fl!("playlist"))] - Playlist(KId), } impl Page { /// Get the icon associated with the page, to be displayed along with the [nav_bar::Model]. - pub fn icon(&self) -> Icon { - let icon = match self { + pub fn icon(&self) -> widget::Icon { + match self { Page::Home => crate::icons::USER, Page::Queue => crate::icons::QUEUE, - Page::History => crate::icons::HISTORY, Page::Search => crate::icons::SEARCH, - Page::Playlists | Page::Playlist(_) => crate::icons::ARCHIVE, - }; - icon::icon(icon::from_svg_bytes(icon).symbolic(true)) + Page::History => crate::icons::HISTORY, + Page::Playlists => crate::icons::ARCHIVE, + } + .apply(widget::icon::from_svg_bytes) + .symbolic(true) + .apply(widget::icon::icon) } } /// Get the navigation bar for the pages. -pub fn nav_bar_model() -> nav_bar::Model { +pub fn nav_bar_model() -> widget::nav_bar::Model { macro_rules! insert { ($b:expr, $page:ident) => { $b.text(Page::$page.to_string()) @@ -69,7 +65,7 @@ pub fn nav_bar_model() -> nav_bar::Model { .data(Page::$page) }; } - nav_bar::Model::builder() + widget::nav_bar::Model::builder() .insert(|b| insert!(b, Home).activate()) .insert(|b| insert!(b, Queue)) .insert(|b| insert!(b, History)) @@ -79,7 +75,7 @@ pub fn nav_bar_model() -> nav_bar::Model { } /// We got a page that was not implemented, or no page at all. -pub fn not_found<'a>(page: Option<Page>) -> impl Into<Element<'a, Message>> { +pub fn not_found<'a>(page: Option<Page>) -> Element<'a, Message> { widget::column() .push(widget::text::title1(fl!("error-found"))) .push_maybe( @@ -91,13 +87,14 @@ pub fn not_found<'a>(page: Option<Page>) -> impl Into<Element<'a, Message>> { .height(Length::Fill) .align_x(Horizontal::Center) .align_y(Vertical::Center) + .into() } /// Helper for the icons at the right of the title in pages. #[must_use] struct PageViewControl<'a> { icon: &'static [u8], - message: Message, + message: Option<Message>, on_non_empty_content: bool, is_destructive_icon: bool, marker: marker::PhantomData<Element<'a, Message>>, @@ -105,16 +102,24 @@ struct PageViewControl<'a> { impl<'a> PageViewControl<'a> { /// Create a new control with an icon and an associated message. - pub fn new(icon: &'static [u8], message: Message) -> Self { + pub fn new(icon: &'static [u8]) -> Self { Self { icon, - message, + message: None, on_non_empty_content: false, is_destructive_icon: false, marker: marker::PhantomData, } } + /// Set the message to use when the button will be pressed. + pub fn message(self, message: Message) -> Self { + Self { + message: Some(message), + ..self + } + } + /// Make the button a destructive one. pub fn destructive(self) -> Self { Self { @@ -146,7 +151,11 @@ impl<'a> PageViewControl<'a> { let button = widget::icon::from_svg_bytes(icon) .symbolic(true) .apply(widget::button::icon) - .on_press_maybe((!page_is_empty || !on_non_empty_content).then_some(message)) + .on_press_maybe( + (!page_is_empty || !on_non_empty_content) + .then_some(message) + .flatten(), + ) .padding(space_xxs) .width(32) .height(32); diff --git a/amadeus/src/app/pages/history.rs b/amadeus/src/app/pages/history.rs index 7f768e0503eb6f527cf9733eadae1e509423390f..2c67b24b5bff33053a428e651ff9afcb0fb818cc 100644 --- a/amadeus/src/app/pages/history.rs +++ b/amadeus/src/app/pages/history.rs @@ -4,26 +4,22 @@ use crate::{ pages::{PageView, PageViewControl}, LektordCommand, Message, }, - fl, + fl, icons, store::Store, }; use cosmic::{prelude::*, widget}; /// Display the history page. -pub fn view(store: &Store) -> impl Into<Element<Message>> { +pub fn view(store: &Store) -> Element<Message> { PageView::default() .titles(fl!("history"), fl!("empty-history")) .controls([ - PageViewControl::new( - crate::icons::RETRY, - Message::SendCommand(LektordCommand::HistoryGet), - ), - PageViewControl::new( - crate::icons::METEOR, - Message::SendCommand(LektordCommand::HistoryClear), - ) - .destructive() - .need_content(), + PageViewControl::new(icons::RETRY) + .message(Message::SendCommand(LektordCommand::HistoryGet)), + PageViewControl::new(icons::METEOR) + .message(Message::SendCommand(LektordCommand::HistoryClear)) + .destructive() + .need_content(), ]) .push_when(!store.iter_history().is_empty(), || { (store.iter_history()).fold(widget::list_column(), |list, kid| { @@ -31,4 +27,5 @@ pub fn view(store: &Store) -> impl Into<Element<Message>> { }) }) .view() + .into() } diff --git a/amadeus/src/app/pages/home.rs b/amadeus/src/app/pages/home.rs index 71d31c083db8fe707988f7542e4ba0046d07496e..96e01a1c01131445221909446153ca8689656ff9 100644 --- a/amadeus/src/app/pages/home.rs +++ b/amadeus/src/app/pages/home.rs @@ -5,6 +5,6 @@ use crate::{ use cosmic::prelude::*; /// Display the home page. -pub fn view<'a>() -> impl Into<Element<'a, Message>> { - PageView::default().title(fl!("home")).view() +pub fn view<'a>() -> Element<'a, Message> { + PageView::default().title(fl!("home")).view().into() } diff --git a/amadeus/src/app/pages/playlist.rs b/amadeus/src/app/pages/playlist.rs deleted file mode 100644 index 007ba72c650fb5421b9cbb7abf1da086726e4653..0000000000000000000000000000000000000000 --- a/amadeus/src/app/pages/playlist.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::{ - app::{ - kard, - pages::{PageView, PageViewControl}, - LektordCommand, Message, - }, - fl, - store::Store, -}; -use cosmic::{prelude::*, style, widget}; -use lektor_payloads::{KId, PlaylistInfo}; - -/// Display the page about a specific playlist. -pub fn view(store: &Store, id: KId) -> impl Into<Element<Message>> { - let Some(infos) = store.playlist(id) else { - todo!() - }; - - let name = infos - .name() - .map(|name| fl!("playlist", name = name)) - .unwrap_or_else(|| "untitled".to_string()); - - let owners = infos - .infos() - .into_iter() - .flat_map(PlaylistInfo::owners) - .map(|owner| -> Element<'_, Message> { - widget::text::body(owner) - .apply(widget::button::custom) - .class(style::Button::Transparent) - .into() - }); - - let (created_at, updated_at) = infos - .infos() - .map(|infos| (infos.created_at(), infos.updated_at())) - .unwrap_or_default(); - - let infos = widget::settings::section() - .add(widget::settings::item( - "owners", - widget::row::with_children(owners.collect()), - )) - .add(widget::settings::item( - "created at", - widget::text::body(created_at.format("%Y-%m-%d %H:%M:%S").to_string()), - )) - .add(widget::settings::item( - "last modified at", - widget::text::body(updated_at.format("%Y-%m-%d %H:%M:%S").to_string()), - )); - - let display_playlist_content = || { - (store.iter_playlist_content(id)).fold(widget::list_column(), |list, kid| { - list.add(kard::view(store.get(kid))) - }) - }; - - PageView::default() - .titles(&name, format!("The playlist {name} is empty")) - .controls([ - PageViewControl::new( - crate::icons::SHUFFLE, - Message::SendCommand(LektordCommand::PlaylistShuffleContent(id)), - ) - .need_content(), - PageViewControl::new( - crate::icons::RETRY, - Message::SendCommand(LektordCommand::PlaylistGetContent(id)), - ), - PageViewControl::new( - crate::icons::METEOR, - Message::SendCommand(LektordCommand::PlaylistDelete(id)), - ) - .destructive(), - ]) - .push_and_ignore_for_empty(infos) - .push_when( - !store.iter_playlist_content(id).is_empty(), - display_playlist_content, - ) - .view() -} diff --git a/amadeus/src/app/pages/playlists.rs b/amadeus/src/app/pages/playlists.rs index 51745b73d0e136c4cd084e24921b39ae7dafbf70..cb3975858925a941744788166b1b0c949483aecb 100644 --- a/amadeus/src/app/pages/playlists.rs +++ b/amadeus/src/app/pages/playlists.rs @@ -1,33 +1,117 @@ use crate::{ app::{ + kard, pages::{PageView, PageViewControl}, LektordCommand, Message, }, - fl, + fl, icons, playlist::Playlist, store::Store, }; -use cosmic::{prelude::*, widget}; +use cosmic::{prelude::*, style, widget}; +use lektor_payloads::{KId, PlaylistInfo}; -fn view_playlist_card(playlist: &Playlist) -> impl Into<Element<Message>> { - widget::text(playlist.name().unwrap_or("untitled")) +/// Display a card that summerize the playlist, when pressed will select the given playlist. +fn view_playlist_card(playlist: &Playlist) -> Option<Element<Message>> { + let infos = playlist.infos()?; + let card = widget::text(infos.name()) + .apply(widget::button::custom) + .on_press(Message::SelectPlaylist(infos.local_id())); + Some(card.into()) } -/// Display all playlists in a page. -pub fn view(store: &Store) -> impl Into<Element<Message>> { +/// Display all the cards for all the available playlists. +fn view_playlists_cards(store: &Store) -> Element<Message> { PageView::default() .titles(fl!("playlists"), fl!("empty-playlists")) - .controls([PageViewControl::new( - crate::icons::RETRY, - Message::SendCommand(LektordCommand::PlaylistsGet), - )]) + .controls([PageViewControl::new(crate::icons::RETRY) + .message(Message::SendCommand(LektordCommand::PlaylistsGet))]) .push_when(store.iter_playlists().count() != 0, || { store .iter_playlists() - .map(view_playlist_card) - .map(Into::into) + .flat_map(view_playlist_card) .collect::<Vec<_>>() .apply(widget::flex_row) }) .view() + .into() +} + +/// Display the page about a specific playlist. +fn view_playlist_content(store: &Store, id: KId) -> Element<Message> { + let Some(infos) = store.playlist(id) else { + todo!() + }; + + let name = infos + .name() + .map(|name| fl!("playlist", name = name)) + .unwrap_or_else(|| "untitled".to_string()); + + let owners = infos + .infos() + .into_iter() + .flat_map(PlaylistInfo::owners) + .map(|owner| -> Element<'_, Message> { + widget::text::body(owner) + .apply(widget::button::custom) + .class(style::Button::Transparent) + .into() + }); + + let (created_at, updated_at) = infos + .infos() + .map(|infos| (infos.created_at(), infos.updated_at())) + .unwrap_or_default(); + + let infos = widget::settings::section() + .add(widget::settings::item( + "owners", + widget::row::with_children(owners.collect()), + )) + .add(widget::settings::item( + "created at", + widget::text::body(created_at.format("%Y-%m-%d %H:%M:%S").to_string()), + )) + .add(widget::settings::item( + "last modified at", + widget::text::body(updated_at.format("%Y-%m-%d %H:%M:%S").to_string()), + )); + + let display_playlist_content = || { + (store.iter_playlist_content(id)).fold(widget::list_column(), |list, kid| { + list.add(kard::view(store.get(kid))) + }) + }; + + PageView::default() + .titles(&name, fl!("empty-playlist", name = name.clone())) + .controls([ + PageViewControl::new(icons::GOBACK).message(Message::UnSelectPlaylist), + PageViewControl::new(icons::SHUFFLE) + .message(Message::SendCommand( + LektordCommand::PlaylistShuffleContent(id), + )) + .need_content(), + PageViewControl::new(icons::RETRY) + .message(Message::SendCommand(LektordCommand::PlaylistGetContent(id))), + PageViewControl::new(icons::METEOR) + .message(Message::SendCommand(LektordCommand::PlaylistDelete(id))) + .destructive(), + ]) + .push_and_ignore_for_empty(infos) + .push_when( + !store.iter_playlist_content(id).is_empty(), + display_playlist_content, + ) + .view() + .into() +} + +/// Display all playlists in a page, or the selected playlist. +pub fn view(store: &Store, selected_playlist: Option<KId>) -> Element<Message> { + match selected_playlist { + Some(id) => view_playlist_content(store, id), + None => view_playlists_cards(store), + } } diff --git a/amadeus/src/app/pages/queue.rs b/amadeus/src/app/pages/queue.rs index bc7ab1e839b0d131aface18f063d89511d700f18..9ca0a56840deeb27c6f71f28ac7174b72d996cd5 100644 --- a/amadeus/src/app/pages/queue.rs +++ b/amadeus/src/app/pages/queue.rs @@ -1,6 +1,6 @@ use crate::{ app::{kard, pages::PageView, LektordCommand, Message}, - fl, + fl, icons, store::Store, }; use cosmic::{prelude::*, style, widget}; @@ -13,21 +13,17 @@ fn view_queue_level(store: &Store, level: Priority) -> impl IntoIterator<Item = widget::text::title2(format!("{} {level}", fl!("queue"))).class(style::Text::Default), false, vec![ - PageViewControl::new( - crate::icons::SHUFFLE, - Message::SendCommand(LektordCommand::QueueLevelShuffle(level)), - ) - .need_content(), - PageViewControl::new( - crate::icons::RETRY, - Message::SendCommand(LektordCommand::QueueLevelGet(level)), - ), - PageViewControl::new( - crate::icons::METEOR, - Message::SendCommand(LektordCommand::QueueLevelClear(level)), - ) - .need_content() - .destructive(), + PageViewControl::new(icons::SHUFFLE) + .message(Message::SendCommand(LektordCommand::QueueLevelShuffle( + level, + ))) + .need_content(), + PageViewControl::new(icons::RETRY) + .message(Message::SendCommand(LektordCommand::QueueLevelGet(level))), + PageViewControl::new(icons::METEOR) + .message(Message::SendCommand(LektordCommand::QueueLevelClear(level))) + .need_content() + .destructive(), ], store.iter_queue_level(level).is_empty(), ); @@ -42,31 +38,23 @@ fn view_queue_level(store: &Store, level: Priority) -> impl IntoIterator<Item = } /// Displays the page with the queue. -pub fn view(store: &Store) -> impl Into<Element<Message>> { +pub fn view(store: &Store) -> Element<Message> { PageView::default() .titles(fl!("queue"), fl!("empty-queue")) .controls([ - PageViewControl::new( - crate::icons::SHUFFLE, - Message::SendCommand(LektordCommand::QueueShuffle), - ) - .need_content(), - PageViewControl::new( - crate::icons::RETRY, - Message::SendCommand(LektordCommand::QueueGet), - ), - PageViewControl::new( - crate::icons::CROP, - Message::SendCommand(LektordCommand::QueueCrop), - ) - .need_content() - .destructive(), - PageViewControl::new( - crate::icons::METEOR, - Message::SendCommand(LektordCommand::QueueClear), - ) - .need_content() - .destructive(), + PageViewControl::new(icons::SHUFFLE) + .message(Message::SendCommand(LektordCommand::QueueShuffle)) + .need_content(), + PageViewControl::new(icons::RETRY) + .message(Message::SendCommand(LektordCommand::QueueGet)), + PageViewControl::new(icons::CROP) + .message(Message::SendCommand(LektordCommand::QueueCrop)) + .need_content() + .destructive(), + PageViewControl::new(icons::METEOR) + .message(Message::SendCommand(LektordCommand::QueueClear)) + .need_content() + .destructive(), ]) .extend( (PRIORITY_VALUES.iter().rev()) @@ -76,4 +64,5 @@ pub fn view(store: &Store) -> impl Into<Element<Message>> { .flatten(), ) .view() + .into() } diff --git a/amadeus/src/app/pages/search.rs b/amadeus/src/app/pages/search.rs index c305e7a55272082e3b084821a6e54a242e752611..3e1b6fcb8d14ab12070c08e8fd8e82c40d85cdcb 100644 --- a/amadeus/src/app/pages/search.rs +++ b/amadeus/src/app/pages/search.rs @@ -1,6 +1,13 @@ //! Contains everything to implement search from Amadeus. -use crate::app::{kard, pages::PageView, AppModel, Message}; +use crate::{ + app::{ + kard, + pages::{PageView, PageViewControl}, + AppModel, Message, + }, + icons, +}; use cosmic::{iced::Alignment, prelude::*, style, theme, widget}; use lektor_payloads::KaraBy; use std::{ @@ -9,8 +16,6 @@ use std::{ sync::atomic::{AtomicUsize, Ordering}, }; -use super::PageViewControl; - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FilterAtom(FilterAtomId, KaraBy); @@ -20,14 +25,6 @@ pub struct FilterAtomId(usize); #[derive(Debug, Default)] pub struct Filter(String, Vec<FilterAtom>); -macro_rules! icon { - ($icon:ident) => { - widget::icon::from_svg_bytes(crate::icons::$icon) - .symbolic(true) - .apply(widget::icon) - }; -} - impl FromStr for FilterAtom { type Err = Infallible; @@ -45,6 +42,14 @@ impl FilterAtomId { impl FilterAtom { fn view(&self) -> Element<Message> { + macro_rules! icon { + ($icon:ident) => { + widget::icon::from_svg_bytes(icons::$icon) + .symbolic(true) + .apply(widget::icon) + }; + } + let (icon, text) = match &self.1 { KaraBy::Id(id) => (icon!(HASHTAG), id.to_string()), KaraBy::Query(query) => (icon!(FILTER), query.clone()), @@ -113,21 +118,22 @@ impl Filter { } pub fn remove(&mut self, id: FilterAtomId) { - if let Some(idx) = (self.1.iter().enumerate()) + _ = (self.1.iter().enumerate()) .find_map(|(idx, FilterAtom(atom, _))| (*atom == id).then_some(idx)) - { - self.1.remove(idx); - } + .map(|idx| self.1.remove(idx)); } } /// Display the search page. -pub fn view(app: &AppModel) -> impl Into<Element<Message>> { +pub fn view(app: &AppModel) -> Element<Message> { PageView::default() .custom_title(app.search_filter.view_staging_row()) .controls([ - PageViewControl::new(crate::icons::FILTER, Message::QueryWithFilters).need_content(), - PageViewControl::new(crate::icons::METEOR, Message::ClearFilters) + PageViewControl::new(icons::FILTER) + .message(Message::QueryWithFilters) + .need_content(), + PageViewControl::new(icons::METEOR) + .message(Message::ClearFilters) .need_content() .destructive(), ]) @@ -139,4 +145,5 @@ pub fn view(app: &AppModel) -> impl Into<Element<Message>> { }) }) .view() + .into() } diff --git a/amadeus/src/icons.rs b/amadeus/src/icons.rs index 28320f56464f4f0bc2830b343c9d024d19322325..05dfb909cf93019ead4a1e1d822609e1b125ca2c 100644 --- a/amadeus/src/icons.rs +++ b/amadeus/src/icons.rs @@ -47,3 +47,4 @@ icon!(PLAY: "fontawesome/play"); icon!(PAUSE: "fontawesome/pause"); icon!(RETRY: "fontawesome/retry"); icon!(CROP: "fontawesome/crop"); +icon!(GOBACK: "fontawesome/goback");