Had AI add code documentation/comments

This commit is contained in:
2025-07-30 22:06:18 -07:00
parent e0ee903f1a
commit d4067bb001

View File

@@ -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());