ytdlp-gui 0.3.0

a GUI for yt-dlp written in Rust
Documentation
use iced::overlay::menu;
use iced::widget::{
    button, checkbox, container, pick_list, progress_bar, radio, scrollable, text, text_input,
};
use iced::{application, theme, Color};
use iced_aw::{modal, style::card, tabs};
use iced_native::Background;

#[derive(Debug, Clone, Copy, Default)]
pub struct Theme;

const SURFACE: Color = Color::from_rgb(
    0x40 as f32 / 255.0,
    0x44 as f32 / 255.0,
    0x4B as f32 / 255.0,
);

const DISABLED: Color = Color::from_rgb(
    0x30 as f32 / 255.0,
    0x34 as f32 / 255.0,
    0x3B as f32 / 255.0,
);

const PLACEHOLDER: Color = Color::from_rgb(0.4, 0.4, 0.4);

const ACCENT: Color = Color::from_rgb(
    0x6F as f32 / 255.0,
    0xFF as f32 / 255.0,
    0xE9 as f32 / 255.0,
);

const ACTIVE: Color = Color::from_rgb(
    0x72 as f32 / 255.0,
    0x89 as f32 / 255.0,
    0xDA as f32 / 255.0,
);

const HOVERED: Color = Color::from_rgb(
    0x67 as f32 / 255.0,
    0x7B as f32 / 255.0,
    0xC4 as f32 / 255.0,
);

const DANGER: Color = Color::from_rgb(
    0x7b as f32 / 255.0,
    0x67 as f32 / 255.0,
    0xC4 as f32 / 255.0,
);

pub fn ytdlp_gui_theme() -> theme::Theme {
    theme::Theme::custom(theme::Palette {
        background: SURFACE,
        text: Color::WHITE,
        primary: ACTIVE,
        success: HOVERED,
        danger: DANGER,
    })
}

impl application::StyleSheet for Theme {
    type Style = ();

    fn appearance(&self, _style: &Self::Style) -> iced::application::Appearance {
        iced::application::Appearance {
            background_color: SURFACE,
            text_color: Color::WHITE,
        }
    }
}

impl card::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: Self::Style) -> iced_aw::card::Appearance {
        iced_aw::card::Appearance {
            background: SURFACE.into(),
            body_text_color: Color::WHITE,
            border_radius: 5.,
            head_background: ACTIVE.into(),
            head_text_color: Color::WHITE,
            border_color: Color::TRANSPARENT,
            close_color: Color::WHITE,
            ..Default::default()
        }
    }
}

impl modal::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: Self::Style) -> iced_aw::style::modal::Appearance {
        iced_aw::style::modal::Appearance {
            background: Color::from_rgba(0.01, 0.01, 0.01, 0.5).into(),
        }
    }
}

impl tabs::StyleSheet for Theme {
    type Style = ();

    fn active(&self, style: Self::Style, is_active: bool) -> iced_aw::style::tab_bar::Appearance {
        if is_active {
            iced_aw::style::tab_bar::Appearance {
                background: ACTIVE.into(),
                tab_label_background: ACTIVE.into(),
                ..self.hovered(style, is_active)
            }
        } else {
            iced_aw::style::tab_bar::Appearance {
                background: SURFACE.into(),
                tab_label_background: SURFACE.into(),
                ..self.hovered(style, is_active)
            }
        }
    }
    fn hovered(
        &self,
        _style: Self::Style,
        _is_active: bool,
    ) -> iced_aw::style::tab_bar::Appearance {
        iced_aw::style::tab_bar::Appearance {
            background: HOVERED.into(),
            text_color: Color::WHITE,
            border_color: None,
            border_width: 0.,
            icon_color: Color::default(),
            tab_label_background: HOVERED.into(),
            tab_label_border_color: Color::TRANSPARENT,
            tab_label_border_width: 1.,
        }
    }
}

impl container::StyleSheet for Theme {
    type Style = ();

    fn appearance(&self, _style: &Self::Style) -> container::Appearance {
        container::Appearance {
            background: Color::from_rgb8(0x36, 0x39, 0x3F).into(),
            text_color: Color::WHITE.into(),
            ..Default::default()
        }
    }
}

impl text::StyleSheet for Theme {
    type Style = ();

    fn appearance(&self, _style: Self::Style) -> text::Appearance {
        text::Appearance {
            color: Some(Color::WHITE),
        }
    }
}

impl radio::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: &Self::Style, is_active: bool) -> radio::Appearance {
        if is_active {
            radio::Appearance {
                background: SURFACE.into(),
                dot_color: ACTIVE,
                border_width: 1.0,
                border_color: ACTIVE,
                text_color: None,
            }
        } else {
            radio::Appearance {
                background: SURFACE.into(),
                dot_color: ACTIVE,
                border_width: 1.0,
                border_color: ACTIVE,
                text_color: None,
            }
        }
    }

    fn hovered(&self, style: &Self::Style, is_active: bool) -> radio::Appearance {
        radio::Appearance {
            background: Color { a: 0.5, ..SURFACE }.into(),
            ..self.active(style, is_active)
        }
    }
}

