mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-03 16:41:26 +01:00
feat(app): mark a season, or everything up to an episode, watched
Marking was per episode on the title page, or the whole title from the library's menu. Someone joining a show at season three had to tick every earlier episode one by one. Season headers now have Mark season watched (or unwatched), and right-clicking an episode's tick offers Mark watched up to here. Both go through one MarkEpisodes action with an Undo, which SetTitleWatched now uses too.
This commit is contained in:
1 parent
5dfb717235
commit
6d1943f2bd
2 files changed
+92
-9
No files matched your search
@@ -218,6 +218,14 @@ pub enum Action {
|
||||
key: String,
|
||||
watched: bool,
|
||||
},
|
||||
/// Some episodes of a title — a season, or everything up to one —
|
||||
/// watched or not, with an Undo. `what` names them in the toast.
|
||||
MarkEpisodes {
|
||||
key: String,
|
||||
links: Vec<(String, String)>,
|
||||
watched: bool,
|
||||
what: String,
|
||||
},
|
||||
/// Take a title off Continue watching by forgetting where it stopped,
|
||||
/// with an Undo.
|
||||
ForgetPosition {
|
||||
@@ -1651,9 +1659,41 @@ impl App {
|
||||
let Some(title) = self.library.get(&key) else {
|
||||
return;
|
||||
};
|
||||
let name = title.name.clone();
|
||||
let links = title
|
||||
.episodes()
|
||||
.map(|e| (e.node.share_id.clone(), e.node.link_id.clone()))
|
||||
.collect();
|
||||
let what = title.name.clone();
|
||||
self.apply(
|
||||
ctx,
|
||||
Action::MarkEpisodes {
|
||||
key,
|
||||
links,
|
||||
watched,
|
||||
what,
|
||||
},
|
||||
);
|
||||
}
|
||||
Action::MarkEpisodes {
|
||||
key,
|
||||
links,
|
||||
watched,
|
||||
what: name,
|
||||
} => {
|
||||
let Some(title) = self.library.get(&key) else {
|
||||
return;
|
||||
};
|
||||
let picked = |e: &&pstr_core::library::Episode| {
|
||||
links
|
||||
.iter()
|
||||
.any(|(share, link)| e.node.share_id == *share && e.node.link_id == *link)
|
||||
};
|
||||
let mut before = Vec::new();
|
||||
for episode in title.episodes().filter(|e| e.is_watched() != watched) {
|
||||
for episode in title
|
||||
.episodes()
|
||||
.filter(picked)
|
||||
.filter(|e| e.is_watched() != watched)
|
||||
{
|
||||
let duration = episode.watch.and_then(|watch| watch.duration_secs);
|
||||
before.push((
|
||||
episode.node.share_id.clone(),
|
||||
|
||||
@@ -96,6 +96,7 @@ pub fn show(
|
||||
)));
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
season_download(ui, title, season, &offline, actions);
|
||||
season_watched(ui, title, season, actions);
|
||||
});
|
||||
});
|
||||
ui.add_space(theme::space::L);
|
||||
@@ -207,6 +208,29 @@ fn back_link(ui: &mut egui::Ui) -> egui::Response {
|
||||
}
|
||||
|
||||
/// Download, or delete, a whole season.
|
||||
/// Mark a whole season seen, or unseen once it all is — for someone who
|
||||
/// watched it elsewhere and joins the show here.
|
||||
fn season_watched(ui: &mut egui::Ui, title: &Title, season: &Season, actions: &mut Vec<Action>) {
|
||||
let all = season.episodes.iter().all(|episode| episode.is_watched());
|
||||
let label = if all {
|
||||
"Mark season unwatched"
|
||||
} else {
|
||||
"Mark season watched"
|
||||
};
|
||||
if ui.button(label).clicked() {
|
||||
actions.push(Action::MarkEpisodes {
|
||||
key: title.key.clone(),
|
||||
links: season
|
||||
.episodes
|
||||
.iter()
|
||||
.map(|e| (e.node.share_id.clone(), e.node.link_id.clone()))
|
||||
.collect(),
|
||||
watched: !all,
|
||||
what: format!("{} {}", title.name, season.label()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn season_download(
|
||||
ui: &mut egui::Ui,
|
||||
title: &Title,
|
||||
@@ -759,14 +783,33 @@ fn episode_row(
|
||||
let cluster = egui::vec2(ui.available_width(), STILL.y);
|
||||
let layout = egui::Layout::right_to_left(egui::Align::Center);
|
||||
ui.allocate_ui_with_layout(cluster, layout, |ui| {
|
||||
if ui::widgets::watched_mark(ui, watched)
|
||||
.on_hover_text(if watched {
|
||||
"Mark unwatched"
|
||||
let mark = ui::widgets::watched_mark(ui, watched).on_hover_text(if watched {
|
||||
"Mark unwatched. Right-click for more."
|
||||
} else {
|
||||
"Mark watched"
|
||||
})
|
||||
.clicked()
|
||||
{
|
||||
"Mark watched. Right-click for more."
|
||||
});
|
||||
// Joining a show partway is the usual reason to mark
|
||||
// anything, and one tick per earlier episode is a chore.
|
||||
mark.context_menu(|ui| {
|
||||
if ui.button("Mark watched up to here").clicked() {
|
||||
let links = title
|
||||
.episodes()
|
||||
.take(
|
||||
title
|
||||
.position_of(&episode.node.share_id, &episode.node.link_id)
|
||||
.map_or(0, |at| at + 1),
|
||||
)
|
||||
.map(|e| (e.node.share_id.clone(), e.node.link_id.clone()))
|
||||
.collect();
|
||||
actions.push(Action::MarkEpisodes {
|
||||
key: title.key.clone(),
|
||||
links,
|
||||
watched: true,
|
||||
what: format!("{} up to {}", title.name, episode.label()),
|
||||
});
|
||||
}
|
||||
});
|
||||
if mark.clicked() {
|
||||
actions.push(Action::SetWatched {
|
||||
share_id: episode.node.share_id.clone(),
|
||||
link_id: episode.node.link_id.clone(),
|
||||
|
||||
Reference in new issue
Block a user