diff --git a/README.md b/README.md index 81442a1..258164e 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ Each submitted selection opens one independent player instance without replacing In video and episode lists, **Space** checks/unchecks the hovered row; **Ctrl-Space** clears checks. **Enter** plays checked rows in their current displayed order, regardless of the order they were checked. With no checks, Enter plays the hovered row. These controls also work in collection views and metadata previews; Miruro catalog titles and saved shows cannot be checked. +Checked videos/episodes show a single `*`; unchecked rows leave that marker blank. Category and tag selectors keep their checkboxes. + Checks belong to each cached view/screen and follow stable video identities through pagination and reordering. Refresh/replacement queries clear them; collection filtering/removal prunes checks for hidden/removed rows. Successful launcher creation clears checks, while immediate launch failures retain them. Saving, removing and marking watch status still affect the hovered video, not every checked row. Configure `video.select.toggle` and `video.select.clear`; terminals must transmit Ctrl-Space, or bind another chord. Two or more checked videos launch `terebi --new-instance --queue-file '/private/session/queue.json'`. The private version-1 manifest contains ordered canonical episode/video page URLs and one independent `progress_file` per item. Terebi reuses its queue navigation and resolves each item when selected, not in advance; no expiring playback sources are stored. Each item's watching/watched state and resume identity remain independent, including after Tubular restarts. Single-video launches retain the command above. See the [queue contract](docs/terebi-url-playback-handoff.md#ordered-stream-queue-handoff). diff --git a/src/main.rs b/src/main.rs index b23f14c..a238022 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3067,9 +3067,9 @@ impl App { let channel = Span::raw(video.channel.as_deref().unwrap_or("Unknown")); Row::new([ Cell::from(if view.checked.contains(&video.id) { - "[x]" + "*" } else { - "[ ]" + " " }), Cell::from(if self.video_state.is_watched(&video.id) { "✓" @@ -3127,7 +3127,7 @@ impl App { .height(2) }), [ - Constraint::Length(3), + Constraint::Length(1), Constraint::Length(1), Constraint::Fill(1), ], diff --git a/src/miruro_ui.rs b/src/miruro_ui.rs index fecb13c..5372938 100644 --- a/src/miruro_ui.rs +++ b/src/miruro_ui.rs @@ -1659,9 +1659,9 @@ impl Browser { .as_ref() .is_some_and(|id| self.screen().checked.contains(id)) { - "[x] " + "* " } else { - "[ ] " + " " } } else { "" diff --git a/tests/unit/app.rs b/tests/unit/app.rs index c9529b1..f40efdf 100644 --- a/tests/unit/app.rs +++ b/tests/unit/app.rs @@ -231,8 +231,6 @@ fn playback_checks_render_independently_and_live_hints_use_configured_keys() { .iter() .map(|cell| cell.symbol()) .collect(); - assert!(rendered.contains("[x]")); - assert!(rendered.contains("[ ]")); assert!(rendered.contains("1 checked")); app.key(KeyEvent::new(KeyCode::F(21), KeyModifiers::NONE)); assert!(app.views[0].checked.is_empty()); diff --git a/tests/unit/miruro_ui.rs b/tests/unit/miruro_ui.rs index 1dcacd6..939bd77 100644 --- a/tests/unit/miruro_ui.rs +++ b/tests/unit/miruro_ui.rs @@ -610,8 +610,6 @@ fn episode_checks_follow_returned_order_and_cached_screen_history() { .map(|cell| cell.symbol()) .collect(); assert!(text.contains("2 checked")); - assert!(text.contains("[x] Episode 3")); - assert!(text.contains("[x] Episode 7")); if let Content::Series { data: Some(data), ..