harpocrates_musik_player

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

library_ui.rs (8694B)


      1 use crossterm::event::{KeyCode, KeyEvent};
      2 use ratatui::{
      3     Frame,
      4     layout::{Constraint, Direction, Layout, Rect},
      5     style::{Color, Modifier, Style},
      6     widgets::{Block, Borders, List, ListItem, ListState},
      7 };
      8 
      9 use crate::{app::App, audio::AudioPlayer, ui::Focus};
     10 
     11 pub fn render(f: &mut Frame, app: &mut App) {
     12     let chunks = Layout::default()
     13         .direction(Direction::Horizontal)
     14         .constraints([
     15             Constraint::Percentage(33),
     16             Constraint::Percentage(33),
     17             Constraint::Percentage(34),
     18         ])
     19         .split(f.area());
     20 
     21     let artists: Vec<String> = app.library.artists.keys().cloned().collect();
     22     let artist_items: Vec<ListItem> = artists
     23         .iter()
     24         .map(|name| ListItem::new(name.as_str()))
     25         .collect();
     26     render_list(
     27         f,
     28         "Artist",
     29         artist_items,
     30         chunks[0],
     31         app.state.focus == Focus::Artist,
     32         &mut app.state.artist_state,
     33     );
     34 
     35     let selected_artist = app
     36         .state
     37         .artist_state
     38         .selected()
     39         .and_then(|i| artists.get(i));
     40     let mut albums: Vec<String> = Vec::new();
     41     if let Some(artist) = selected_artist {
     42         if let Some(artist_data) = app.library.artists.get(artist) {
     43             albums = artist_data.keys().cloned().collect();
     44         }
     45     }
     46     let album_items: Vec<ListItem> = albums
     47         .iter()
     48         .map(|name| ListItem::new(name.as_str()))
     49         .collect();
     50     render_list(
     51         f,
     52         "Album",
     53         album_items,
     54         chunks[1],
     55         app.state.focus == Focus::Album,
     56         &mut app.state.album_state,
     57     );
     58 
     59     let selected_album = app.state.album_state.selected().and_then(|i| albums.get(i));
     60     let mut tracks: Vec<String> = Vec::new();
     61     if let (Some(artist), Some(album)) = (selected_artist, selected_album) {
     62         if let Some(album_data) = app.library.artists.get(artist).and_then(|a| a.get(album)) {
     63             tracks = album_data.iter().map(|t| t.title.clone()).collect();
     64         }
     65     }
     66     let track_items: Vec<ListItem> = tracks
     67         .iter()
     68         .map(|name| ListItem::new(name.as_str()))
     69         .collect();
     70     render_list(
     71         f,
     72         "Track",
     73         track_items,
     74         chunks[2],
     75         app.state.focus == Focus::Track,
     76         &mut app.state.track_state,
     77     );
     78 }
     79 
     80 fn render_list(
     81     frame: &mut Frame,
     82     title: &str,
     83     items: Vec<ListItem>,
     84     area: Rect,
     85     focused: bool,
     86     state: &mut ListState,
     87 ) {
     88     let border_style = if focused {
     89         Style::default().fg(Color::Yellow)
     90     } else {
     91         Style::default()
     92     };
     93     let list = List::new(items)
     94         .block(
     95             Block::default()
     96                 .title(title)
     97                 .borders(Borders::ALL)
     98                 .border_style(border_style),
     99         )
    100         .highlight_style(
    101             Style::default()
    102                 .bg(Color::Blue)
    103                 .add_modifier(Modifier::BOLD),
    104         )
    105         .highlight_symbol(">> ");
    106     frame.render_stateful_widget(list, area, state);
    107 }
    108 
    109 pub fn handle_key_event(app: &mut App, key: KeyEvent) -> Result<bool, Box<dyn std::error::Error>> {
    110     match key.code {
    111         KeyCode::Left => {
    112             app.state.focus = match app.state.focus {
    113                 Focus::Artist => Focus::Artist,
    114                 Focus::Album => Focus::Artist,
    115                 Focus::Track => Focus::Album,
    116                 Focus::Settings => Focus::Settings,
    117             };
    118         }
    119         KeyCode::Right => {
    120             app.state.focus = match app.state.focus {
    121                 Focus::Artist => {
    122                     app.state.album_state.select(Some(0));
    123                     Focus::Album
    124                 }
    125                 Focus::Album => {
    126                     app.state.track_state.select(Some(0));
    127                     Focus::Track
    128                 }
    129                 Focus::Track => Focus::Track,
    130                 Focus::Settings => Focus::Settings,
    131             };
    132         }
    133         KeyCode::Up => {
    134             let current_state = match app.state.focus {
    135                 Focus::Artist => &mut app.state.artist_state,
    136                 Focus::Album => &mut app.state.album_state,
    137                 Focus::Track => &mut app.state.track_state,
    138                 Focus::Settings => &mut app.state.artist_state,
    139             };
    140             let i = current_state.selected().unwrap_or(0);
    141             if i > 0 {
    142                 current_state.select(Some(i - 1));
    143             }
    144         }
    145         KeyCode::Down => {
    146             let max_len = match app.state.focus {
    147                 Focus::Artist => app.library.artists.len(),
    148                 Focus::Album => {
    149                     let artists: Vec<_> = app.library.artists.keys().collect();
    150                     app.state
    151                         .artist_state
    152                         .selected()
    153                         .and_then(|i| artists.get(i))
    154                         .and_then(|a| app.library.artists.get(*a))
    155                         .map(|m| m.len())
    156                         .unwrap_or(0)
    157                 }
    158                 Focus::Track => {
    159                     let artists: Vec<_> = app.library.artists.keys().collect();
    160                     let artist = app
    161                         .state
    162                         .artist_state
    163                         .selected()
    164                         .and_then(|i| artists.get(i));
    165                     let albums: Vec<_> = artist
    166                         .and_then(|a| app.library.artists.get(*a))
    167                         .map(|m| m.keys().collect())
    168                         .unwrap_or_default();
    169                     let album = app.state.album_state.selected().and_then(|i| albums.get(i));
    170                     artist
    171                         .and_then(|a| app.library.artists.get(*a))
    172                         .and_then(|m| album.and_then(|al| m.get(*al)))
    173                         .map(|v| v.len())
    174                         .unwrap_or(0)
    175                 }
    176                 Focus::Settings => 0,
    177             };
    178 
    179             let current_state = match app.state.focus {
    180                 Focus::Artist => &mut app.state.artist_state,
    181                 Focus::Album => &mut app.state.album_state,
    182                 Focus::Track => &mut app.state.track_state,
    183                 Focus::Settings => &mut app.state.artist_state,
    184             };
    185             let i = current_state.selected().unwrap_or(0);
    186             if max_len > 0 && i < max_len - 1 {
    187                 current_state.select(Some(i + 1));
    188             }
    189         }
    190         KeyCode::Enter => {
    191             let artists: Vec<_> = app.library.artists.keys().collect();
    192             if let Some(artist_name) = app
    193                 .state
    194                 .artist_state
    195                 .selected()
    196                 .and_then(|i| artists.get(i))
    197             {
    198                 let artist_data = app.library.artists.get(*artist_name).unwrap();
    199                 let albums: Vec<_> = artist_data.keys().collect();
    200 
    201                 match app.state.focus {
    202                     Focus::Track => {
    203                         if let Some(album_name) =
    204                             app.state.album_state.selected().and_then(|i| albums.get(i))
    205                         {
    206                             let tracks = artist_data.get(*album_name).unwrap();
    207                             if let Some(track) =
    208                                 app.state.track_state.selected().and_then(|i| tracks.get(i))
    209                             {
    210                                 app.audioengine.stop();
    211                                 app.audioengine
    212                                     .append_a_track(track.path.to_str().unwrap())?;
    213                                 app.audioengine.play();
    214                             }
    215                         }
    216                     }
    217                     Focus::Album => {
    218                         if let Some(album_name) =
    219                             app.state.album_state.selected().and_then(|i| albums.get(i))
    220                         {
    221                             let tracks = artist_data.get(*album_name).unwrap();
    222                             app.audioengine.stop();
    223                             for track in tracks {
    224                                 app.audioengine
    225                                     .append_a_track(track.path.to_str().unwrap())?;
    226                             }
    227                             app.audioengine.play();
    228                         }
    229                     }
    230                     _ => {}
    231                 }
    232             }
    233         }
    234         _ => {}
    235     }
    236     Ok(false)
    237 }