summaryrefslogtreecommitdiff
path: root/examples/gtk3/lua/media-player
diff options
context:
space:
mode:
Diffstat (limited to 'examples/gtk3/lua/media-player')
-rw-r--r--examples/gtk3/lua/media-player/README.md5
-rw-r--r--examples/gtk3/lua/media-player/init.lua19
-rw-r--r--examples/gtk3/lua/media-player/lib.lua38
-rw-r--r--examples/gtk3/lua/media-player/style.scss1
-rw-r--r--examples/gtk3/lua/media-player/widget/MediaPlayer.lua144
-rw-r--r--examples/gtk3/lua/media-player/widget/MediaPlayer.scss56
6 files changed, 263 insertions, 0 deletions
diff --git a/examples/gtk3/lua/media-player/README.md b/examples/gtk3/lua/media-player/README.md
new file mode 100644
index 0000000..4e3d237
--- /dev/null
+++ b/examples/gtk3/lua/media-player/README.md
@@ -0,0 +1,5 @@
+# Media Player
+
+![mpris](https://github.com/user-attachments/assets/891e9706-74db-4505-bd83-c3628d7b4fd0)
+
+Using [Mpris](https://aylur.github.io/astal/guide/libraries/mpris).
diff --git a/examples/gtk3/lua/media-player/init.lua b/examples/gtk3/lua/media-player/init.lua
new file mode 100644
index 0000000..16ccbfb
--- /dev/null
+++ b/examples/gtk3/lua/media-player/init.lua
@@ -0,0 +1,19 @@
+local astal = require("astal")
+local App = require("astal.gtk3.app")
+local Widget = require("astal.gtk3.widget")
+
+local MprisPlayers = require("widget.MediaPlayer")
+local src = require("lib").src
+
+local scss = src("style.scss")
+local css = "/tmp/style.css"
+
+astal.exec("sass " .. scss .. " " .. css)
+
+App:start({
+ instance_name = "lua",
+ css = css,
+ main = function()
+ Widget.Window({ MprisPlayers() })
+ end,
+})
diff --git a/examples/gtk3/lua/media-player/lib.lua b/examples/gtk3/lua/media-player/lib.lua
new file mode 100644
index 0000000..8a50bdd
--- /dev/null
+++ b/examples/gtk3/lua/media-player/lib.lua
@@ -0,0 +1,38 @@
+local M = {}
+
+function M.src(path)
+ local str = debug.getinfo(2, "S").source:sub(2)
+ local src = str:match("(.*/)") or str:match("(.*\\)") or "./"
+ return src .. path
+end
+
+---@generic T, R
+---@param array T[]
+---@param func fun(T, i: integer): R
+---@return R[]
+function M.map(array, func)
+ local new_arr = {}
+ for i, v in ipairs(array) do
+ new_arr[i] = func(v, i)
+ end
+ return new_arr
+end
+
+---@generic T
+---@param array T[]
+---@param start integer
+---@param stop? integer
+---@return T[]
+function M.slice(array, start, stop)
+ local new_arr = {}
+
+ stop = stop or #array
+
+ for i = start, stop do
+ table.insert(new_arr, array[i])
+ end
+
+ return new_arr
+end
+
+return M
diff --git a/examples/gtk3/lua/media-player/style.scss b/examples/gtk3/lua/media-player/style.scss
new file mode 100644
index 0000000..be398dd
--- /dev/null
+++ b/examples/gtk3/lua/media-player/style.scss
@@ -0,0 +1 @@
+@use './widget/MediaPlayer.scss';
diff --git a/examples/gtk3/lua/media-player/widget/MediaPlayer.lua b/examples/gtk3/lua/media-player/widget/MediaPlayer.lua
new file mode 100644
index 0000000..fbad3e0
--- /dev/null
+++ b/examples/gtk3/lua/media-player/widget/MediaPlayer.lua
@@ -0,0 +1,144 @@
+local astal = require("astal")
+
+local Astal = astal.require("Astal", "3.0")
+
+local bind = astal.bind
+local Widget = require("astal.gtk3.widget")
+local lookup_icon = Astal.Icon.lookup_icon
+
+local map = require("lib").map
+
+local Mpris = astal.require("AstalMpris")
+
+---@param length integer
+local function length_str(length)
+ local min = math.floor(length / 60)
+ local sec = math.floor(length % 60)
+
+ return string.format("%d:%s%d", min, sec < 10 and "0" or "", sec)
+end
+
+local function MediaPlayer(player)
+ local title = bind(player, "title"):as(
+ function(t) return t or "Unknown Track" end
+ )
+
+ local artist = bind(player, "artist"):as(
+ function(a) return a or "Unknown Artist" end
+ )
+
+ local cover_art = bind(player, "cover-art"):as(
+ function(c) return string.format("background-image: url('%s');", c) end
+ )
+
+ local player_icon = bind(player, "entry"):as(
+ function(e) return lookup_icon(e) and e or "audio-x-generic-symbolic" end
+ )
+
+ local position = bind(player, "position"):as(
+ function(p) return player.length > 0 and p / player.length or 0 end
+ )
+
+ local play_icon = bind(player, "playback-status"):as(
+ function(s)
+ return s == "PLAYING" and "media-playback-pause-symbolic"
+ or "media-playback-start-symbolic"
+ end
+ )
+
+ return Widget.Box({
+ class_name = "MediaPlayer",
+ Widget.Box({
+ class_name = "cover-art",
+ css = cover_art,
+ }),
+ Widget.Box({
+ vertical = true,
+ Widget.Box({
+ class_name = "title",
+ Widget.Label({
+ ellipsize = "END",
+ hexpand = true,
+ halign = "START",
+ label = title,
+ }),
+ Widget.Icon({
+ icon = player_icon,
+ }),
+ }),
+ Widget.Label({
+ halign = "START",
+ valign = "START",
+ vexpand = true,
+ wrap = true,
+ label = artist,
+ }),
+ Widget.Slider({
+ visible = bind(player, "length"):as(
+ function(l) return l > 0 end
+ ),
+ on_dragged = function(event)
+ player.position = event.value * player.length
+ end,
+ value = position,
+ }),
+ Widget.CenterBox({
+ class_name = "actions",
+ Widget.Label({
+ hexpand = true,
+ class_name = "position",
+ halign = "START",
+ visible = bind(player, "length"):as(
+ function(l) return l > 0 end
+ ),
+ label = bind(player, "position"):as(length_str),
+ }),
+ Widget.Box({
+ Widget.Button({
+ on_clicked = function() player:previous() end,
+ visible = bind(player, "can-go-previous"),
+ Widget.Icon({
+ icon = "media-skip-backward-symbolic",
+ }),
+ }),
+ Widget.Button({
+ on_clicked = function() player:play_pause() end,
+ visible = bind(player, "can-control"),
+ Widget.Icon({
+ icon = play_icon,
+ }),
+ }),
+ Widget.Button({
+ on_clicked = function() player:next() end,
+ visible = bind(player, "can-go-next"),
+ Widget.Icon({
+ icon = "media-skip-forward-symbolic",
+ }),
+ }),
+ }),
+ Widget.Label({
+ class_name = "length",
+ hexpand = true,
+ halign = "END",
+ visible = bind(player, "length"):as(
+ function(l) return l > 0 end
+ ),
+ label = bind(player, "length"):as(
+ function(l) return l > 0 and length_str(l) or "0:00" end
+ ),
+ }),
+ }),
+ }),
+ })
+end
+
+return function()
+ local mpris = Mpris.get_default()
+
+ return Widget.Box({
+ vertical = true,
+ bind(mpris, "players"):as(
+ function(players) return map(players, MediaPlayer) end
+ ),
+ })
+end
diff --git a/examples/gtk3/lua/media-player/widget/MediaPlayer.scss b/examples/gtk3/lua/media-player/widget/MediaPlayer.scss
new file mode 100644
index 0000000..e1597c2
--- /dev/null
+++ b/examples/gtk3/lua/media-player/widget/MediaPlayer.scss
@@ -0,0 +1,56 @@
+// https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-24/gtk/theme/Adwaita/_colors-public.scss
+$fg-color: #{"@theme_fg_color"};
+$bg-color: #{"@theme_bg_color"};
+
+window {
+ all: unset;
+}
+
+box.MediaPlayer {
+ padding: .6rem;
+ background-color: $bg-color;
+
+ box.cover-art {
+ min-width: 120px;
+ min-height: 120px;
+ border-radius: 9px;
+ margin-right: .6rem;
+ background-size: contain;
+ background-position: center;
+ }
+
+ box.title {
+ label {
+ font-weight: bold;
+ font-size: 1.1em;
+ }
+ }
+
+ scale {
+ padding: 0;
+ margin: .4rem 0;
+
+ trough {
+ min-height: 8px;
+ }
+
+ highlight {
+ background-color: $fg-color;
+ }
+
+ slider {
+ all: unset;
+ }
+ }
+
+ centerbox.actions {
+ min-width: 220px;
+
+ button {
+ min-width: 0;
+ min-height: 0;
+ padding: .4rem;
+ margin: 0 .2rem;
+ }
+ }
+}