Add dynamic title bar colors based on player state

Title bar background color changes:
- Gray: Stopped or Paused
- Green: Playing
- Red: Error (when last_error is set)

Main content border remains gray.
This commit is contained in:
2025-12-13 10:34:55 +01:00
parent b7cc219f40
commit 821a844fe0
3 changed files with 21 additions and 6 deletions

View File

@@ -88,6 +88,7 @@ pub struct AppState {
pub last_click_is_playlist: bool, pub last_click_is_playlist: bool,
pub context_menu: Option<ContextMenu>, pub context_menu: Option<ContextMenu>,
pub play_mode: PlayMode, pub play_mode: PlayMode,
pub last_error: Option<String>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -141,6 +142,7 @@ impl AppState {
last_click_is_playlist: false, last_click_is_playlist: false,
context_menu: None, context_menu: None,
play_mode: PlayMode::Normal, play_mode: PlayMode::Normal,
last_error: None,
} }
} }

View File

@@ -57,7 +57,7 @@ pub fn render(frame: &mut Frame, state: &mut AppState, player: &mut Player) -> (
Span::styled(playlist_text, playlist_style), Span::styled(playlist_text, playlist_style),
]); ]);
// Create one border around the entire content area // Create one border around the entire content area with fixed gray border
let main_block = Block::default() let main_block = Block::default()
.borders(Borders::ALL) .borders(Borders::ALL)
.title(title) .title(title)
@@ -384,12 +384,17 @@ fn render_right_panel(frame: &mut Frame, state: &mut AppState, area: Rect, _tab_
} }
fn render_title_bar(frame: &mut Frame, state: &AppState, player: &mut Player, area: Rect) { fn render_title_bar(frame: &mut Frame, state: &AppState, player: &mut Player, area: Rect) {
// Default to stopped if we can't query MPV // Get player state
let player_state = player.get_player_state().unwrap_or(PlayerState::Stopped); let player_state = player.get_player_state().unwrap_or(PlayerState::Stopped);
let background_color = match player_state {
// Title bar background color: red for error, gray for stopped/paused, green for playing
let background_color = if state.last_error.is_some() {
Theme::error()
} else {
match player_state {
PlayerState::Playing => Theme::success(), // Green for playing PlayerState::Playing => Theme::success(), // Green for playing
PlayerState::Paused => Theme::highlight(), // Blue for paused PlayerState::Paused | PlayerState::Stopped => Theme::border(), // Gray for paused/stopped
PlayerState::Stopped => Theme::dim_foreground(), // Gray for stopped }
}; };
// Split the title bar into left and right sections // Split the title bar into left and right sections

View File

@@ -34,6 +34,10 @@ impl Theme {
Color::Rgb(215, 175, 95) // #d7af5f Color::Rgb(215, 175, 95) // #d7af5f
} }
pub fn normal_red() -> Color {
Color::Rgb(215, 95, 95) // #d75f5f
}
// Semantic mappings // Semantic mappings
pub fn secondary_text() -> Color { pub fn secondary_text() -> Color {
Self::foreground() Self::foreground()
@@ -59,6 +63,10 @@ impl Theme {
Self::normal_yellow() Self::normal_yellow()
} }
pub fn error() -> Color {
Self::normal_red()
}
// Styles // Styles
pub fn widget_border_style() -> Style { pub fn widget_border_style() -> Style {
Style::default().fg(Self::border()).bg(Self::background()) Style::default().fg(Self::border()).bg(Self::background())