From 8c3d87133de22f349e9ace8bdfd9c386655e827d Mon Sep 17 00:00:00 2001 From: "alterwain@protonmail.com" Date: Tue, 11 Feb 2025 17:32:15 +0300 Subject: [PATCH] modified: src/main_screen.rs modified: src/playlist_icon.rs --- src/main_screen.rs | 16 ++++++---- src/playlist_icon.rs | 71 +++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/main_screen.rs b/src/main_screen.rs index afd2c9a..677c097 100644 --- a/src/main_screen.rs +++ b/src/main_screen.rs @@ -261,7 +261,7 @@ impl MainScreen { for (i, row) in rows.iter().enumerate() { let cols = Layout::default() .direction(Direction::Horizontal) - .constraints(vec![Constraint::Length(16); 2]) // Three columns + .constraints(vec![Constraint::Percentage(33); 3]) // Three columns .split(*row); for (j, col) in cols.iter().enumerate() { @@ -270,13 +270,19 @@ impl MainScreen { let p = &v[index]; /*let url_cl = p.thumbnail_url.clone(); - let s = url_cl.lines().map(Line::from).collect::>(); + let s = url_cl.lines().map(Line::from).collect::>();*/ - let paragraph = Paragraph::new(s) + let paragraph = Paragraph::new(Line::from(p.name.clone())) .block(Block::default().borders(Borders::ALL)) - .style(Style::default());*/ + .style(Style::default()); - frame.render_widget(p.thumbnail.clone(), *col); + let pl = Layout::default() + .direction(Direction::Vertical) + .constraints([Constraint::Percentage(70), Constraint::Percentage(30)]) + .split(*col); + + frame.render_widget(p.thumbnail.clone(), pl[0]); + frame.render_widget(paragraph, pl[1]); } } } diff --git a/src/playlist_icon.rs b/src/playlist_icon.rs index 884994d..fbbed9c 100644 --- a/src/playlist_icon.rs +++ b/src/playlist_icon.rs @@ -1,34 +1,30 @@ -use std::collections::HashSet; - -use color_eyre::owo_colors::OwoColorize; -use image::{DynamicImage, GenericImageView}; -use ratatui::{ - buffer::Buffer, - layout::Rect, - style::{Color, Style, Stylize}, - widgets::Widget, -}; +use image::DynamicImage; +use ratatui::{buffer::Buffer, layout::Rect, style::Color, widgets::Widget}; #[derive(Default, Clone)] pub struct PlaylistIcon { - colors: [[u8; 3]; 8], + colors: Vec<[u8; 3]>, } impl PlaylistIcon { pub fn new(img: DynamicImage) -> Self { - let pixels = img - .resize_exact(8, 8, image::imageops::FilterType::Nearest) - .to_rgb8() - .pixels() - .map(|p| p.0) - .collect::>() + let img_rgb = img.to_rgb8(); + let pixels = img_rgb.as_raw(); + + let r = color_thief::get_palette(pixels, color_thief::ColorFormat::Rgb, 10, 4) + .unwrap() .iter() - .copied() + .map(|c| [c.r, c.g, c.b]) .collect::>(); - Self { - colors: pixels[..8].try_into().unwrap(), - } + Self { colors: r } + } + + fn lerp(a: &[u8; 3], b: &[u8; 3], n: f32) -> [u8; 3] { + let r = (b[0] as f32 - a[0] as f32) * n + b[0] as f32; + let g = (b[1] as f32 - a[1] as f32) * n + b[1] as f32; + let b = (b[2] as f32 - a[2] as f32) * n + b[2] as f32; + [r as u8, g as u8, b as u8] } } @@ -36,17 +32,30 @@ impl Widget for PlaylistIcon { fn render(self, area: Rect, buf: &mut Buffer) { let mut i = 0; - for x in area.left()..area.right() { - for y in area.top()..area.bottom() { - let color = self.colors[i]; - buf.set_string( - x, - y, - "█", - Style::default().fg(Color::Rgb(color[0], color[1], color[2])), - ); - i = if i >= self.colors.len() - 1 { 0 } else { i + 1 }; + let start = self.colors.first().unwrap_or(&[255u8, 255u8, 255u8]); + let end = &[0u8, 0u8, 0u8]; + + let mut c = *start; + + for y in area.top()..area.bottom() { + for x in area.left()..area.right() { + let n = (((area.bottom() - y).pow(2) + (area.right() - x).pow(2)) as f32).sqrt(); + c = PlaylistIcon::lerp(start, end, n); + buf[(x, y)] + .set_char(' ') + .set_bg(Color::Rgb(c[0], c[1], c[2])) + .set_fg(Color::Rgb(c[0], c[1], c[2])); } + i = match self.colors.len() { + 0 => 0, + _ => { + if i >= self.colors.len() - 1 { + 0 + } else { + i + 1 + } + } + }; } } }