Had AI add code documentation/comments
This commit is contained in:
132
src/main.rs
132
src/main.rs
@@ -16,19 +16,38 @@ use ratatui::{
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use std::{io, time::Duration};
|
||||
|
||||
/// Application state
|
||||
/// Main application state holding all the data needed for the TUI
|
||||
struct App {
|
||||
/// MPD client connection for interacting with the music player daemon
|
||||
client: Client,
|
||||
/// Currently playing song, if any
|
||||
current_song: Option<Song>,
|
||||
/// List of songs in the current playlist, deduplicated by file path
|
||||
playlist: Vec<Song>,
|
||||
/// Current MPD server status including playback state, volume, etc.
|
||||
status: mpd::Status,
|
||||
selected_index: usize, // Currently selected song in the playlist
|
||||
scroll_offset: usize, // Offset for playlist scrolling
|
||||
show_help: bool, // Whether to show the help panel
|
||||
/// Index of the currently selected song in the playlist (for UI highlighting)
|
||||
selected_index: usize,
|
||||
/// Number of items to skip from the start of playlist (for scrolling)
|
||||
scroll_offset: usize,
|
||||
/// Whether to display the help overlay
|
||||
show_help: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
/// Create a new App instance, connecting to MPD
|
||||
/// Creates a new application instance and initializes the MPD connection
|
||||
///
|
||||
/// This function:
|
||||
/// 1. Connects to the MPD server at localhost:6600
|
||||
/// 2. Retrieves initial server status
|
||||
/// 3. Gets the current playlist
|
||||
/// 4. Gets the currently playing song
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - Cannot connect to MPD server
|
||||
/// - Failed to retrieve initial state from server
|
||||
fn new() -> Result<Self, anyhow::Error> {
|
||||
let mut client = Client::connect("127.0.0.1:6600")?;
|
||||
let status = client.status()?;
|
||||
@@ -46,7 +65,22 @@ impl App {
|
||||
})
|
||||
}
|
||||
|
||||
/// Refresh the application state from MPD
|
||||
/// Updates the application state by fetching fresh data from the MPD server
|
||||
///
|
||||
/// This function:
|
||||
/// 1. Updates the server status (play state, volume, etc)
|
||||
/// 2. Updates the currently playing song
|
||||
/// 3. Refreshes the playlist, removing any duplicates
|
||||
/// 4. Adjusts scroll position to keep selected item visible
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `playlist_height` - The number of playlist items that can be displayed at once
|
||||
/// Used to adjust scrolling to keep selected item visible
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if communication with MPD server fails
|
||||
fn refresh(&mut self, playlist_height: usize) -> Result<(), anyhow::Error> {
|
||||
self.status = self.client.status()?;
|
||||
self.current_song = self.client.currentsong()?;
|
||||
@@ -79,21 +113,33 @@ impl App {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Move selection up, adjusting scroll if necessary
|
||||
/// Moves the selection cursor up one item in the playlist
|
||||
///
|
||||
/// Will not move past the first item (index 0)
|
||||
fn move_up(&mut self) {
|
||||
if self.selected_index > 0 {
|
||||
self.selected_index -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Move selection down, adjusting scroll if necessary
|
||||
/// Moves the selection cursor down one item in the playlist
|
||||
///
|
||||
/// Will not move past the last item in the playlist
|
||||
fn move_down(&mut self) {
|
||||
if self.selected_index + 1 < self.playlist.len() {
|
||||
self.selected_index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Update scroll offset to ensure selected item is visible
|
||||
/// Adjusts the scroll offset to ensure the selected item remains visible
|
||||
///
|
||||
/// This function handles two cases:
|
||||
/// 1. Selected item is below visible area -> Scroll down to show it
|
||||
/// 2. Selected item is above visible area -> Scroll up to show it
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `height` - Number of items that can be displayed at once
|
||||
fn update_scroll(&mut self, height: usize) {
|
||||
if self.selected_index >= self.scroll_offset + height {
|
||||
self.scroll_offset = self.selected_index.saturating_sub(height) + 1;
|
||||
@@ -103,8 +149,19 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
/// Main entry point for the Sonnet MPD client
|
||||
///
|
||||
/// Sets up the terminal UI environment and runs the main application loop.
|
||||
/// Handles cleanup when the application exits.
|
||||
///
|
||||
/// # Error
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - Terminal setup fails
|
||||
/// - MPD connection fails
|
||||
/// - Terminal restoration fails
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// Setup terminal
|
||||
// Setup terminal in raw mode and alternate screen
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen)?;
|
||||
@@ -127,9 +184,25 @@ fn main() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Main application loop handling user input and UI updates
|
||||
///
|
||||
/// This function:
|
||||
/// 1. Continuously updates the application state
|
||||
/// 2. Redraws the terminal UI
|
||||
/// 3. Handles keyboard input events
|
||||
/// 4. Controls MPD playback based on user commands
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `terminal` - The terminal interface for rendering
|
||||
/// * `app` - The application state
|
||||
///
|
||||
/// # Type Parameters
|
||||
///
|
||||
/// * `B` - The terminal backend type (allows for different terminal implementations)
|
||||
fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> anyhow::Result<()> {
|
||||
loop {
|
||||
// Get the available height for the playlist
|
||||
// Calculate available height for playlist display
|
||||
let height = terminal.size()?.height.saturating_sub(12) as usize;
|
||||
app.refresh(height)?;
|
||||
|
||||
@@ -182,7 +255,20 @@ fn run_app<B: Backend>(terminal: &mut Terminal<B>, app: &mut App) -> anyhow::Res
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to create a centered rect using up certain percentage of the available rect
|
||||
/// Creates a centered rectangle for modal overlays like the help panel
|
||||
///
|
||||
/// This function creates a rectangle that is centered both horizontally and vertically
|
||||
/// within the given space. The size is specified as percentages of the available space.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `percent_x` - Width of the rectangle as a percentage of parent width
|
||||
/// * `percent_y` - Height of the rectangle as a percentage of parent height
|
||||
/// * `r` - The parent rectangle within which to center the new rectangle
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A new rectangle centered within the parent, with the specified size
|
||||
fn centered_rect(percent_x: u16, percent_y: u16, r: ratatui::layout::Rect) -> ratatui::layout::Rect {
|
||||
// Calculate the width and height of the popup
|
||||
let popup_layout = Layout::default()
|
||||
@@ -204,13 +290,29 @@ fn centered_rect(percent_x: u16, percent_y: u16, r: ratatui::layout::Rect) -> ra
|
||||
.split(popup_layout[1])[1]
|
||||
}
|
||||
|
||||
/// Renders the terminal user interface
|
||||
///
|
||||
/// The UI is composed of several sections:
|
||||
/// - Header: Shows the application title
|
||||
/// - Status: Displays current playback status and song info
|
||||
/// - Playlist: Shows the list of songs with selection highlight
|
||||
/// - Help Panel: Optional overlay showing keyboard shortcuts
|
||||
///
|
||||
/// The layout is organized vertically with fixed heights for header and status,
|
||||
/// and the playlist taking the remaining space.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `f` - Frame for rendering UI elements
|
||||
/// * `app` - Application state containing all the data to display
|
||||
pub(crate) fn ui(f: &mut Frame, app: &App) {
|
||||
// Create the main vertical layout
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([
|
||||
Constraint::Length(3), // Header
|
||||
Constraint::Length(10), // Status
|
||||
Constraint::Min(0) // Playlist
|
||||
Constraint::Length(3), // Header: Fixed 3 lines
|
||||
Constraint::Length(10), // Status: Fixed 10 lines
|
||||
Constraint::Min(0) // Playlist: All remaining space
|
||||
].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
|
Reference in New Issue
Block a user