Related timeline screen - #30
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (17)
📝 WalkthroughWalkthroughThis PR introduces a Related Timeline screen for exploring anime prequels/sequels, adds build-time OAuth client ID injection via environment variables, implements title localization with a configurable ChangesRelated Timeline Feature and Configuration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Adds a new Related top-level screen that lets users search for an anime and view a prequel→sequel “watch-order” timeline with side relations shown as selectable branches. It also centralizes title display logic (English vs romaji) and introduces a single-anime fetch path needed to traverse MAL’s relation graph.
Changes:
- Introduces
RelatedScreenwith background search + relation-chain building, and wires it into the navbar and popup flow (“Related series” button). - Adds
Anime::display_title()plus aprefer_romajiconfig option and updates several widgets/screens to use it. - Adds a single-anime network fetch + MAL client method, and injects
MAL_CLIENT_IDat build time viabuild.rs/CI.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/screens/widgets/sync.rs | Uses Anime::display_title() for consistent title rendering in sync popup. |
| src/screens/widgets/popup.rs | Adds “Related series” button and routes it to Action::ShowRelated; uses display_title(). |
| src/screens/widgets/animebox.rs | Uses display_title() and improves status display to include user score when present. |
| src/screens/seasons.rs | Shows “Your Score” in the season detail list. |
| src/screens/related.rs | New Related screen: search → pick → timeline UI + background timeline builder + unit tests. |
| src/screens/mod.rs | Registers RELATED screen and adds Screen::build_related hook + ScreenManager::show_related. |
| src/mal/oauth.rs | Switches OAuth client id to compile-time env injection (env!("MAL_CLIENT_ID")). |
| src/mal/network.rs | Adds fetch_single_anime() to deserialize the single-object /anime/{id} endpoint. |
| src/mal/models/anime.rs | Adds flexible u64 deserializer for statistics and Anime::display_title(); updates statistics fields. |
| src/mal/mod.rs | Adds MalClient::get_anime_by_id() using the new single-anime fetch path. |
| src/config/README.md | Documents new prefer_romaji config option. |
| src/config/mod.rs | Adds prefer_romaji field + helper accessor. |
| src/app.rs | Adds Action::ShowRelated handling. |
| docs/superpowers/specs/2026-06-01-related-timeline-screen-design.md | Design spec document for the Related timeline screen. |
| Cross.toml | Passes MAL_CLIENT_ID into cross builds. |
| build.rs | Build-time injection of MAL_CLIENT_ID from env or local .env. |
| .github/workflows/binaries.yaml | Provides MAL_CLIENT_ID from GitHub Actions secrets for release builds. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if let Some(id) = target | ||
| && self.app_info.anime_store.get(&id).is_some() | ||
| { | ||
| return Some(Action::ShowOverlay(id)); | ||
| } |
| fn draw_timeline(&mut self, frame: &mut Frame, area: Rect) { | ||
| let Some(timeline) = self.timeline.clone() else { return }; | ||
|
|
| // keep the highlight on the searched anime as boxes stream in | ||
| self.line_index = root_index; | ||
| } |
| // Injected at build time by build.rs (from the MAL_CLIENT_ID env var or a | ||
| // gitignored .env file) so it is not hard-coded in the source. | ||
| pub const CLIENT_ID: &str = env!("MAL_CLIENT_ID"); |
| if let crossterm::event::MouseEventKind::Down(_) = mouse_event.kind | ||
| && let Some(id) = self.current_branches().get(bi).map(|b| b.id) | ||
| && self.app_info.anime_store.get(&id).is_some() | ||
| { | ||
| return Some(Action::ShowOverlay(id)); | ||
| } |
Summary by CodeRabbit
New Features
Improvements