From 1a0b3e7e438693ab1cef3f612b6f71df64faddcf Mon Sep 17 00:00:00 2001 From: Fabian Lippold Date: Fri, 17 Nov 2023 05:05:00 +0100 Subject: [PATCH] fix clippy warnings & fixes --- src/cache.rs | 32 ++++------- src/config.rs | 6 +- src/main.rs | 4 +- src/player/facade.rs | 8 +-- src/player/loader.rs | 9 +-- src/player/mod.rs | 125 ++++++++--------------------------------- src/player/playback.rs | 95 +++++++++++++++++++++++++++++++ src/song.rs | 10 ++-- src/tui/fancy.rs | 2 - src/tui/files.rs | 59 ++++++++----------- src/tui/mod.rs | 6 +- src/tui/queue.rs | 23 ++++---- src/tui/search.rs | 9 ++- src/tui/status.rs | 5 +- src/tui/tabs.rs | 7 +-- 15 files changed, 194 insertions(+), 206 deletions(-) create mode 100644 src/player/playback.rs diff --git a/src/cache.rs b/src/cache.rs index 054f83f..c58af3b 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,7 +1,6 @@ use crate::{config::Config, song::Song}; use std::{ collections::HashMap, - fs::Metadata, path::{Path, PathBuf}, }; @@ -45,7 +44,7 @@ impl Cache { config .search_directories .iter() - .flat_map(|d| WalkDir::new(d)) + .flat_map(WalkDir::new) .filter_map(|e| e.ok()) .filter(|e| e.file_type().is_file()) .filter(|e| { @@ -54,33 +53,27 @@ impl Cache { .map(|e| config.extensions.contains(e.to_str().unwrap_or(""))) .unwrap_or(false) }) - .filter_map(|e| { - e.metadata() - .map(|m| (e, m)) - .map_err(|e| warn!("Failed to read metadata {:?}", e)) - .ok() - }) - .inspect(|(e, _)| { + .inspect(|e| { trace!("Found file {}", e.path().display()); }) - .filter_map(|(e, m)| { + .filter_map(|e| { Song::load(e.path()) - .map(|s| (e.path().to_path_buf(), m, s)) + .map(|s| (e.path().to_path_buf(), s)) .map_err(|e| { warn!("Failed to read song from {:?}: {}", e, e); }) .ok() }) - .for_each(|(p, m, s)| { + .for_each(|(p, s)| { cache - .insert_file(&p, m, s) + .insert_file(&p, s) .unwrap_or_else(|e| warn!("Failed to insert file {:?}: {}", p, e)); }); cache } - fn insert_file

(&mut self, path: P, meta: Metadata, song: Song) -> anyhow::Result<()> + fn insert_file

(&mut self, path: P, song: Song) -> anyhow::Result<()> where P: AsRef, { @@ -105,7 +98,7 @@ impl Cache { .or_insert(CacheEntry::Directory { children: HashMap::new(), }) - .insert_file(cs, meta, song)?; + .insert_file(cs, song)?; Ok(()) } @@ -229,12 +222,7 @@ impl CacheEntry { } } - fn insert_file( - &mut self, - mut path: Vec<&str>, - meta: Metadata, - song: Song, - ) -> anyhow::Result<()> { + fn insert_file(&mut self, mut path: Vec<&str>, song: Song) -> anyhow::Result<()> { match self { CacheEntry::File { .. } => { anyhow::bail!("CacheEntry::insert_file called on {:?}", self) @@ -260,7 +248,7 @@ impl CacheEntry { .or_insert_with(|| CacheEntry::Directory { children: HashMap::new(), }) - .insert_file(path, meta, song) + .insert_file(path, song) } } } diff --git a/src/config.rs b/src/config.rs index 0b24ace..ef187b7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -34,12 +34,12 @@ impl Config { Ok(()) } - pub fn default_from_config_dir(config_dir: &PathBuf) -> Self { + pub fn default_from_config_dir>(config_dir: P) -> Self { Self { search_directories: vec![], extensions: HashSet::new(), - cache_path: config_dir.join("ramp.cache"), - log_path: config_dir.join("ramp.log"), + cache_path: config_dir.as_ref().join("ramp.cache"), + log_path: config_dir.as_ref().join("ramp.log"), gain: OrderedFloat(0.0), } } diff --git a/src/main.rs b/src/main.rs index a26d3b8..f5cccac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,11 +25,11 @@ fn main() -> anyhow::Result<()> { } let config = Arc::new( - Config::load(&config_dir.join("config.json")).unwrap_or_else(|e| { + Config::load(config_dir.join("config.json")).unwrap_or_else(|e| { eprintln!("Failed to load config, using default: {e:?}"); let config = Config::default_from_config_dir(&config_dir); config - .save(&config_dir.join("config.json")) + .save(config_dir.join("config.json")) .unwrap_or_else(|e| { eprintln!("Failed to save config: {e:?}"); }); diff --git a/src/player/facade.rs b/src/player/facade.rs index 46c9470..57c3b8d 100644 --- a/src/player/facade.rs +++ b/src/player/facade.rs @@ -10,6 +10,7 @@ use crate::song::Song; use super::Player; #[derive(Default)] +#[allow(clippy::large_enum_variant)] pub enum PlayerStatus { PlayingOrPaused { song: Song, @@ -27,14 +28,13 @@ impl PlayerStatus { super::InternalPlayerStatus::PlayingOrPaused { song, metadata, - playing_duration, - stream_paused, + playback, .. } => PlayerStatus::PlayingOrPaused { song: song.clone(), metadata: metadata.clone(), - playing_duration: playing_duration.clone(), - paused: stream_paused.clone(), + playing_duration: playback.played_duration.clone(), + paused: playback.pause.clone(), }, super::InternalPlayerStatus::Stopped => PlayerStatus::Stopped, } diff --git a/src/player/loader.rs b/src/player/loader.rs index 9d9bd6f..74bf1bf 100644 --- a/src/player/loader.rs +++ b/src/player/loader.rs @@ -13,11 +13,13 @@ use symphonia::core::{ use crate::song::Song; +pub type Decoder = dyn FnMut() -> anyhow::Result<(Option>, bool)> + Send; + pub struct LoadedSong { pub song: Song, pub metadata: Option, pub signal_spec: SignalSpec, - pub decoder: Box anyhow::Result<(Option>, bool)> + Send>, + pub decoder: Box, } impl LoadedSong { @@ -44,7 +46,7 @@ impl LoadedSong { let track = format_reader .tracks() - .into_iter() + .iter() .find(|t| t.codec_params.codec != CODEC_TYPE_NULL) .ok_or(anyhow::anyhow!("No audio tracks found"))?; @@ -65,7 +67,6 @@ impl LoadedSong { ); debug!("Signal spec: {:?}", signal_spec); - let signal_spec2 = signal_spec.clone(); let decoder = move || match format_reader.next_packet() { Ok(packet) => { if packet.track_id() == track_id { @@ -76,7 +77,7 @@ impl LoadedSong { } }; - let mut sample_buffer = SampleBuffer::new(data.capacity() as u64, signal_spec2); + let mut sample_buffer = SampleBuffer::new(data.capacity() as u64, signal_spec); sample_buffer.copy_interleaved_ref(data); trace!( diff --git a/src/player/mod.rs b/src/player/mod.rs index 09b0d8b..6c7442e 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -3,34 +3,29 @@ use crate::{ song::{Song, StandardTagKey}, }; use anyhow::Context; -use cpal::{ - traits::{DeviceTrait, HostTrait}, - Stream, StreamConfig, -}; -use log::{debug, warn}; +use log::warn; use souvlaki::{MediaControls, MediaMetadata, MediaPlayback, MediaPosition, PlatformConfig}; use std::{ collections::VecDeque, - io::{Seek, Write}, - sync::{atomic::AtomicBool, mpsc, Arc, RwLock}, - time::Duration, + io::Write, + sync::{mpsc, Arc, RwLock}, }; use symphonia::core::meta::MetadataRevision; use tempfile::NamedTempFile; -use self::{command::Command, facade::PlayerFacade, loader::LoadedSong}; +use self::{command::Command, facade::PlayerFacade, loader::LoadedSong, playback::Playback}; pub mod command; pub mod facade; mod loader; +mod playback; +#[allow(clippy::large_enum_variant)] enum InternalPlayerStatus { PlayingOrPaused { song: Song, metadata: Option, - playing_duration: Arc>, - stream_paused: Arc, - _stream: Stream, + playback: Playback, }, Stopped, } @@ -47,12 +42,11 @@ impl Player { /// command player to continue playing or start playing the next song fn play(&mut self) -> anyhow::Result<()> { match &self.status { - InternalPlayerStatus::PlayingOrPaused { - stream_paused: paused, - .. - } => { - if paused.load(std::sync::atomic::Ordering::Relaxed) { - paused.store(false, std::sync::atomic::Ordering::Relaxed); + InternalPlayerStatus::PlayingOrPaused { playback, .. } => { + if playback.pause.load(std::sync::atomic::Ordering::Relaxed) { + playback + .pause + .store(false, std::sync::atomic::Ordering::Relaxed); } } InternalPlayerStatus::Stopped => {} @@ -72,15 +66,12 @@ impl Player { let loaded_song = LoadedSong::load(song.clone()).context("Failed to load song")?; let metadata = loaded_song.metadata.clone(); - let (stream_paused, playing_duration, _stream) = - self.create_playback(loaded_song)?; + let playback = Playback::new(self.command_tx.clone(), loaded_song)?; self.status = InternalPlayerStatus::PlayingOrPaused { song, metadata, - playing_duration, - stream_paused, - _stream, + playback, } } } @@ -91,11 +82,10 @@ impl Player { /// command player to pause fn pause(&mut self) -> anyhow::Result<()> { match &self.status { - InternalPlayerStatus::PlayingOrPaused { - stream_paused: paused, - .. - } => { - paused.store(true, std::sync::atomic::Ordering::Relaxed); + InternalPlayerStatus::PlayingOrPaused { playback, .. } => { + playback + .pause + .store(true, std::sync::atomic::Ordering::Relaxed); } InternalPlayerStatus::Stopped => {} } @@ -106,11 +96,10 @@ impl Player { /// command player to play if paused or pause if playing fn play_pause(&mut self) -> anyhow::Result<()> { match &self.status { - InternalPlayerStatus::PlayingOrPaused { - stream_paused: paused, - .. - } => { - paused.fetch_xor(true, std::sync::atomic::Ordering::Relaxed); + InternalPlayerStatus::PlayingOrPaused { playback, .. } => { + playback + .pause + .fetch_xor(true, std::sync::atomic::Ordering::Relaxed); } InternalPlayerStatus::Stopped => {} } @@ -162,76 +151,6 @@ impl Player { Ok(()) } - /// create playback stream for song - fn create_playback( - &mut self, - mut song: LoadedSong, - ) -> anyhow::Result<(Arc, Arc>, Stream)> { - let config = StreamConfig { - channels: song.signal_spec.channels.count() as u16, - sample_rate: cpal::SampleRate(song.signal_spec.rate), - buffer_size: cpal::BufferSize::Default, - }; - debug!("Stream config: {:?}", config); - - let mut buffer = VecDeque::::new(); - - let pause_stream = Arc::new(AtomicBool::new(false)); - let playing_duration = Arc::new(RwLock::new(Duration::from_secs(0))); - - let gain_factor = song.song.gain_factor; - let pause_stream2 = pause_stream.clone(); - let playing_duration2 = playing_duration.clone(); - let command_tx = self.command_tx.clone(); - - let stream = cpal::default_host() - .default_output_device() - .expect("Failed to get default output device") - .build_output_stream::( - &config, - move |dest, _info| { - if pause_stream2.load(std::sync::atomic::Ordering::Relaxed) { - dest.fill(0.0); - return; - } - - let mut duration = playing_duration2.write().unwrap(); - - let mut byte_count = 0; - while byte_count < dest.len() { - if buffer.len() < dest.len() { - let (sample_buffer, end_of_stream) = (song.decoder)().unwrap(); - if let Some(sample_buffer) = sample_buffer { - buffer.extend(sample_buffer.samples()); - } - - if end_of_stream { - command_tx.send(Command::Skip).unwrap(); - } - } - - buffer - .drain(..(dest.len() - byte_count).min(buffer.len())) - .for_each(|sample| { - dest[byte_count] = sample * gain_factor; - byte_count += 1; - }); - } - - *duration += Duration::from_secs_f64( - dest.len() as f64 / config.channels as f64 / config.sample_rate.0 as f64, - ); - }, - |e| { - warn!("Error in playback stream: {:?}", e); - }, - None, - ) - .expect("Failed to build output stream"); - - Ok((pause_stream, playing_duration, stream)) - } - pub fn run( cache: Arc, ) -> anyhow::Result<(mpsc::Sender, Arc>)> { diff --git a/src/player/playback.rs b/src/player/playback.rs new file mode 100644 index 0000000..aea9dea --- /dev/null +++ b/src/player/playback.rs @@ -0,0 +1,95 @@ +use std::{ + collections::VecDeque, + sync::{atomic::AtomicBool, mpsc, Arc, RwLock}, + time::Duration, +}; + +use cpal::{ + traits::{DeviceTrait, HostTrait}, + StreamConfig, +}; +use log::{debug, warn}; + +use super::{command::Command, loader::LoadedSong}; + +pub struct Playback { + _stream: cpal::Stream, + pub pause: Arc, + pub played_duration: Arc>, +} + +impl Playback { + pub fn new(cmd: mpsc::Sender, mut song: LoadedSong) -> anyhow::Result { + let config = StreamConfig { + channels: song.signal_spec.channels.count() as u16, + sample_rate: cpal::SampleRate(song.signal_spec.rate), + buffer_size: cpal::BufferSize::Default, + }; + debug!("Stream config: {:?}", config); + + let mut buffer = VecDeque::::new(); + + let pause = Arc::new(AtomicBool::new(false)); + let playing_duration = Arc::new(RwLock::new(Duration::from_secs(0))); + + let gain_factor = song.song.gain_factor; + let pause_stream2 = pause.clone(); + let playing_duration2 = playing_duration.clone(); + + let stream = cpal::default_host() + .default_output_device() + .expect("Failed to get default output device") + .build_output_stream::( + &config, + move |dest, _info| { + if pause_stream2.load(std::sync::atomic::Ordering::Relaxed) { + dest.fill(0.0); + return; + } + + let mut duration = playing_duration2.write().unwrap(); + + let mut byte_count = 0; + while byte_count < dest.len() { + if buffer.len() < dest.len() { + let (sample_buffer, eof) = (song.decoder)().unwrap_or_else(|e| { + warn!("Error in decoder: {:?}", e); + (None, false) + }); + + if let Some(s) = sample_buffer { + buffer.extend(s.samples()); + } + + if eof && buffer.is_empty() { + cmd.send(Command::Skip).unwrap(); + break; + } + } + + buffer + .drain(..(dest.len() - byte_count).min(buffer.len())) + .for_each(|sample| { + dest[byte_count] = sample * gain_factor; + byte_count += 1; + }); + } + + *duration += Duration::from_secs_f64( + dest.len() as f64 / config.channels as f64 / config.sample_rate.0 as f64, + ); + }, + |e| { + warn!("Error in playback stream: {:?}", e); + }, + None, + ) + .expect("Failed to build output stream"); + + Ok(Self { + _stream: stream, + pause, + played_duration: playing_duration, + }) + } +} diff --git a/src/song.rs b/src/song.rs index 8b37ec3..06834ca 100644 --- a/src/song.rs +++ b/src/song.rs @@ -509,7 +509,7 @@ impl Song { ))?; let mut probed = symphonia::default::get_probe().format( - &Hint::new().with_extension(extension), + Hint::new().with_extension(extension), source, &FormatOptions { prebuild_seek_index: false, @@ -525,7 +525,7 @@ impl Song { let track = probed .format .tracks() - .into_iter() + .iter() .find(|t| t.codec_params.codec != codecs::CODEC_TYPE_NULL) .ok_or(anyhow::anyhow!("No audio tracks found"))?; @@ -547,14 +547,14 @@ impl Song { .map(|m| { let s = m .tags() - .into_iter() + .iter() .filter_map(|t| t.std_key.map(|k| (k.into(), t.value.clone().into()))) .collect::>(); let o = m .tags() - .into_iter() - .filter(|t| t.std_key == None) + .iter() + .filter(|t| t.std_key.is_none()) .map(|t| (t.key.clone(), t.value.clone().into())) .collect::>(); diff --git a/src/tui/fancy.rs b/src/tui/fancy.rs index dc3ef05..30d0e8b 100644 --- a/src/tui/fancy.rs +++ b/src/tui/fancy.rs @@ -2,7 +2,6 @@ use std::sync::{Arc, RwLock}; use crossterm::event::Event; use image::imageops::FilterType; -use log::trace; use ratatui::{ prelude::{Alignment, Constraint, Direction, Layout, Rect}, style::{Color, Style, Stylize}, @@ -27,7 +26,6 @@ impl Fancy { impl Tui for Fancy { fn draw(&self, area: Rect, f: &mut Frame) -> anyhow::Result<()> { - trace!("locking player"); let player = self.player.read().expect("Failed to lock player"); let standard_tags = Table::new( diff --git a/src/tui/files.rs b/src/tui/files.rs index 4cc66a8..ce9f40c 100644 --- a/src/tui/files.rs +++ b/src/tui/files.rs @@ -96,34 +96,38 @@ impl Files { .expect("Failed to send clear"); } KeyCode::Up => { - self.selected - .last_mut() - .map(|i| *i = i.checked_sub(1).unwrap_or(0)); + if let Some(i) = self.selected.last_mut() { + *i = i.checked_sub(1).unwrap_or(0); + } } KeyCode::Down => { - self.selected.last_mut().map(|i| *i = (*i + 1).min(l - 1)); + if let Some(i) = self.selected.last_mut() { + *i = (*i + 1).min(l - 1); + } } KeyCode::PageUp => { - self.selected - .last_mut() - .map(|i| *i = i.checked_sub(25).unwrap_or(0)); + if let Some(i) = self.selected.last_mut() { + *i = i.checked_sub(25).unwrap_or(0); + } } KeyCode::PageDown => { - self.selected.last_mut().map(|i| *i = (*i + 25).min(l - 1)); + if let Some(i) = self.selected.last_mut() { + *i = (*i + 25).min(l - 1); + } } KeyCode::End => { - self.selected.last_mut().map(|i| *i = l - 1); + if let Some(i) = self.selected.last_mut() { + *i = l - 1; + } } KeyCode::Home => { - self.selected.last_mut().map(|i| *i = 0); + if let Some(i) = self.selected.last_mut() { + *i = 0; + } } KeyCode::Enter => { let selected = *self.selected.last().expect("Failed to get selected index"); - let (f, c) = self - .items()? - .nth(selected) - .expect("Failed to get item") - .clone(); + let (f, c) = self.items()?.nth(selected).expect("Failed to get item"); match c { CacheEntry::File { .. } => { @@ -265,7 +269,7 @@ impl Tui for Files { let selected = *self.selected.last().expect("Failed to get selected index"); let mut table_state = TableState::default() - .with_selected(Some((selected).min(len - 1).max(0) as usize)) + .with_selected(Some((selected).min(len - 1).max(0))) .with_offset({ if len <= area.height as usize { 0 @@ -280,21 +284,7 @@ impl Tui for Files { } }); - let breadcrums = Paragraph::new(Line::from( - Span::from(format!("🔗 {}", self.path.display().to_string())) - .bold() - .light_red(), - )); - - let layout = Layout::new() - .direction(Direction::Vertical) - .constraints([Constraint::Length(1), Constraint::Min(1)]) - .split(inner_area); - - let (path_area, files_area) = (layout[0], layout[1]); - - f.render_widget(breadcrums, path_area); - f.render_stateful_widget(table, files_area, &mut table_state); + f.render_stateful_widget(table, inner_area, &mut table_state); if let Some(search_bar_area) = filter_area { f.render_widget(search_bar, search_bar_area); @@ -342,10 +332,9 @@ impl Tui for Files { let l = self.items()?.count(); - self.selected - .last_mut() - .filter(|i| **i >= l) - .map(|i| *i = l - 1); + if let Some(i) = self.selected.last_mut().filter(|i| **i >= l) { + *i = l - 1; + } Ok(()) } diff --git a/src/tui/mod.rs b/src/tui/mod.rs index aa7e70d..fccd460 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -7,7 +7,7 @@ mod status; mod tabs; use std::{ - sync::{atomic::AtomicBool, mpsc, Arc, Mutex, RwLock}, + sync::{atomic::AtomicBool, mpsc, Arc, RwLock}, time::Duration, }; @@ -30,7 +30,7 @@ use crate::{ use self::{fancy::Fancy, files::Files, queue::Queue, search::Search, status::Status, tabs::Tabs}; -pub const UNKNOWN_STRING: &'static str = ""; +pub const UNKNOWN_STRING: &str = ""; pub fn format_duration(duration: Duration) -> String { let hours = duration.as_secs() / 3600; @@ -49,7 +49,7 @@ pub trait Tui { fn input(&mut self, event: &Event) -> anyhow::Result<()>; } -pub fn tui<'a>( +pub fn tui( _config: Arc, cache: Arc, cmd: mpsc::Sender, diff --git a/src/tui/queue.rs b/src/tui/queue.rs index 8a83167..fcffe67 100644 --- a/src/tui/queue.rs +++ b/src/tui/queue.rs @@ -4,8 +4,8 @@ use crossterm::event::Event; use log::trace; use ratatui::{ prelude::Constraint, - style::{Color, Modifier, Style, Stylize}, - widgets::Table, + style::{Color, Modifier, Stylize}, + widgets::{Table, TableState}, }; use crate::{cache::Cache, player::facade::PlayerFacade, tui::song_table}; @@ -34,18 +34,17 @@ impl Tui for Queue { .queue .iter() .map(|p| self.cache.get(p).unwrap().unwrap().as_file().unwrap()) - .map(|s| song_table::song_row(s)) + .map(song_table::song_row) .collect::>(); let table = Table::new(items.clone()) - .header(song_table::HEADER()) - .fg(Color::Rgb(210, 210, 210)) - .highlight_style( - Style::default() - .fg(Color::LightYellow) + .header( + song_table::HEADER() + .fg(Color::LightBlue) .add_modifier(Modifier::BOLD), ) - .highlight_symbol("⏯️ ") + .fg(Color::Rgb(210, 210, 210)) + .highlight_symbol(" ") .column_spacing(4) .widths(&[ Constraint::Percentage(5), @@ -54,7 +53,11 @@ impl Tui for Queue { Constraint::Percentage(30), ]); - f.render_widget(table, area); + f.render_stateful_widget( + table, + area, + &mut TableState::default().with_selected(Some(0)), + ); Ok(()) } diff --git a/src/tui/search.rs b/src/tui/search.rs index 9a74c7a..2a0f85b 100644 --- a/src/tui/search.rs +++ b/src/tui/search.rs @@ -148,8 +148,8 @@ impl Tui for Search { } fn input(&mut self, event: &Event) -> anyhow::Result<()> { - match event { - Event::Key(KeyEvent { code, .. }) => match code { + if let Event::Key(KeyEvent { code, .. }) = event { + match code { KeyCode::Char(c) => { self.keyword.push(*c); self.update_items(); @@ -159,7 +159,7 @@ impl Tui for Search { self.update_items(); } - if self.keyword.len() == 0 { + if self.keyword.is_empty() { self.items.clear(); } } @@ -181,8 +181,7 @@ impl Tui for Search { self.cmd.send(Command::Enqueue(path.as_path().into()))?; } _ => {} - }, - _ => {} + } } self.selected = self.selected.clamp(0, self.items.len()); diff --git a/src/tui/status.rs b/src/tui/status.rs index efddcdb..43f64da 100644 --- a/src/tui/status.rs +++ b/src/tui/status.rs @@ -1,7 +1,6 @@ use std::sync::{Arc, RwLock}; use itertools::Itertools; -use log::trace; use ratatui::{ prelude::{Constraint, Direction, Layout, Margin, Rect}, style::{Color, Style, Stylize}, @@ -34,7 +33,6 @@ impl Tui for Status { horizontal: 1, })); - trace!("locking player"); let playing = Paragraph::new( if let Some(song) = self.player.read().unwrap().current_song() { let title = song @@ -82,7 +80,6 @@ impl Tui for Status { ) .alignment(ratatui::prelude::Alignment::Center); - trace!("locking player"); let player = self.player.read().unwrap(); let ratio = if let (Some(song), Some(current_time)) = (player.current_song(), player.playing_duration()) @@ -94,7 +91,7 @@ impl Tui for Status { .clamp(0.0, 1.0); let progress = LineGauge::default() - .ratio(ratio as f64) + .ratio(ratio) .line_set(ratatui::symbols::line::DOUBLE) .label("") .gauge_style(Style::default().fg(Color::LightBlue).bg(Color::DarkGray)); diff --git a/src/tui/tabs.rs b/src/tui/tabs.rs index 2aa0679..73e04c2 100644 --- a/src/tui/tabs.rs +++ b/src/tui/tabs.rs @@ -77,8 +77,8 @@ impl Tui for Tabs<'_> { fn input(&mut self, event: &Event) -> anyhow::Result<()> { trace!("Tabs input: {:?}", event); - match event { - Event::Key(KeyEvent { code, .. }) => match code { + if let Event::Key(KeyEvent { code, .. }) = event { + match code { KeyCode::Tab => { self.selected = (self.selected + 1) % self.tabs.len(); } @@ -93,8 +93,7 @@ impl Tui for Tabs<'_> { let content = self.tabs.get_mut(self.selected).expect("Tab not found"); content.1.input(event)?; } - }, - _ => {} + } } Ok(())