harpocrates_musik_player

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

setting_ui.rs (5822B)


      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, Clear, List, ListItem},
      7 };
      8 
      9 use crate::{
     10     app::App,
     11     audio::{AudioPlayer, DeviceManager},
     12 };
     13 
     14 pub fn render(f: &mut Frame, app: &mut App) {
     15     let area = f.area();
     16     let settings_items = vec![
     17         ListItem::new(format!("Volume: {:.2}", app.settings.audio().volume())),
     18         ListItem::new(format!(
     19             "Library Path: {}",
     20             app.settings.audio().library_path()
     21         )),
     22         ListItem::new(format!(
     23             "Output Device: {}",
     24             app.settings.audio().output_device()
     25         )),
     26     ];
     27 
     28     let list = List::new(settings_items)
     29         .block(
     30             Block::default()
     31                 .title("Settings")
     32                 .borders(Borders::ALL)
     33                 .border_style(Style::default().fg(Color::Yellow)),
     34         )
     35         .highlight_style(
     36             Style::default()
     37                 .bg(Color::Blue)
     38                 .add_modifier(Modifier::BOLD),
     39         )
     40         .highlight_symbol(">> ");
     41 
     42     f.render_stateful_widget(list, area, &mut app.state.settings_state);
     43 
     44     if app.state.is_device_dialog_open {
     45         render_device_dialog(f, app);
     46     }
     47 }
     48 
     49 fn render_device_dialog(f: &mut Frame, app: &mut App) {
     50     let area = centered_rect(60, 40, f.area());
     51     f.render_widget(Clear, area);
     52 
     53     let items: Vec<ListItem> = app
     54         .state
     55         .available_devices
     56         .iter()
     57         .map(|name| ListItem::new(name.as_str()))
     58         .collect();
     59 
     60     let list = List::new(items)
     61         .block(
     62             Block::default()
     63                 .title("Select Output Device")
     64                 .borders(Borders::ALL)
     65                 .border_style(Style::default().fg(Color::Yellow)),
     66         )
     67         .highlight_style(
     68             Style::default()
     69                 .bg(Color::Blue)
     70                 .add_modifier(Modifier::BOLD),
     71         )
     72         .highlight_symbol(">> ");
     73 
     74     f.render_stateful_widget(list, area, &mut app.state.device_dialog_state);
     75 }
     76 
     77 fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
     78     let popup_layout = Layout::default()
     79         .direction(Direction::Vertical)
     80         .constraints([
     81             Constraint::Percentage((100 - percent_y) / 2),
     82             Constraint::Percentage(percent_y),
     83             Constraint::Percentage((100 - percent_y) / 2),
     84         ])
     85         .split(r);
     86 
     87     Layout::default()
     88         .direction(Direction::Horizontal)
     89         .constraints([
     90             Constraint::Percentage((100 - percent_x) / 2),
     91             Constraint::Percentage(percent_x),
     92             Constraint::Percentage((100 - percent_x) / 2),
     93         ])
     94         .split(popup_layout[1])[1]
     95 }
     96 
     97 pub fn handle_key_event(app: &mut App, key: KeyEvent) -> Result<bool, Box<dyn std::error::Error>> {
     98     if app.state.is_device_dialog_open {
     99         return handle_dialog_key_event(app, key);
    100     }
    101 
    102     match key.code {
    103         KeyCode::Up => {
    104             let i = app.state.settings_state.selected().unwrap_or(0);
    105             if i > 0 {
    106                 app.state.settings_state.select(Some(i - 1));
    107             }
    108         }
    109         KeyCode::Down => {
    110             let i = app.state.settings_state.selected().unwrap_or(0);
    111             if i < 2 {
    112                 app.state.settings_state.select(Some(i + 1));
    113             }
    114         }
    115         KeyCode::Left => {
    116             if app.state.settings_state.selected() == Some(0) {
    117                 let new_vol = (app.settings.audio().volume() - 0.1).max(0.0);
    118                 app.settings.audio_mut().set_volume(new_vol);
    119                 app.audioengine.set_volume(new_vol);
    120                 app.settings.save()?;
    121             }
    122         }
    123         KeyCode::Right => {
    124             if app.state.settings_state.selected() == Some(0) {
    125                 let new_vol = (app.settings.audio().volume() + 0.1).min(1.0);
    126                 app.settings.audio_mut().set_volume(new_vol);
    127                 app.audioengine.set_volume(new_vol);
    128                 app.settings.save()?;
    129             }
    130         }
    131         KeyCode::Enter => {
    132             if app.state.settings_state.selected() == Some(2) {
    133                 let devices = DeviceManager::list_device_names();
    134                 app.state.open_device_dialog(devices);
    135             }
    136         }
    137         _ => {}
    138     }
    139     Ok(false)
    140 }
    141 
    142 fn handle_dialog_key_event(
    143     app: &mut App,
    144     key: KeyEvent,
    145 ) -> Result<bool, Box<dyn std::error::Error>> {
    146     match key.code {
    147         KeyCode::Up => {
    148             let i = app.state.device_dialog_state.selected().unwrap_or(0);
    149             if i > 0 {
    150                 app.state.device_dialog_state.select(Some(i - 1));
    151             }
    152         }
    153         KeyCode::Down => {
    154             let i = app.state.device_dialog_state.selected().unwrap_or(0);
    155             if !app.state.available_devices.is_empty() && i < app.state.available_devices.len() - 1
    156             {
    157                 app.state.device_dialog_state.select(Some(i + 1));
    158             }
    159         }
    160         KeyCode::Enter => {
    161             if let Some(i) = app.state.device_dialog_state.selected() {
    162                 if let Some(device_name) = app.state.available_devices.get(i) {
    163                     app.settings
    164                         .audio_mut()
    165                         .set_output_device(device_name.clone());
    166                     app.recreate_audio_engine()?;
    167                     app.settings.save()?;
    168                 }
    169             }
    170             app.state.close_device_dialog();
    171         }
    172         KeyCode::Esc => {
    173             app.state.close_device_dialog();
    174         }
    175         _ => {}
    176     }
    177     Ok(false)
    178 }