Remember selected season when refreshing season list (fixes #59)

This commit is contained in:
Avery
2024-01-18 00:19:04 -05:00
parent e6deee77e9
commit 222cf8e24e
3 changed files with 50 additions and 15 deletions

View File

@@ -16,7 +16,9 @@ use crate::{
}; };
use super::{ use super::{
display_years::DisplayYears, media_details_header::MediaDetailsHeader, seasons::Seasons, display_years::DisplayYears,
media_details_header::MediaDetailsHeader,
seasons::{Seasons, SeasonsOutput},
}; };
pub struct MediaDetailsContents { pub struct MediaDetailsContents {
@@ -25,11 +27,13 @@ pub struct MediaDetailsContents {
series_id: Option<Uuid>, series_id: Option<Uuid>,
header: OnceCell<Controller<MediaDetailsHeader>>, header: OnceCell<Controller<MediaDetailsHeader>>,
seasons: Option<AsyncController<Seasons>>, seasons: Option<AsyncController<Seasons>>,
selected_season_index: Option<usize>,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum MediaDetailsContentsInput { pub enum MediaDetailsContentsInput {
RefreshSeasons, RefreshSeasons,
SetSelectedSeasonIndex(usize),
} }
#[relm4::component(pub async)] #[relm4::component(pub async)]
@@ -92,7 +96,7 @@ impl AsyncComponent for MediaDetailsContents {
async fn init( async fn init(
init: Self::Init, init: Self::Init,
root: Self::Root, root: Self::Root,
_sender: AsyncComponentSender<Self>, sender: AsyncComponentSender<Self>,
) -> AsyncComponentParts<Self> { ) -> AsyncComponentParts<Self> {
let (api_client, media) = init; let (api_client, media) = init;
@@ -115,6 +119,7 @@ impl AsyncComponent for MediaDetailsContents {
series_id, series_id,
header: OnceCell::new(), header: OnceCell::new(),
seasons: None, seasons: None,
selected_season_index: None,
}; };
let widgets = view_output!(); let widgets = view_output!();
@@ -133,7 +138,7 @@ impl AsyncComponent for MediaDetailsContents {
model.add_info(info_box); model.add_info(info_box);
model.load_seasons(container); model.load_seasons(&sender, container);
AsyncComponentParts { model, widgets } AsyncComponentParts { model, widgets }
} }
@@ -147,7 +152,10 @@ impl AsyncComponent for MediaDetailsContents {
) { ) {
match message { match message {
MediaDetailsContentsInput::RefreshSeasons => { MediaDetailsContentsInput::RefreshSeasons => {
self.load_seasons(&widgets.container); self.load_seasons(&sender, &widgets.container);
}
MediaDetailsContentsInput::SetSelectedSeasonIndex(selected_season_index) => {
self.selected_season_index = Some(selected_season_index);
} }
} }
self.update_view(widgets, sender); self.update_view(widgets, sender);
@@ -155,7 +163,7 @@ impl AsyncComponent for MediaDetailsContents {
} }
impl MediaDetailsContents { impl MediaDetailsContents {
fn load_seasons(&mut self, container: &gtk::Box) { fn load_seasons(&mut self, sender: &AsyncComponentSender<Self>, container: &gtk::Box) {
if let Some(seasons) = self.seasons.take() { if let Some(seasons) = self.seasons.take() {
container.remove(seasons.widget()); container.remove(seasons.widget());
} }
@@ -165,8 +173,9 @@ impl MediaDetailsContents {
.launch(SeasonsInit { .launch(SeasonsInit {
api_client: self.api_client.clone(), api_client: self.api_client.clone(),
series_id, series_id,
initial_selected_season_index: self.selected_season_index,
}) })
.detach(); .forward(sender.input_sender(), |m| m.into());
container.append(seasons.widget()); container.append(seasons.widget());
self.seasons = Some(seasons); self.seasons = Some(seasons);
} }
@@ -232,3 +241,13 @@ impl MediaDetailsContents {
} }
} }
} }
impl From<SeasonsOutput> for MediaDetailsContentsInput {
fn from(val: SeasonsOutput) -> Self {
match val {
SeasonsOutput::SeasonSelected(selected_season_index) => {
MediaDetailsContentsInput::SetSelectedSeasonIndex(selected_season_index)
}
}
}
}

View File

@@ -10,7 +10,7 @@ pub(crate) struct SeasonButtons;
#[relm4::component(pub(crate))] #[relm4::component(pub(crate))]
impl SimpleComponent for SeasonButtons { impl SimpleComponent for SeasonButtons {
type Init = Vec<BaseItemDto>; type Init = (Vec<BaseItemDto>, usize);
type Input = (); type Input = ();
type Output = SeasonsInput; type Output = SeasonsInput;
@@ -23,10 +23,12 @@ impl SimpleComponent for SeasonButtons {
} }
fn init( fn init(
seasons: Self::Init, init: Self::Init,
seasons_box: &Self::Root, seasons_box: &Self::Root,
sender: ComponentSender<Self>, sender: ComponentSender<Self>,
) -> ComponentParts<Self> { ) -> ComponentParts<Self> {
let (seasons, initial_selected_season_index) = init;
let model = SeasonButtons; let model = SeasonButtons;
let widgets = view_output!(); let widgets = view_output!();
@@ -40,15 +42,16 @@ impl SimpleComponent for SeasonButtons {
} }
}; };
// First button will be active and is used to group remaining buttons // First button will is used to group remaining buttons
let first_btn = create_season_btn(&seasons[0]); let first_btn = create_season_btn(&seasons[0]);
first_btn.set_active(true); first_btn.set_active(initial_selected_season_index == 0);
first_btn.connect_toggled(btn_toggle_handler(0)); first_btn.connect_toggled(btn_toggle_handler(0));
seasons_box.append(&first_btn); seasons_box.append(&first_btn);
for (index, season) in seasons.iter().enumerate().skip(1) { for (index, season) in seasons.iter().enumerate().skip(1) {
let season_btn = create_season_btn(season); let season_btn = create_season_btn(season);
season_btn.set_group(Some(&first_btn)); season_btn.set_group(Some(&first_btn));
season_btn.set_active(initial_selected_season_index == index);
season_btn.connect_toggled(btn_toggle_handler(index)); season_btn.connect_toggled(btn_toggle_handler(index));
seasons_box.append(&season_btn); seasons_box.append(&season_btn);
} }

View File

@@ -26,6 +26,7 @@ pub struct Seasons {
pub struct SeasonsInit { pub struct SeasonsInit {
pub api_client: Arc<ApiClient>, pub api_client: Arc<ApiClient>,
pub series_id: Uuid, pub series_id: Uuid,
pub initial_selected_season_index: Option<usize>,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -33,11 +34,16 @@ pub enum SeasonsInput {
SeasonActivated(usize), SeasonActivated(usize),
} }
#[derive(Debug)]
pub enum SeasonsOutput {
SeasonSelected(usize),
}
#[relm4::component(pub async)] #[relm4::component(pub async)]
impl AsyncComponent for Seasons { impl AsyncComponent for Seasons {
type Init = SeasonsInit; type Init = SeasonsInit;
type Input = SeasonsInput; type Input = SeasonsInput;
type Output = (); type Output = SeasonsOutput;
type CommandOutput = (); type CommandOutput = ();
view! { view! {
@@ -74,6 +80,7 @@ impl AsyncComponent for Seasons {
let SeasonsInit { let SeasonsInit {
api_client, api_client,
series_id, series_id,
initial_selected_season_index,
} = init; } = init;
let widgets = view_output!(); let widgets = view_output!();
@@ -93,14 +100,18 @@ impl AsyncComponent for Seasons {
return AsyncComponentParts { model, widgets }; return AsyncComponentParts { model, widgets };
} }
let initial_selected_season_index = match initial_selected_season_index {
Some(season) if season < model.seasons.len() => season,
_ => 0,
};
let season_buttons = SeasonButtons::builder() let season_buttons = SeasonButtons::builder()
.launch(model.seasons.clone()) .launch((model.seasons.clone(), initial_selected_season_index))
.forward(sender.input_sender(), |e| e); .forward(sender.input_sender(), |e| e);
root.append(season_buttons.widget()); root.append(season_buttons.widget());
model.season_buttons = Some(season_buttons); model.season_buttons = Some(season_buttons);
// Load first season by default sender.input(SeasonsInput::SeasonActivated(initial_selected_season_index));
sender.input(SeasonsInput::SeasonActivated(0));
AsyncComponentParts { model, widgets } AsyncComponentParts { model, widgets }
} }
@@ -108,7 +119,7 @@ impl AsyncComponent for Seasons {
async fn update( async fn update(
&mut self, &mut self,
msg: Self::Input, msg: Self::Input,
_sender: AsyncComponentSender<Self>, sender: AsyncComponentSender<Self>,
root: &Self::Root, root: &Self::Root,
) { ) {
match msg { match msg {
@@ -128,6 +139,8 @@ impl AsyncComponent for Seasons {
.detach(); .detach();
root.append(episodes.widget()); root.append(episodes.widget());
self.episodes = Some(episodes); self.episodes = Some(episodes);
sender.output(SeasonsOutput::SeasonSelected(index)).unwrap();
} }
} }
} }