island: an idle pill while no player is open

the island is always there now: with no player it shows a pill with a
drawn music note and 'Nothing playing', in the cover gradient with the
pink glow. click-through, static (draws once). checked on all 4 monitors
This commit is contained in:
server2
2026-10-08 11:45:26 +02:00
parent ecd9a8d3b0
commit 2870ebbd13
2 changed files with 36 additions and 10 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
A Dynamic-Island-style media widget for Amane (Rust Wayland shell library), running on Hyprland. It sits as a small pill at the top centre of the screen and opens into a now-playing card.
- **Pill:** cover thumbnail, title, 7 live bars from the shown player's own sound (lows left, highs right, growing up and down from the middle), or a pause sign.
- **Pill:** cover thumbnail, title, 7 live bars from the shown player's own sound (lows left, highs right, growing up and down from the middle), or a pause sign. With no player open, an idle pill: a music note and "Nothing playing".
- **Card:** a still CD of the cover ringed by 40 cava "candles", title and artist, a seekable time bar, previous / play-pause / next.
- **Player switcher** ("VIA …" chip): every MPRIS player; picking one pins it, otherwise the island follows whichever plays.
- **Output switcher:** moves only the shown player's audio to another device.
+35 -9
View File
@@ -4,7 +4,7 @@ use std::thread;
use std::time::{Duration, Instant};
use amane::{
Animation, Arc, Argument, Blend, Bus, Canvas, Cap, Center, Color, Column, Easing, End, Full, Gradient,
Animation, Arc, Argument, Blend, Bus, Canvas, Cap, Center, Circle, Color, Column, Easing, End, Full, Gradient,
Image, InputArea, Layer, LayerWindow, Line, Media, MediaPlayer, Monitor, Padding, Palette, Parent, Path,
Pointer, Rectangle, Row, Scroll, ScrollArea, Service, Shadow, Shape, SpaceBetween, Stack,
Start, Text, Vertical, Weight, Widget, Workspaces, Zone, children, shapes,
@@ -267,15 +267,21 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
.space(Zone::Ignore)
.namespace("magic-island");
/*
* no player: an empty window that lets every click through, never visible(false).
* hyprland 0.56 configures a layer surface before its first commit, so a window
* that starts hidden gets a size anyway: amane then logs "no child to draw" and,
* with nothing ever drawn, waits for frame callbacks that never come, and the
* island never showed up once a player started
*/
let Some(player) = shown(&media, island.selected.as_deref()) else {
return window.click_through().child(Rectangle::new().width(0.0).height(0.0));
/*
* nothing playing: a quiet pill, so the island is always there. never
* visible(false): hyprland 0.56 configures a layer surface before its first
* commit, so a window that starts hidden gets a size anyway, amane logs "no
* child to draw" and waits for frame callbacks an undrawn surface never gets
*/
return window.click_through().child(
Rectangle::new()
.width(Parent)
.height(Parent)
.padding(Padding { top: TOP_GAP, right: 0.0, bottom: 0.0, left: 0.0 })
.align_child(Center, Start)
.child(idle(&backdrop_colors(&palette))),
);
};
let (grow, pill, reveal) = phases(if opened_here { island.open.value() } else { 0.0 });
@@ -589,6 +595,19 @@ pub fn faded(color: Color, alpha: u8) -> Color {
Color::rgba(color.red(), color.green(), color.blue(), alpha)
}
// the island while no player is open: a music note and "Nothing playing", glowing like the pill
fn idle(colors: &[Color; 3]) -> Rectangle {
Rectangle::new()
.width(COMPACT_W)
.height(COMPACT_H)
.radius(Full)
.fill(backdrop(colors, 255))
.border(1.0, EDGE)
.shadow(Shadow::drop(PINK).opacity(0.3).blur(22.0))
.align_child(Center, Center)
.child(Row::new(children![icon(Glyph::Note, 15.0, PINK), Text::new("Nothing playing").size(12.0).color(DIM)]).gap(8.0).align(Center))
}
// the pill: cover, title, the player's live levels
fn compact(player: &MediaPlayer, playing: bool, art: &str, levels: &[f32]) -> Rectangle {
Rectangle::new()
@@ -1405,6 +1424,7 @@ enum Glyph {
Muted,
Bluetooth,
Chevron,
Note,
}
// drawn, not typed, so the island looks the same whatever fonts are installed
@@ -1473,6 +1493,12 @@ fn bold_icon(glyph: Glyph, size: f32, color: Color, weight: f32) -> Canvas {
Glyph::Chevron => shapes![
Path::new().move_to(0.12 * s, 0.32 * s).line_to(0.5 * s, 0.7 * s).line_to(0.88 * s, 0.32 * s).stroke(1.5, color).cap(Cap::Round)
],
// an eighth note: round head, stem, a curved flag
Glyph::Note => shapes![
Circle::new().center(0.32 * s, 0.74 * s).radius(0.17 * s).fill(color),
Line::new().from(0.47 * s, 0.74 * s).to(0.47 * s, 0.12 * s).stroke(thin, color).cap(Cap::Round),
Path::new().move_to(0.47 * s, 0.12 * s).quad_to(0.62 * s, 0.3 * s, 0.84 * s, 0.38 * s).stroke(thin, color).cap(Cap::Round),
],
};
Canvas::new().width(size).height(size).shapes(shapes)