use iced::{ alignment, widget::{column, row, Container}, Length, }; use itertools::Itertools; use schist_models::Bucket; use crate::{ gui::components::{ navigation::{self, InsertOptionResult}, BucketNavigationEntry, Navigation, Text, }, style::SPACING_LG, traits::{Component, Viewable}, }; #[derive(Clone, Debug)] pub struct BucketsView { greeting: String, navigation: Navigation, } #[derive(Clone, Debug)] pub enum Message { NavigationMessage(navigation::Message), SelectNext, SelectPrev, SetBuckets(Vec), ExpandGroup(String, Vec), CollapseGroup(String), } pub enum Action { None, } impl BucketsView { pub fn new(groups: Vec, greeting: &str) -> Self { Self { greeting: greeting.to_owned(), navigation: Navigation::new( groups .first() .map(String::as_str) .map(BucketNavigationEntry::from_group_closed), groups .iter() .map(String::as_str) .map(BucketNavigationEntry::from_group_closed) .collect(), ), } } pub fn active_group(&self) -> Option { self.navigation .active_option .as_ref() .map(|active_option| active_option.group()) } fn update_greeting(&mut self, active_entry: &str) { self.greeting = format!("Hello, {}!", active_entry); } fn expand_group(&mut self, group: String, buckets: Vec) -> Action { match self.navigation.insert_after_first( |bucket_navigation_entry| { bucket_navigation_entry.is_group_and(|bucket_group_name| { !bucket_group_name.is_open && bucket_group_name.group.eq(group.as_str()) }) }, &buckets .iter() .map(BucketNavigationEntry::from_bucket) .collect(), ) { InsertOptionResult::InsertedOptions => { self.navigation.replace_first( |bucket_navigation_entry| { bucket_navigation_entry.is_group_and(|g| g.group.eq(group.as_str())) }, &vec![BucketNavigationEntry::from_group_open(&group)], ); Action::None } InsertOptionResult::NoSuchOption => Action::None, } } fn collapse_group(&mut self, group: String) -> Action { self.navigation .remove_options_where(|bucket_navigation_entry| { bucket_navigation_entry.is_bucket_and(|bucket| bucket.group.eq(&group)) }); self.navigation.replace_first( |bucket_navigation_entry| bucket_navigation_entry.is_group_and(|g| g.group.eq(&group)), &vec![BucketNavigationEntry::from_group_closed(&group)], ); Action::None } } impl<'a> Viewable<'a, Message> for BucketsView { fn view(&'a self) -> iced::Element<'a, Message> where Message: 'a, { let navigation = self.navigation.view().map(Message::NavigationMessage); let main_content = column![Text::default(&self.greeting).as_element()]; row![ Container::new(navigation).width(Length::FillPortion(1)), Container::new(main_content).width(Length::FillPortion(3)), ] .align_y(alignment::Vertical::Center) .height(Length::Fill) .spacing(SPACING_LG) .into() } } impl<'a> Component<'a, Message, Action> for BucketsView { fn update(&mut self, message: Message) -> Action { match message { Message::SetBuckets(buckets) => { let groups: Vec = buckets .iter() .map(|bucket| bucket.group.as_str()) .unique() .map(BucketNavigationEntry::from_group_closed) .collect(); match self .navigation .update(navigation::Message::SetOptions(groups)) { navigation::Action::ActivateOption(bucket_navigation_entry) | navigation::Action::SelectOption(bucket_navigation_entry) => { self.update_greeting(&bucket_navigation_entry.to_string()); Action::None } navigation::Action::None => Action::None, } } Message::NavigationMessage(message) => match self.navigation.update(message) { navigation::Action::ActivateOption(bucket_navigation_entry) | navigation::Action::SelectOption(bucket_navigation_entry) => { self.update_greeting(&bucket_navigation_entry.to_string()); Action::None } navigation::Action::None => Action::None, }, Message::SelectNext => match self.navigation.update(navigation::Message::SelectNext) { navigation::Action::ActivateOption(bucket_navigation_entry) | navigation::Action::SelectOption(bucket_navigation_entry) => { self.update_greeting(&bucket_navigation_entry.to_string()); Action::None } navigation::Action::None => Action::None, }, Message::SelectPrev => match self.navigation.update(navigation::Message::SelectPrev) { navigation::Action::ActivateOption(bucket_navigation_entry) | navigation::Action::SelectOption(bucket_navigation_entry) => { self.update_greeting(&bucket_navigation_entry.to_string()); Action::None } navigation::Action::None => Action::None, }, Message::ExpandGroup(group, buckets) => self.expand_group(group, buckets), Message::CollapseGroup(group) => self.collapse_group(group), } } }