diff --git a/.gitignore b/.gitignore index ea8c4bf..ee44a9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ /target +/result +/http-cacache \ No newline at end of file diff --git a/flake.nix b/flake.nix index f67dba3..ace55bc 100644 --- a/flake.nix +++ b/flake.nix @@ -92,14 +92,14 @@ in rec { checks = { - rustnix = cargoNix.rootCrate.build.override { + rshell = cargoNix.rootCrate.build.override { runTests = true; }; }; packages = { - rustnix = cargoNix.rootCrate.build; - default = packages.rustnix; + rshell = cargoNix.rootCrate.build; + default = packages.rshell; inherit (pkgs) rust-toolchain; diff --git a/nix/devshell/flake-module.nix b/nix/devshell/flake-module.nix index 84dfaa0..6d0cb07 100644 --- a/nix/devshell/flake-module.nix +++ b/nix/devshell/flake-module.nix @@ -6,7 +6,21 @@ config.perSystem = { pkgs , ... - }: { + }: let + packages = with pkgs; [ + libxkbcommon + libGL + dbus + + wayland + + xorg.libXcursor + xorg.libXrandr + xorg.libXi + xorg.libX11 + openssl + ]; + in { config.devshells.default = { imports = [ "${inputs.devshell}/extra/language/c.nix" @@ -16,42 +30,29 @@ devshell = { name = "rshell devshell"; - packages = with pkgs; [ - libxkbcommon - libGL - dbus - - wayland - - xorg.libXcursor - xorg.libXrandr - xorg.libXi - xorg.libX11 - openssl - pkg-config - ]; + packages = packages ++ [ pkgs.pkg-config ]; }; + env = [{ + name = "LD_LIBRARY_PATH"; + value = lib.makeLibraryPath packages; + } { + name = "PKG_CONFIG_PATH"; + value = lib.concatStringsSep ":" + ( map + ( pkg: "${pkg.dev}/lib/pkgconfig" ) + ( packages ) + ); + #"${pkgs.openssl.dev}/lib/pkgconfig"; + }]; + commands = with pkgs; [ { package = rust-toolchain; category = "rust"; } ]; language.c = { libraries = - (with pkgs; [ - libxkbcommon - libGL - dbus - - wayland - - xorg.libXcursor - xorg.libXrandr - xorg.libXi - xorg.libX11 - openssl - pkg-config - ]) ++ + packages ++ (lib.optional pkgs.stdenv.isDarwin pkgs.libiconv); }; }; diff --git a/src/main.rs b/src/main.rs index 19b3c10..abc3f7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,18 @@ -use cushy::{Open, PendingApp, Run, TokioRuntime}; +use cushy::{styles::{components::DefaultBackgroundColor, Color}, widget::MakeWidget, Open, PendingApp, Run, TokioRuntime}; mod spotify; mod vibrancy; fn main() -> cushy::Result { let mut app = PendingApp::new(TokioRuntime::default()); + spotify::spotify_controls() + .centered() + .with(&DefaultBackgroundColor, Color::CLEAR_WHITE) + .into_window() + .transparent() + .app_name("rshell") .open(&mut app)?; app.run() diff --git a/src/spotify.rs b/src/spotify.rs index 058aa2d..8287218 100644 --- a/src/spotify.rs +++ b/src/spotify.rs @@ -1,9 +1,10 @@ use std::{sync::{Arc, Mutex}, thread, time::Duration}; +use http_cache_reqwest::{CACacheManager, Cache, CacheMode, HttpCache, HttpCacheOptions}; use mpris::{LoopStatus, PlaybackStatus, PlayerFinder}; -use cushy::{kludgine::{AnyTexture, LazyTexture}, styles::{components::WidgetBackground, Color}, value::{Destination, Dynamic, IntoReader, Source}, widget::MakeWidget, widgets::Image, Open, PendingApp}; -use palette::Srgb; +use cushy::{figures::{units::Lp, Size}, kludgine::{AnyTexture, LazyTexture}, styles::{components::WidgetBackground, Color, Dimension, DimensionRange}, value::{Destination, Dynamic, IntoReader, Source}, widget::MakeWidget, widgets::{image::ImageCornerRadius, Image}}; use reqwest::Client; +use reqwest_middleware::ClientBuilder; use image::{self, Rgb}; use tokio::{runtime, task::JoinHandle}; use crate::vibrancy::Vibrancy; @@ -22,30 +23,37 @@ struct PlayingTrack { loop_status: LoopStatus, } +/// Renders spotify control widget, the small one pub fn spotify_controls() -> impl MakeWidget { let (progress, track) = get_track_dynamics(); let (texture, vibrancy) = get_texture_dynamic(track.clone()); - track.map_each(|track| { - if let Some(track) = track { - format!( - "{} - {}", - track.artist, - track.title, - ) - } else { - "No track playing".to_string() - } - }) - .to_label() - .centered() - .pad() - .and( - Image::new(texture) - ) - .into_rows() - .with(&WidgetBackground, vibrancy.map_each(|vib| vib.dark.unwrap_or(Color::BLACK).into())) - .pad() + const IMAGE_SIZE: i32 = 16 /* lineheight */ + 2 * 6 /* padding */ + 8; // Why the 8 there? I don't know, but it works. + + Image::new(texture) + .aspect_fit() + // .with(&ImageCornerRadius, Lp::points(6)) + // default pad is 6, default line height is 16 + .size(Size::new(DimensionRange::from(Dimension::Lp(Lp::points(IMAGE_SIZE))), DimensionRange::from(Dimension::Lp(Lp::points(IMAGE_SIZE))))) + .and( + track.map_each(|track| { + if let Some(track) = track { + format!( + "{} - {}", + track.artist, + track.title, + ) + } else { + "No track playing".to_string() + } + }) + .to_label() + .centered() + .pad() + ) + .into_columns() + .with(&WidgetBackground, Color::CLEAR_WHITE) // vibrancy.map_each(|vib| vib.muted.unwrap_or(Color::BLACK).into())) + // .size(Size::new(DimensionRange::default(), DimensionRange::from(Dimension::Lp(Lp::points(28))))) } fn get_empty_texture() -> AnyTexture { @@ -63,12 +71,6 @@ fn tokio_runtime() -> &'static runtime::Handle { use std::sync::OnceLock; use std::time::Duration; - use cushy::value::{Destination, Dynamic}; - use cushy::widget::MakeWidget; - use cushy::widgets::progress::Progressable; - use cushy::Run; - use tokio::time::sleep; - static RUNTIME: OnceLock = OnceLock::new(); RUNTIME.get_or_init(|| { let rt = runtime::Builder::new_multi_thread() @@ -100,7 +102,13 @@ pub struct ImageVibrancy { } fn get_texture_dynamic(track: Dynamic>) -> (Dynamic, Dynamic) { - let client = Client::new(); + let client = ClientBuilder::new(Client::new()) + .with(Cache(HttpCache { + mode: CacheMode::Default, + manager: CACacheManager::default(), + options: HttpCacheOptions::default(), + })) + .build(); let texture = Dynamic::new(get_empty_texture());