impl text_input::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: &Self::Style) -> text_input::Appearance {
        text_input::Appearance {
            background: SURFACE.into(),
            border_radius: 2.0,
            border_width: 0.0,
            border_color: Color::TRANSPARENT,
            icon_color: Color::TRANSPARENT,
        }
    }

    fn focused(&self, style: &Self::Style) -> text_input::Appearance {
        text_input::Appearance {
            border_width: 1.0,
            border_color: ACCENT,
            ..self.active(style)
        }
    }

    fn placeholder_color(&self, _style: &Self::Style) -> Color {
        PLACEHOLDER
    }

    fn value_color(&self, _style: &Self::Style) -> Color {
        Color::WHITE
    }

    fn selection_color(&self, _style: &Self::Style) -> Color {
        ACTIVE
    }

    fn disabled_color(&self, _style: &Self::Style) -> Color {
        DISABLED
    }

    fn disabled(&self, style: &Self::Style) -> text_input::Appearance {
        text_input::Appearance {
            ..self.active(style)
        }
    }
}

impl button::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: &Self::Style) -> button::Appearance {
        button::Appearance {
            background: ACTIVE.into(),
            border_radius: 3.0,
            text_color: Color::WHITE,
            ..Default::default()
        }
    }

    fn hovered(&self, style: &Self::Style) -> button::Appearance {
        button::Appearance {
            background: HOVERED.into(),
            text_color: Color::WHITE,
            ..self.active(style)
        }
    }

    fn pressed(&self, style: &Self::Style) -> button::Appearance {
        button::Appearance {
            border_width: 1.0,
            border_color: Color::WHITE,
            ..self.hovered(style)
        }
    }
}

impl progress_bar::StyleSheet for Theme {
    type Style = ();

    fn appearance(&self, _style: &Self::Style) -> progress_bar::Appearance {
        progress_bar::Appearance {
            background: SURFACE.into(),
            bar: ACTIVE.into(),
            border_radius: 5.0,
        }
    }
}

impl checkbox::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: &Self::Style, is_checked: bool) -> checkbox::Appearance {
        checkbox::Appearance {
            background: if is_checked { ACTIVE } else { SURFACE }.into(),
            border_radius: 2.0,
            border_width: 1.0,
            border_color: ACTIVE,
            text_color: None,
            icon_color: Color::WHITE,
        }
    }

    fn hovered(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance {
        checkbox::Appearance {
            background: Color {
                a: 0.8,
                ..if is_checked { ACTIVE } else { SURFACE }
            }
            .into(),
            ..self.active(style, is_checked)
        }
    }
}

impl pick_list::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: &<Self as pick_list::StyleSheet>::Style) -> pick_list::Appearance {
        pick_list::Appearance {
            text_color: Color::WHITE,
            placeholder_color: PLACEHOLDER,
            handle_color: Color::WHITE,
            background: Background::Color(SURFACE),
            border_radius: 2.0,
            border_width: 0.0,
            border_color: Color::TRANSPARENT,
        }
    }

    fn hovered(&self, style: &<Self as pick_list::StyleSheet>::Style) -> pick_list::Appearance {
        pick_list::Appearance {
            border_color: HOVERED,
            background: Background::Color(HOVERED),
            ..self.active(style)
        }
    }
}

impl scrollable::StyleSheet for Theme {
    type Style = ();

    fn active(&self, _style: &Self::Style) -> scrollable::Scrollbar {
        scrollable::Scrollbar {
            background: None,
            border_radius: 2.,
            border_width: 0.,
            border_color: Color::TRANSPARENT,
            scroller: scrollable::Scroller {
                color: ACCENT,
                border_radius: 0.,
                border_width: 0.,
                border_color: Color::TRANSPARENT,
            },
        }
    }

    fn hovered(&self, style: &Self::Style, is_mouse_over_scrollbar: bool) -> scrollable::Scrollbar {
        if is_mouse_over_scrollbar {
            scrollable::Scrollbar {
                scroller: scrollable::Scroller {
                    color: HOVERED,
                    border_width: 1.,
                    ..self.active(style).scroller
                },
                ..self.active(style)
            }
        } else {
            scrollable::Scrollbar {
                scroller: scrollable::Scroller {
                    color: HOVERED,
                    ..self.active(style).scroller
                },
                ..self.active(style)
            }
        }
    }
}

impl menu::StyleSheet for Theme {
    type Style = ();

    fn appearance(&self, _style: &Self::Style) -> menu::Appearance {
        menu::Appearance {
            text_color: Color::WHITE,
            background: Background::Color(ACCENT),
            border_width: 0.,
            border_radius: 0.,
            border_color: Color::TRANSPARENT,
            selected_text_color: Color::BLACK,
            selected_background: Background::Color(ACTIVE),
        }
    }
}