diff --git a/modules/home/ags/app/style.scss b/modules/home/ags/app/style.scss
index e3ab040..3f2d2ed 100644
--- a/modules/home/ags/app/style.scss
+++ b/modules/home/ags/app/style.scss
@@ -285,6 +285,76 @@ $module-bg: transparentize($base02, 0.4);
}
}
+.media-section {
+ margin-top: 10px;
+ border-top: 1px solid $base02;
+ padding-top: 8px;
+}
+
+.player {
+ .cover {
+ min-width: 48px;
+ min-height: 48px;
+ padding: 12px;
+ border-radius: 8px;
+ background-color: transparentize($base02, 0.4);
+ background-size: cover;
+ background-position: center;
+ }
+
+ .player-title {
+ font-weight: bold;
+ }
+
+ .player-artist {
+ font-size: 0.85em;
+ opacity: 0.7;
+ }
+}
+
+.position {
+ trough {
+ background: $base03;
+ border-radius: 999px;
+ min-height: 10px;
+
+ highlight {
+ background: $base0D;
+ border-radius: 999px;
+ }
+
+ slider {
+ min-width: 12px;
+ min-height: 12px;
+ background: $base05;
+ border-radius: 999px;
+ }
+ }
+}
+
+.player-ctl {
+ padding: 4px 6px;
+ border-radius: 6px;
+
+ icon {
+ font-size: 14px;
+ }
+
+ &:hover {
+ background: transparentize($base05, 0.88);
+ }
+}
+
+.bar .media {
+ icon {
+ font-size: 12px;
+ }
+
+ .media-title {
+ font-size: 0.9em;
+ }
+}
+
.wifi-section {
margin-top: 10px;
border-top: 1px solid $base02;
diff --git a/modules/home/ags/app/widget/Bar.tsx b/modules/home/ags/app/widget/Bar.tsx
index 273b670..c080d48 100644
--- a/modules/home/ags/app/widget/Bar.tsx
+++ b/modules/home/ags/app/widget/Bar.tsx
@@ -2,6 +2,7 @@ import { App, Astal, Gdk, Gtk } from "astal/gtk3"
import Workspaces from "./Workspaces"
import Logo from "./Logo"
import Clock from "./Clock"
+import { MediaButton } from "./Media"
import QuickSettings from "./QuickSettings"
const RADIUS = 12
@@ -85,7 +86,9 @@ export default function Bar(gdkmonitor: Gdk.Monitor) {
className="bar-center"
halign={Gtk.Align.CENTER}
valign={Gtk.Align.CENTER}
- />
+ >
+
+
+ player.available ? player.position : -1,
+ )
+
+ return (
+
+
+ c !== "" ? `background-image: url('${encodeURI(`file://${c}`)}')` : "",
+ )}
+ >
+ c === "")}
+ />
+
+
+
+
+
+
+ )
+}
+
+export function MediaSection() {
+ const players = bind(mpris, "players")
+ return (
+ ps.length > 0)}>
+ {players.as((ps) => ps.map((p) => PlayerCard(p)))}
+
+ )
+}
+
+// the players property only notifies on connect/disconnect, so the bar
+// button tracks the first player directly to follow track changes
+let player: AstalMpris.Player | null = null
+let hookIds: Array = []
+
+const hasPlayer = Variable(false)
+const title = Variable("")
+const icon = Variable(NO_ART)
+
+function sync() {
+ const current = mpris.players[0] ?? null
+ if (current !== player) {
+ hookIds.forEach((id) => player?.disconnect(id))
+ hookIds = []
+ player = current
+ if (player) {
+ hookIds = [
+ player.connect("notify::title", sync),
+ player.connect("notify::entry", sync),
+ ]
+ }
+ }
+ hasPlayer.set(player !== null)
+ title.set(player?.title || "")
+ icon.set(player ? playerIcon(player.entry) : "")
+}
+
+mpris.connect("notify::players", sync)
+sync()
+
+export function MediaButton() {
+ return (
+
+ )
+}
diff --git a/modules/home/ags/app/widget/QuickSettings.tsx b/modules/home/ags/app/widget/QuickSettings.tsx
index 19192f6..2e97edd 100644
--- a/modules/home/ags/app/widget/QuickSettings.tsx
+++ b/modules/home/ags/app/widget/QuickSettings.tsx
@@ -7,6 +7,7 @@ import Dropdown from "./Dropdown"
import { wifiIcon, WifiSection } from "./Wifi"
import { bluetoothIndicator, BluetoothSection } from "./Bluetooth"
import { BrightnessRow } from "./Brightness"
+import { MediaSection } from "./Media"
import { batteryIcon, batteryPercent, BatterySection } from "./Battery"
import { NotificationCard } from "./Notifications"
@@ -145,6 +146,7 @@ export default function QuickSettings(gdkmonitor: Gdk.Monitor) {
+