diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-03 23:13:50 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-03 23:13:50 -0600 |
| commit | 5d07af632e9680416f28571cca6ff3ccd5e1b1a7 (patch) | |
| tree | eee72adb86fdf9a1999c399a9658135045b4fc67 /src/app.rs | |
| parent | 99b5dd9c1a6fb5022232864005072c39497d0f0e (diff) | |
feat: implement CJSW music discovery featuremain
Added music discovery screen with CJSW radio program browsing:
- Added MusicDiscovery screen with genre-based navigation
- Implemented CJSW show data structure with 8 sample programs
- Added keyboard controls: 'm' key to access from episode/now playing screens
- Genre browsing with j/k navigation showing show schedules
- Updated help text to include music discovery option
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'src/app.rs')
| -rw-r--r-- | src/app.rs | 122 |
1 files changed, 122 insertions, 0 deletions
@@ -8,6 +8,7 @@ pub enum CurrentScreen { FeedList, EpisodeList, NowPlaying, + MusicDiscovery, } pub struct App { @@ -19,6 +20,8 @@ pub struct App { pub player: Player, pub current_track: Option<CurrentTrack>, pub volume: u8, + pub selected_genre: usize, + pub cjsw_shows: Vec<CjswShow>, feed_receiver: mpsc::Receiver<(usize, Feed)>, } @@ -30,6 +33,15 @@ pub struct CurrentTrack { pub _position: f64, // seconds } +#[derive(Debug, Clone)] +pub struct CjswShow { + pub name: String, + pub genre: String, + pub time_slot: String, + pub description: String, + pub day: String, +} + impl App { pub fn new() -> Result<Self> { let config = Config::load()?; @@ -64,6 +76,8 @@ impl App { player: Player::new()?, current_track: None, volume: 70, // Default volume 70% + selected_genre: 0, + cjsw_shows: Self::load_cjsw_shows(), feed_receiver: receiver, }) } @@ -212,4 +226,112 @@ impl App { } } } + + // Music discovery navigation + pub fn go_to_music_discovery(&mut self) { + self.current_screen = CurrentScreen::MusicDiscovery; + self.selected_genre = 0; + } + + pub fn next_genre(&mut self) { + if !self.cjsw_shows.is_empty() { + let unique_genres = self.get_unique_genres(); + if !unique_genres.is_empty() { + self.selected_genre = (self.selected_genre + 1) % unique_genres.len(); + } + } + } + + pub fn previous_genre(&mut self) { + if !self.cjsw_shows.is_empty() { + let unique_genres = self.get_unique_genres(); + if !unique_genres.is_empty() { + self.selected_genre = if self.selected_genre == 0 { + unique_genres.len() - 1 + } else { + self.selected_genre - 1 + }; + } + } + } + + pub fn get_unique_genres(&self) -> Vec<String> { + let mut genres: Vec<String> = self.cjsw_shows + .iter() + .map(|show| show.genre.clone()) + .collect::<std::collections::HashSet<_>>() + .into_iter() + .collect(); + genres.sort(); + genres + } + + pub fn get_shows_by_genre(&self, genre: &str) -> Vec<&CjswShow> { + self.cjsw_shows + .iter() + .filter(|show| show.genre == genre) + .collect() + } + + // Load CJSW shows data + fn load_cjsw_shows() -> Vec<CjswShow> { + vec![ + CjswShow { + name: "Black Milk".to_string(), + genre: "Electronic/Experimental".to_string(), + time_slot: "Monday 1:00-3:00 AM".to_string(), + description: "Electronic and experimental music exploration".to_string(), + day: "Monday".to_string(), + }, + CjswShow { + name: "Soular Power".to_string(), + genre: "R&B/Soul".to_string(), + time_slot: "Tuesday 7:00-9:00 PM".to_string(), + description: "Classic and contemporary R&B and soul".to_string(), + day: "Tuesday".to_string(), + }, + CjswShow { + name: "Fade to Bass".to_string(), + genre: "Electronic".to_string(), + time_slot: "Friday 11:00 PM-1:00 AM".to_string(), + description: "House and techno music journey".to_string(), + day: "Friday".to_string(), + }, + CjswShow { + name: "Noise".to_string(), + genre: "Experimental".to_string(), + time_slot: "Wednesday 2:00-4:00 AM".to_string(), + description: "30+ years of avant-garde experimental music".to_string(), + day: "Wednesday".to_string(), + }, + CjswShow { + name: "Local Singles".to_string(), + genre: "Local/Indie".to_string(), + time_slot: "Thursday 6:00-8:00 PM".to_string(), + description: "Featuring Calgary and Alberta local artists".to_string(), + day: "Thursday".to_string(), + }, + CjswShow { + name: "CantoStars".to_string(), + genre: "Multicultural".to_string(), + time_slot: "Sunday 10:00 AM-12:00 PM".to_string(), + description: "Cantonese music and cultural programming".to_string(), + day: "Sunday".to_string(), + }, + CjswShow { + name: "Sonic Cycle".to_string(), + genre: "Indie Pop/Rock".to_string(), + time_slot: "Saturday 3:00-5:00 PM".to_string(), + description: "Genre-blending indie music journey".to_string(), + day: "Saturday".to_string(), + }, + CjswShow { + name: "Jazz Spectrum".to_string(), + genre: "Jazz".to_string(), + time_slot: "Monday 8:00-10:00 PM".to_string(), + description: "Classic to contemporary jazz exploration".to_string(), + day: "Monday".to_string(), + }, + ] + } } |
