              activate      r#!/bin/sh
#!/bin/sh
# Generated by shikumi (spec/home.md section 4.3); links this home's files.
set -f
umask 022
rc=0
fail() { echo "shikumi: home: $*" >&2; rc=1; }
note() { echo "shikumi: home: $*" >&2; }
case ${1:-} in /?*) ;; *) echo "usage: activate <profile path>" >&2; exit 2 ;; esac
case ${HOME:-} in /?*) ;; *) echo "shikumi: home: HOME is not set" >&2; exit 1 ;; esac
base=$1/files
state=$HOME/.local/state/shikumi
reg=$state/home-managed
reg_new=$state/home-managed.new
mkdir -p "$state" || { fail "cannot create $state"; exit 1; }
: > "$reg_new" || { fail "cannot write $reg_new"; exit 1; }
listed() { [ -f "$1" ] || return 1; while IFS= read -r listed_p; do [ "$listed_p" = "$2" ] && return 0; done < "$1"; return 1; }
prune() {
    [ -f "$reg" ] || return 0
    while IFS= read -r prune_p; do
        listed "$reg_new" "$prune_p" && continue
        prune_t=$HOME/$prune_p
        if [ -L "$prune_t" ] && [ "$(readlink "$prune_t")" = "$base/$prune_p" ]; then rm -f "$prune_t" || fail "cannot remove $prune_t"; fi
    done < "$reg"
}
parents() {
    parents_d=${1%/*}
    while [ "$parents_d" != "$HOME" ]; do
        if [ -L "$parents_d" ]; then fail "$parents_d is a symlink, not linking $1"; return 1; fi
        parents_d=${parents_d%/*}
    done
    mkdir -p "${1%/*}"
}
vacate() {
    vacate_t=$HOME/$1
    [ -e "$vacate_t" ] || [ -L "$vacate_t" ] || return 0
    if [ -L "$vacate_t" ] && [ "$(readlink "$vacate_t")" = "$base/$1" ]; then return 0; fi
    vacate_b=$vacate_t.before-shikumi; vacate_i=0
    while [ -e "$vacate_b" ] || [ -L "$vacate_b" ]; do vacate_i=$((vacate_i + 1)); vacate_b=$vacate_t.before-shikumi.$vacate_i; done
    mv "$vacate_t" "$vacate_b" && note "moved $vacate_t to $vacate_b"
}
link() {
    link_t=$HOME/$1
    if [ -L "$link_t" ] && [ "$(readlink "$link_t")" = "$base/$1" ]; then return 0; fi
    parents "$link_t" || return 0
    { vacate "$1" && ln -s "$base/$1" "$link_t"; } || fail "cannot link $link_t"
}
echo '.config/hypr/hyprland.lua' >> "$reg_new"
echo '.config/quickshell/aura/Bar.qml' >> "$reg_new"
echo '.config/quickshell/aura/BluetoothPanel.qml' >> "$reg_new"
echo '.config/quickshell/aura/Diamond.qml' >> "$reg_new"
echo '.config/quickshell/aura/Frame.qml' >> "$reg_new"
echo '.config/quickshell/aura/Launcher.qml' >> "$reg_new"
echo '.config/quickshell/aura/Lock.qml' >> "$reg_new"
echo '.config/quickshell/aura/Login.qml' >> "$reg_new"
echo '.config/quickshell/aura/NetworkPanel.qml' >> "$reg_new"
echo '.config/quickshell/aura/Notifications.qml' >> "$reg_new"
echo '.config/quickshell/aura/Osd.qml' >> "$reg_new"
echo '.config/quickshell/aura/Panel.qml' >> "$reg_new"
echo '.config/quickshell/aura/Polkit.qml' >> "$reg_new"
echo '.config/quickshell/aura/Power.qml' >> "$reg_new"
echo '.config/quickshell/aura/Theme.qml' >> "$reg_new"
echo '.config/quickshell/aura/Wallpaper.qml' >> "$reg_new"
echo '.config/quickshell/aura/shell.qml' >> "$reg_new"
prune
link '.config/hypr/hyprland.lua'
link '.config/quickshell/aura/Bar.qml'
link '.config/quickshell/aura/BluetoothPanel.qml'
link '.config/quickshell/aura/Diamond.qml'
link '.config/quickshell/aura/Frame.qml'
link '.config/quickshell/aura/Launcher.qml'
link '.config/quickshell/aura/Lock.qml'
link '.config/quickshell/aura/Login.qml'
link '.config/quickshell/aura/NetworkPanel.qml'
link '.config/quickshell/aura/Notifications.qml'
link '.config/quickshell/aura/Osd.qml'
link '.config/quickshell/aura/Panel.qml'
link '.config/quickshell/aura/Polkit.qml'
link '.config/quickshell/aura/Power.qml'
link '.config/quickshell/aura/Theme.qml'
link '.config/quickshell/aura/Wallpaper.qml'
link '.config/quickshell/aura/shell.qml'
mv -f "$reg_new" "$reg" || fail "cannot write $reg"
exit $rc
       files              .config              hypr              hyprland.lua      Š-- Made by the Aura (desktop/hyprland.lua). The default of the system is
-- in /etc/xdg/hypr. The file of the home profile
-- (homes/<user>/home.lua), in ~/.config/hypr, has priority.

hl.monitor({
    output   = "",
    mode     = "preferred",
    position = "auto",
    scale    = "auto",
})

local terminal = "foot"

-- The colors of the theme: the file of matugen (six hex digits for each
-- color), or the colors of the sketch.
local theme = { active = "6fd3e8", inactive = "24486a", background = "070b14" }
do
    local ok, t = pcall(dofile, (os.getenv("HOME") or "") .. "/.local/state/aura/hyprland-theme.lua")
    if ok and type(t) == "table" then
        for k, v in pairs(t) do
            if theme[k] and type(v) == "string" and v:match("^%x%x%x%x%x%x$") then
                theme[k] = v
            end
        end
    end
end

hl.on("hyprland.start", function()
    hl.exec_cmd("pipewire")
    hl.exec_cmd("pipewire-pulse")
    hl.exec_cmd("wireplumber")
    hl.exec_cmd("qs -c aura")
    hl.exec_cmd("hypridle")
    hl.exec_cmd("wl-clip-persist --clipboard regular")
    hl.exec_cmd("xdg-user-dirs-update")
end)

hl.on("hyprland.shutdown", function()
    os.execute('pkill -u "$(id -u)" -x wireplumber; pkill -u "$(id -u)" -x pipewire-pulse; pkill -u "$(id -u)" -x pipewire')
    os.execute('fusermount3 -u -z "$XDG_RUNTIME_DIR/doc" 2>/dev/null')
end)

hl.env("XCURSOR_SIZE", "24")
hl.env("HYPRCURSOR_SIZE", "24")

hl.config({
    general = {
        gaps_in     = 5,
        gaps_out    = 12,
        border_size = 2,
        col = {
            active_border   = "rgba(" .. theme.active .. "ee)",
            inactive_border = "rgba(" .. theme.inactive .. "aa)",
        },
        layout = "dwindle",
    },
    decoration = {
        rounding = 0,
    },
    animations = {
        enabled = true,
    },
    input = {
        kb_layout    = "br",
        kb_variant   = "abnt2",
        follow_mouse = 1,
    },
    misc = {
        force_default_wallpaper = 0,
        disable_hyprland_logo   = true,
        disable_splash_rendering = true,
        background_color        = "rgb(" .. theme.background .. ")",
    },
    ecosystem = {
        no_update_news  = true,
        no_donation_nag = true,
    },
})

local mainMod = "SUPER"

hl.bind(mainMod .. " + Q", hl.dsp.exec_cmd(terminal))
hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd(terminal))
hl.bind(mainMod .. " + C", hl.dsp.window.close())
hl.bind(mainMod .. " + M", hl.dsp.exec_cmd("hyprctl dispatch 'hl.dsp.exit()'"))
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" }))
hl.bind(mainMod .. " + R", hl.dsp.exec_cmd("qs -c aura ipc call launcher toggle"))
hl.bind(mainMod .. " + L", hl.dsp.exec_cmd("qs -c aura ipc call lock lock"))
hl.bind(mainMod .. " + Escape", hl.dsp.exec_cmd("qs -c aura ipc call power toggle"))
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(terminal .. " yazi"))
hl.bind(mainMod .. " + B", hl.dsp.exec_cmd("firefox"))
hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen({ action = "toggle" }))
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo())
hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit"))
hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("magic"))
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:magic" }))
hl.bind("Print", hl.dsp.exec_cmd('grim -g "$(slurp)" - | wl-copy -t image/png'))
hl.bind("SHIFT + Print", hl.dsp.exec_cmd("grim - | wl-copy -t image/png"))
hl.bind("switch:on:Lid Switch", hl.dsp.exec_cmd("qs -c aura ipc call power suspend"), { locked = true })
hl.bind(mainMod .. " + left",  hl.dsp.focus({ direction = "left" }))
hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "right" }))
hl.bind(mainMod .. " + up",    hl.dsp.focus({ direction = "up" }))
hl.bind(mainMod .. " + down",  hl.dsp.focus({ direction = "down" }))
for _, d in ipairs { "left", "right", "up", "down" } do
    hl.bind(mainMod .. " + SHIFT + " .. d, hl.dsp.window.move({ direction = d }))
end
for i = 1, 10 do
    local key = i % 10
    hl.bind(mainMod .. " + " .. key,         hl.dsp.focus({ workspace = i }))
    hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }))
end
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(),   { mouse = true })
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true, repeating = true })
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"),      { locked = true, repeating = true })
hl.bind("XF86AudioMute",        hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"),     { locked = true, repeating = true })
hl.bind("XF86AudioMicMute",     hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"),   { locked = true, repeating = true })
hl.bind("XF86MonBrightnessUp",   hl.dsp.exec_cmd("brightnessctl -q -n set 5%+ && qs -c aura ipc call osd brightness"), { locked = true, repeating = true })
hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -q -n set 5%- && qs -c aura ipc call osd brightness"), { locked = true, repeating = true })
hl.bind("XF86AudioPlay",  hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioNext",  hl.dsp.exec_cmd("playerctl next"),       { locked = true })
hl.bind("XF86AudioPrev",  hl.dsp.exec_cmd("playerctl previous"),   { locked = true })
hl.bind(mainMod .. " + SHIFT + C", hl.dsp.exec_cmd("hyprpicker -a"))
       
quickshell              aura              Bar.qml      import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Services.UPower
import Quickshell.Wayland

PanelWindow {
    id: bar
    required property var modelData
    required property var network
    required property var bluetooth
    required property var power
    screen: modelData
    // network, bluetooth, and power are set after the first evaluation of
    // the bindings below: thus "?."

    readonly property var battery: UPower.displayDevice

    anchors { top: true; left: true; right: true }
    implicitHeight: Theme.barHeight
    color: Theme.panel
    WlrLayershell.namespace: "aura-bar"

    SystemClock { id: clock; precision: SystemClock.Minutes }

    Rectangle {
        anchors.bottom: parent.bottom
        width: parent.width; height: 1
        color: Theme.line
    }

    Row {
        anchors.verticalCenter: parent.verticalCenter
        x: 16
        spacing: 20

        Row {
            anchors.verticalCenter: parent.verticalCenter
            spacing: 8
            Diamond { anchors.verticalCenter: parent.verticalCenter; size: 8; color: Theme.gold }
            Text {
                anchors.verticalCenter: parent.verticalCenter
                text: "AURA"
                color: Theme.gold
                font.family: Theme.titleFont; font.pixelSize: 14; font.letterSpacing: 4
            }
        }

        Row {
            anchors.verticalCenter: parent.verticalCenter
            spacing: 6
            Repeater {
                model: 5
                Diamond {
                    required property int index
                    readonly property int wsId: index + 1
                    readonly property bool focused: Hyprland.focusedWorkspace !== null
                        && Hyprland.focusedWorkspace.id === wsId
                    readonly property bool occupied: Hyprland.workspaces.values.some(w => w.id === wsId)
                    anchors.verticalCenter: parent.verticalCenter
                    size: focused || occupied ? 8 : 6
                    filled: focused
                    color: focused || occupied ? Theme.cyan : Theme.cyanDim
                    lineWidth: occupied ? 1.5 : 1
                }
            }
        }
    }

    Text {
        anchors.centerIn: parent
        width: Math.min(implicitWidth, parent.width * 0.5)
        elide: Text.ElideRight
        text: Hyprland.activeToplevel ? Hyprland.activeToplevel.title : ""
        color: Theme.muted
        font.family: Theme.textFont; font.pixelSize: 13
    }

    Row {
        anchors.verticalCenter: parent.verticalCenter
        anchors.right: parent.right; anchors.rightMargin: 16
        spacing: 12
        Text {
            anchors.baseline: time.baseline
            visible: bar.battery.isLaptopBattery
            readonly property bool charging: bar.battery.state === UPowerDeviceState.Charging
                || bar.battery.state === UPowerDeviceState.FullyCharged
            text: "BAT " + Math.round(bar.battery.percentage * 100) + (charging ? "+" : "")
            color: !charging && bar.battery.percentage < 0.15 ? Theme.drain : Theme.muted
            font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2
        }
        Text {
            anchors.baseline: time.baseline
            visible: bar.network?.available ?? false
            text: bar.network?.current ? "WIFI " + bar.network.current.name.toUpperCase() : "WIFI --"
            color: bar.network?.open ? Theme.cyan : Theme.muted
            font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2
            MouseArea { anchors.fill: parent; onClicked: bar.network.open = !bar.network.open }
        }
        Text {
            anchors.baseline: time.baseline
            visible: (bar.bluetooth?.adapter ?? null) !== null
            text: !bar.bluetooth?.adapter || !bar.bluetooth.adapter.enabled ? "BT OFF"
                : bar.bluetooth.connected > 0 ? "BT " + bar.bluetooth.connected : "BT"
            color: bar.bluetooth?.open ? Theme.cyan : Theme.muted
            font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2
            MouseArea { anchors.fill: parent; onClicked: bar.bluetooth.open = !bar.bluetooth.open }
        }
        Text {
            anchors.baseline: time.baseline
            text: Qt.formatDateTime(clock.date, "ddd dd MMM").toUpperCase()
            color: Theme.muted
            font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2
        }
        Text {
            id: time
            text: Qt.formatDateTime(clock.date, "hh:mm")
            color: Theme.gold
            font.family: Theme.titleFont; font.pixelSize: 18; font.letterSpacing: 1
        }
        Diamond {
            anchors.verticalCenter: parent.verticalCenter
            size: 9
            filled: bar.power?.open ?? false
            color: Theme.drain
            MouseArea { anchors.fill: parent; onClicked: bar.power.open = !bar.power.open }
        }
    }
}
       BluetoothPanel.qml      :import QtQuick
import Quickshell
import Quickshell.Bluetooth
import Quickshell.Io

Scope {
    id: root
    property bool open: false
    readonly property var adapter: Bluetooth.defaultAdapter
    readonly property var devices: adapter ? adapter.devices.values.filter(d => d.name !== "" || d.connected) : []
    readonly property int connected: devices.filter(d => d.connected).length
    property var pairingWith: null

    function choose(dev) {
        if (dev.connected) {
            dev.disconnect();
        } else if (!dev.paired) {
            if (root.pairingWith)
                return;
            root.pairingWith = dev;
            pairTimeout.restart();
            dev.trusted = true;
            dev.pair();
        } else {
            dev.connect();
        }
    }

    function search() {
        if (!root.adapter || !root.adapter.enabled)
            return;
        if (!root.adapter.discovering)
            root.adapter.discovering = true;
        searchTimer.restart();
    }

    function stopSearch() {
        searchTimer.stop();
        if (root.adapter && root.adapter.discovering)
            root.adapter.discovering = false;
    }

    Timer { id: searchTimer; interval: 30000; onTriggered: root.stopSearch() }
    Timer { id: pairTimeout; interval: 30000; onTriggered: root.pairingWith = null }

    // a paired device connects after the pairing
    Instantiator {
        model: root.devices
        delegate: Connections {
            required property var modelData
            target: modelData
            function onPairedChanged() {
                if (modelData === root.pairingWith)
                    root.pairingWith = null;
                if (modelData.paired && !modelData.connected)
                    modelData.connect();
            }
            function onPairingChanged() {
                if (modelData === root.pairingWith && !modelData.pairing && !modelData.paired)
                    root.pairingWith = null;
            }
        }
    }

    onOpenChanged: {
        if (root.adapter && root.adapter.enabled)
            root.adapter.pairable = open;
        if (!open)
            root.stopSearch();
    }

    IpcHandler {
        target: "bluetooth"
        function toggle(): void { root.open = !root.open; }
        function state(): string {
            return !root.adapter ? "none" : !root.adapter.enabled ? "off"
                : root.connected > 0 ? String(root.connected) : "on";
        }
    }

    Panel {
        open: root.open
        title: "BLUETOOTH"
        onDismissed: root.open = false

        Text {
            visible: !root.adapter
            text: "No Bluetooth adapter."
            color: Theme.muted
            font.family: Theme.textFont; font.pixelSize: 13
        }

        Row {
            visible: root.adapter !== null
            spacing: 24

            Text {
                text: root.adapter && root.adapter.enabled ? "[ ON ]" : "[ OFF ]"
                color: root.adapter && root.adapter.enabled ? Theme.cyan : Theme.muted
                font.family: Theme.titleFont; font.pixelSize: 13; font.letterSpacing: 2
                MouseArea {
                    anchors.fill: parent
                    onClicked: root.adapter.enabled = !root.adapter.enabled
                }
            }
            Text {
                visible: root.adapter && root.adapter.enabled
                text: searchTimer.running ? "[ SEARCHING ]" : "[ SEARCH ]"
                color: searchTimer.running ? Theme.gold : Theme.muted
                font.family: Theme.titleFont; font.pixelSize: 13; font.letterSpacing: 2
                MouseArea {
                    anchors.fill: parent
                    onClicked: searchTimer.running ? root.stopSearch() : root.search()
                }
            }
        }

        Repeater {
            model: root.adapter && root.adapter.enabled ? root.devices : []

            Item {
                id: row
                required property var modelData
                width: parent.width; height: 40
                readonly property bool busy: modelData.pairing || modelData === root.pairingWith
                    || modelData.state === BluetoothDeviceState.Connecting
                    || modelData.state === BluetoothDeviceState.Disconnecting
                readonly property bool waiting: root.pairingWith !== null && !row.modelData.paired
                    && row.modelData !== root.pairingWith

                Rectangle {
                    anchors.fill: parent
                    color: area.containsMouse ? Theme.panelHi : "transparent"
                }
                Diamond {
                    x: 8
                    anchors.verticalCenter: parent.verticalCenter
                    size: 8
                    filled: row.modelData.connected
                    color: row.modelData.connected ? Theme.cyan : row.modelData.paired ? Theme.cyanDim : Theme.line
                }
                Text {
                    x: 32
                    width: parent.width - 32 - status.width - 16
                    anchors.verticalCenter: parent.verticalCenter
                    elide: Text.ElideRight
                    text: row.modelData.name || row.modelData.address
                    color: Theme.text
                    font.family: Theme.textFont; font.pixelSize: 14
                    font.weight: row.modelData.connected ? Font.DemiBold : Font.Normal
                }
                Text {
                    id: status
                    anchors.right: parent.right; anchors.rightMargin: 8
                    anchors.verticalCenter: parent.verticalCenter
                    text: row.modelData === root.pairingWith ? "PAIRING"
                        : row.busy ? "..."
                        : row.modelData.connected && row.modelData.batteryAvailable
                            ? Math.round(row.modelData.battery * 100) + "%"
                        : row.modelData.paired ? "FORGET" : ""
                    color: text === "FORGET" && forget.containsMouse ? Theme.drain : Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 1
                }
                MouseArea {
                    id: area
                    anchors.fill: parent
                    anchors.rightMargin: status.width + 16
                    hoverEnabled: true
                    enabled: !row.busy && !row.waiting
                    onClicked: root.choose(row.modelData)
                }
                MouseArea {
                    id: forget
                    anchors.fill: status
                    hoverEnabled: true
                    enabled: status.text === "FORGET"
                    onClicked: row.modelData.forget()
                }
            }
        }

        Text {
            visible: root.pairingWith !== null
            width: parent.width
            wrapMode: Text.Wrap
            text: "Pairing with " + (root.pairingWith ? (root.pairingWith.name || root.pairingWith.address) : "")
                + ". The device must be in pairing mode."
            color: Theme.muted
            font.family: Theme.textFont; font.pixelSize: 13
        }
    }
}
       Diamond.qml      import QtQuick

Item {
    id: root
    property real size: 8
    property color color: Theme.cyan
    property bool filled: false
    property real lineWidth: 1.5

    implicitWidth: Math.ceil(root.size * 1.5)
    implicitHeight: implicitWidth

    Rectangle {
        anchors.centerIn: parent
        width: root.size; height: root.size
        rotation: 45
        antialiasing: true
        color: root.filled ? root.color : "transparent"
        border.color: root.color
        border.width: root.filled ? 0 : root.lineWidth
    }
}
       	Frame.qml      	import QtQuick
import QtQuick.Shapes

Item {
    id: root
    property real cut: Theme.cut
    property color fill: Theme.panel
    property color stroke: Theme.line

    Shape {
        anchors.fill: parent
        preferredRendererType: Shape.CurveRenderer
        ShapePath {
            fillColor: root.fill
            strokeColor: root.stroke
            strokeWidth: 1
            startX: root.cut; startY: 0.5
            PathLine { x: root.width - 0.5; y: 0.5 }
            PathLine { x: root.width - 0.5; y: root.height - root.cut }
            PathLine { x: root.width - root.cut; y: root.height - 0.5 }
            PathLine { x: 0.5; y: root.height - 0.5 }
            PathLine { x: 0.5; y: root.cut }
            PathLine { x: root.cut; y: 0.5 }
        }
    }
}
       Launcher.qml      žimport QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland

Scope {
    id: root
    property bool open: false
    readonly property var matches: filter(DesktopEntries.applications.values, search.text)

    function filter(apps, query) {
        const q = query.toLowerCase();
        return apps
            .filter(a => !a.noDisplay && (q === ""
                || a.name.toLowerCase().includes(q)
                || a.genericName.toLowerCase().includes(q)))
            .sort((a, b) => a.name.localeCompare(b.name));
    }

    function launch(i) {
        const entry = root.matches[i];
        if (entry) {
            if (entry.runInTerminal)
                Quickshell.execDetached({ command: [ "foot", "--" ].concat(entry.command),
                                          workingDirectory: entry.workingDirectory });
            else
                entry.execute();
            root.open = false;
        }
    }

    onOpenChanged: {
        if (open) {
            search.text = "";
            list.currentIndex = 0;
            search.forceActiveFocus();
        }
    }

    IpcHandler {
        target: "launcher"
        function toggle(): void { root.open = !root.open; }
        function show(): void { root.open = true; }
        function hide(): void { root.open = false; }
    }

    PanelWindow {
        id: win
        visible: root.open
        anchors { top: true; bottom: true; left: true; right: true }
        color: "#b8070b14"
        exclusionMode: ExclusionMode.Ignore
        WlrLayershell.layer: WlrLayer.Overlay
        WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
        WlrLayershell.namespace: "aura-launcher"

        MouseArea { anchors.fill: parent; onClicked: root.open = false }

        Frame {
            id: box
            x: (win.width - width) / 2
            y: 150
            width: 520
            height: content.implicitHeight + 36
            cut: 18
            stroke: Theme.cyan

            MouseArea { anchors.fill: parent }

            Column {
                id: content
                x: 0; y: 22
                width: parent.width
                spacing: 14

                Text {
                    x: 24
                    text: "// LAUNCH"
                    color: Theme.gold
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
                }

                Item {
                    x: 24
                    width: parent.width - 48; height: 34
                    Text {
                        id: arrow
                        anchors.verticalCenter: search.verticalCenter
                        text: ">"
                        color: Theme.cyan
                        font.family: Theme.titleFont; font.pixelSize: 18
                    }
                    TextInput {
                        id: search
                        anchors.left: arrow.right; anchors.leftMargin: 10
                        anchors.right: parent.right
                        color: Theme.text
                        selectionColor: Theme.cyanDim
                        font.family: Theme.textFont; font.pixelSize: 20
                        focus: true
                        onTextChanged: list.currentIndex = 0
                        Keys.onEscapePressed: root.open = false
                        Keys.onDownPressed: list.incrementCurrentIndex()
                        Keys.onUpPressed: list.decrementCurrentIndex()
                        Keys.onReturnPressed: root.launch(list.currentIndex)
                        Keys.onEnterPressed: root.launch(list.currentIndex)
                    }
                    Rectangle {
                        anchors.bottom: parent.bottom
                        width: parent.width; height: 1
                        color: Theme.line
                    }
                }

                ListView {
                    id: list
                    width: parent.width
                    height: Math.min(count, 6) * 52
                    clip: true
                    model: root.matches
                    highlightMoveDuration: 0

                    delegate: Item {
                        id: item
                        required property var modelData
                        required property int index
                        readonly property bool current: ListView.isCurrentItem
                        width: list.width; height: 52

                        Rectangle {
                            anchors.fill: parent
                            color: item.current ? Theme.panelHi : "transparent"
                        }
                        Rectangle {
                            width: 2; height: parent.height
                            color: item.current ? Theme.cyan : "transparent"
                        }
                        Diamond {
                            x: 24
                            anchors.verticalCenter: parent.verticalCenter
                            size: 10
                            color: item.current ? Theme.cyan : Theme.cyanDim
                        }
                        Column {
                            x: 56
                            anchors.verticalCenter: parent.verticalCenter
                            width: parent.width - 80
                            spacing: 2
                            Text {
                                width: parent.width
                                elide: Text.ElideRight
                                text: item.modelData.name
                                color: Theme.text
                                font.family: Theme.textFont; font.pixelSize: 15
                                font.weight: item.current ? Font.DemiBold : Font.Normal
                            }
                            Text {
                                width: parent.width
                                elide: Text.ElideRight
                                visible: text !== ""
                                text: item.modelData.genericName || item.modelData.comment
                                color: Theme.muted
                                font.family: Theme.textFont; font.pixelSize: 12
                            }
                        }
                        MouseArea {
                            anchors.fill: parent
                            hoverEnabled: true
                            onEntered: list.currentIndex = item.index
                            onClicked: root.launch(item.index)
                        }
                    }
                }

                Text {
                    x: 24
                    text: "UP/DOWN SELECT    ENTER OPEN    ESC CLOSE"
                    color: Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 11; font.letterSpacing: 2
                }
            }
        }
    }
}
       Lock.qml      °import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.Pam
import Quickshell.Wayland

Scope {
    id: root
    // the password lives only between Enter and the answer of PAM
    property string password: ""
    property bool failed: false
    readonly property bool secure: sessionLock.secure

    function lock() {
        root.failed = false;
        sessionLock.locked = true;
    }

    function submit(password) {
        if (pam.active)
            return;
        root.password = password;
        root.failed = false;
        pam.start();
    }

    IpcHandler {
        target: "lock"
        function lock(): void { root.lock(); }
        // for the scenario: "locked" only after the compositor confirms
        function state(): string {
            return sessionLock.secure ? "locked" : sessionLock.locked ? "locking" : "unlocked";
        }
    }

    PamContext {
        id: pam
        config: "quickshell"
        onPamMessage: {
            if (responseRequired)
                respond(root.password);
        }
        onCompleted: result => {
            root.password = "";
            if (result === PamResult.Success)
                sessionLock.locked = false;
            else
                root.failed = true;
        }
    }

    WlSessionLock {
        id: sessionLock

        WlSessionLockSurface {
            color: Theme.void_

            Login {
                anchors.fill: parent
                user: Quickshell.env("USER") ?? ""
                action: "UNLOCK"
                footer: "SESSION LOCKED"
                busy: pam.active
                message: pam.active ? "Checking..." : root.failed ? "Wrong password. Try again." : ""
                messageIsError: root.failed && !pam.active
                onSubmitted: (user, password) => root.submit(password)
                onEdited: root.failed = false
                Component.onCompleted: focusInput()
            }
        }
    }
}
       	Login.qml      "·import QtQuick
import QtQuick.Shapes
import Quickshell

Rectangle {
    id: root
    property string user: ""
    property bool userEditable: false
    property string action: "UNLOCK"
    property string host: ""
    property string footer: ""
    property string message: ""
    property bool messageIsError: false
    property bool busy: false
    property bool showForm: true

    signal submitted(string user, string password)
    signal edited()

    function focusInput() {
        if (root.userEditable && userInput.text === "")
            userInput.forceActiveFocus();
        else
            field.forceActiveFocus();
    }

    function send() {
        if (root.busy || userInput.text === "" || field.text === "")
            return;
        root.submitted(userInput.text, field.text);
        field.text = "";
    }

    color: Theme.void_

    SystemClock { id: clock; precision: SystemClock.Minutes }

    // the rings and the sights behind the clock and the frame
    Item {
        anchors.centerIn: parent
        width: 760; height: 760

        Rectangle {
            anchors.centerIn: parent
            width: 760; height: 760; radius: 380
            color: "transparent"
            border.color: Theme.panelHi
        }
        Shape {
            anchors.fill: parent
            preferredRendererType: Shape.CurveRenderer
            ShapePath {
                fillColor: "transparent"
                strokeColor: Theme.line
                strokeWidth: 1
                strokeStyle: ShapePath.DashLine
                dashPattern: [2, 12]
                PathAngleArc {
                    centerX: 380; centerY: 380
                    radiusX: 300; radiusY: 300
                    startAngle: 0; sweepAngle: 360
                }
            }
        }
        Rectangle {
            anchors.centerIn: parent
            width: 460; height: 460; radius: 230
            color: "transparent"
            border.color: Theme.line
            opacity: 0.7
        }
        Rectangle { x: 380; y: 0; width: 1; height: 150; color: Theme.line }
        Rectangle { x: 380; y: 610; width: 1; height: 150; color: Theme.line }
        Rectangle { x: 0; y: 380; width: 150; height: 1; color: Theme.line }
        Rectangle { x: 610; y: 380; width: 150; height: 1; color: Theme.line }
    }

    Column {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: box.top
        anchors.bottomMargin: 70
        spacing: 6
        Text {
            anchors.horizontalCenter: parent.horizontalCenter
            text: Qt.formatDateTime(clock.date, "hh:mm")
            color: Theme.gold
            font.family: Theme.titleFont; font.pixelSize: 72; font.letterSpacing: 4
        }
        Text {
            anchors.horizontalCenter: parent.horizontalCenter
            text: Qt.formatDateTime(clock.date, "dddd \u00b7 dd MMM yyyy").toUpperCase()
            color: Theme.muted
            font.family: Theme.titleFont; font.pixelSize: 14; font.letterSpacing: 4.5
        }
    }

    Frame {
        id: box
        visible: root.showForm
        anchors.centerIn: parent
        width: 400
        height: content.implicitHeight + 52
        cut: 18

        Column {
            id: content
            x: 28; y: 26
            width: parent.width - 56
            spacing: 18

            Item {
                width: parent.width; height: 16
                Diamond {
                    id: mark
                    anchors.verticalCenter: parent.verticalCenter
                    size: 8
                    color: Theme.gold
                }
                Text {
                    anchors.left: mark.right; anchors.leftMargin: 10
                    anchors.verticalCenter: parent.verticalCenter
                    text: "AURA R:1"
                    color: Theme.gold
                    font.family: Theme.titleFont; font.pixelSize: 14; font.letterSpacing: 4.5
                }
                Text {
                    anchors.right: parent.right
                    anchors.verticalCenter: parent.verticalCenter
                    text: root.host.toUpperCase()
                    color: Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2.4
                }
            }

            Column {
                width: parent.width
                spacing: 6
                Text {
                    text: "USER"
                    color: userInput.activeFocus ? Theme.cyan : Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
                }
                Rectangle {
                    width: parent.width; height: 44
                    color: Theme.void_
                    border.color: userInput.activeFocus ? Theme.cyan : Theme.line
                    TextInput {
                        id: userInput
                        anchors.fill: parent
                        anchors.leftMargin: 12; anchors.rightMargin: 12
                        verticalAlignment: TextInput.AlignVCenter
                        text: root.user
                        readOnly: !root.userEditable || root.busy
                        activeFocusOnPress: root.userEditable
                        color: Theme.text
                        selectionColor: Theme.cyanDim
                        font.family: Theme.textFont; font.pixelSize: 16
                        onAccepted: field.forceActiveFocus()
                        Keys.onTabPressed: field.forceActiveFocus()
                    }
                }
            }

            Column {
                width: parent.width
                spacing: 6
                Text {
                    text: "PASSWORD"
                    color: field.activeFocus ? Theme.cyan : Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
                }
                Rectangle {
                    width: parent.width; height: 44
                    color: Theme.void_
                    border.color: root.messageIsError ? Theme.drain
                        : field.activeFocus ? Theme.cyan : Theme.line
                    TextInput {
                        id: field
                        anchors.fill: parent
                        anchors.leftMargin: 12; anchors.rightMargin: 12
                        verticalAlignment: TextInput.AlignVCenter
                        echoMode: TextInput.Password
                        passwordCharacter: "\u25c6"
                        readOnly: root.busy
                        color: Theme.text
                        selectionColor: Theme.cyanDim
                        font.family: Theme.textFont; font.pixelSize: 16
                        onTextChanged: root.edited()
                        onAccepted: root.send()
                        Keys.onEscapePressed: text = ""
                        Keys.onBacktabPressed: {
                            if (root.userEditable)
                                userInput.forceActiveFocus();
                        }
                    }
                }
            }

            Item {
                width: parent.width; height: 18
                Diamond {
                    id: sign
                    anchors.verticalCenter: parent.verticalCenter
                    visible: root.message !== ""
                    size: 6
                    filled: true
                    color: root.messageIsError ? Theme.drain : Theme.cyan
                }
                Text {
                    anchors.left: sign.right; anchors.leftMargin: 8
                    anchors.right: parent.right
                    anchors.verticalCenter: parent.verticalCenter
                    elide: Text.ElideRight
                    text: root.message
                    color: root.messageIsError ? Theme.drain : Theme.muted
                    font.family: Theme.textFont; font.pixelSize: 13
                }
            }

            Frame {
                width: parent.width; height: 44
                cut: 10
                fill: root.busy ? Theme.cyanDim : Theme.cyan
                stroke: fill
                Text {
                    anchors.centerIn: parent
                    text: root.action
                    color: Theme.void_
                    font.family: Theme.titleFont; font.pixelSize: 15; font.letterSpacing: 4.8
                }
                MouseArea {
                    anchors.fill: parent
                    onClicked: root.send()
                }
            }
        }
    }

    Text {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 36
        text: root.footer
        color: Theme.muted
        font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
    }
}
       NetworkPanel.qml      &import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland

Scope {
    id: root
    property bool open: false
    property bool available: false
    property string device: ""
    property var networks: []
    readonly property var current: networks.find(n => n.connected) ?? null
    property string asking: ""
    property string message: ""
    property bool busy: connector.running

    // the rows of a table of iwctl: the lines after the second dashed line
    function rows(text) {
        const out = [];
        let dashes = 0;
        for (const raw of text.replace(/\x1b\[[0-9;]*m/g, "").split("\n")) {
            // the JavaScript of QML has no trimEnd
            const line = raw.replace(/\s+$/, "");
            if (/^-{10,}$/.test(line.trim())) {
                dashes++;
                continue;
            }
            if (dashes >= 2 && line.trim() !== "")
                out.push(line);
        }
        return out;
    }

    function parseNetworks(text) {
        const out = [];
        for (const row of root.rows(text)) {
            let line = row.trim();
            const connected = line.startsWith("> ");
            if (connected)
                line = line.substring(2).trim();
            const m = line.match(/^(.*?)\s{2,}(\S+(?: \(unsupported\))?)\s{2,}(-?\d+)$/);
            if (m)
                out.push({ name: m[1], security: m[2], signal: Number(m[3]) / 100, connected: connected });
        }
        return out;
    }

    function bars(dbm) {
        return dbm >= -60 ? 4 : dbm >= -67 ? 3 : dbm >= -75 ? 2 : 1;
    }

    function refresh() {
        if (root.available && !stations.running)
            stations.running = true;
    }

    function connect(net, passphrase) {
        if (connector.running || root.device === "")
            return;
        root.message = "";
        const args = passphrase !== "" ? [ "--passphrase", passphrase ] : [ "--dont-ask" ];
        connector.target = net.name;
        connector.command = [ "iwctl" ].concat(args, [ "station", root.device, "connect", net.name ]);
        connector.running = true;
    }

    function disconnect() {
        if (connector.running || root.device === "")
            return;
        connector.target = "";
        connector.command = [ "iwctl", "station", root.device, "disconnect" ];
        connector.running = true;
    }

    // a known or open network connects without the passphrase; an
    // unknown protected network fails, and then the panel asks
    function choose(net) {
        if (net.connected)
            root.disconnect();
        else
            root.connect(net, "");
    }

    onOpenChanged: {
        if (open) {
            root.asking = "";
            root.message = "";
            root.refresh();
            if (root.device !== "") {
                scan.command = [ "iwctl", "station", root.device, "scan" ];
                scan.running = true;
            }
        }
    }

    IpcHandler {
        target: "network"
        function toggle(): void { root.open = !root.open; }
        function state(): string {
            return root.device === "" ? "none" : root.current ? root.device + " " + root.current.name : root.device;
        }
    }

    // iwd is only in the system of a machine with Wi-Fi
    Process {
        running: true
        command: [ "sh", "-c", "command -v iwctl" ]
        onExited: (code, status) => root.available = code === 0
    }

    // the state, every 10 s, and faster while the panel is open
    Timer {
        running: root.available; repeat: true; triggeredOnStart: true
        interval: root.open ? 3000 : 10000
        onTriggered: root.refresh()
    }

    Process {
        id: stations
        command: [ "iwctl", "station", "list" ]
        stdout: StdioCollector {
            onStreamFinished: {
                const first = root.rows(this.text)[0];
                root.device = first ? first.trim().split(/\s{2,}/)[0] : "";
                if (root.device !== "") {
                    lister.command = [ "iwctl", "station", root.device, "get-networks", "rssi-dbms" ];
                    lister.running = true;
                } else {
                    root.networks = [];
                }
            }
        }
        onExited: (code, status) => { if (code !== 0) { root.device = ""; root.networks = []; } }
    }

    Process {
        id: lister
        stdout: StdioCollector {
            onStreamFinished: root.networks = root.parseNetworks(this.text)
        }
    }

    Process {
        id: scan
        onExited: refreshLater.restart()
    }

    Timer { id: refreshLater; interval: 2500; onTriggered: root.refresh() }

    Process {
        id: connector
        property string target: ""
        onExited: (code, status) => {
            if (code === 0) {
                root.asking = "";
                root.message = "";
            } else if (connector.target !== "" && root.asking !== connector.target) {
                const net = root.networks.find(n => n.name === connector.target);
                if (net && net.security !== "open") {
                    root.asking = connector.target;
                    root.message = "";
                    pass.text = "";
                    pass.forceActiveFocus();
                } else {
                    root.message = "Cannot connect.";
                }
            } else {
                root.message = connector.target !== "" ? "Wrong passphrase or no answer." : "Cannot disconnect.";
            }
            refreshLater.restart();
        }
    }

    Panel {
        open: root.open
        title: "WI-FI"
        onDismissed: root.open = false

        Text {
            visible: root.device === ""
            text: "No Wi-Fi station (iwd)."
            color: Theme.muted
            font.family: Theme.textFont; font.pixelSize: 13
        }

        Text {
            visible: root.device !== ""
            text: (root.device + (root.current ? "  //  " + root.current.name : "  //  NOT CONNECTED")).toUpperCase()
            color: root.current ? Theme.cyan : Theme.muted
            width: parent.width
            elide: Text.ElideRight
            font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2
        }

        Repeater {
            model: root.networks

            Item {
                id: row
                required property var modelData
                width: parent.width; height: 40
                readonly property bool hover: area.containsMouse

                Rectangle {
                    anchors.fill: parent
                    color: row.hover ? Theme.panelHi : "transparent"
                }
                Diamond {
                    x: 8
                    anchors.verticalCenter: parent.verticalCenter
                    size: 8
                    filled: row.modelData.connected
                    color: row.modelData.connected ? Theme.cyan : Theme.cyanDim
                }
                Text {
                    x: 32
                    width: parent.width - 32 - signal.width - 16
                    anchors.verticalCenter: parent.verticalCenter
                    elide: Text.ElideRight
                    text: row.modelData.name
                    color: Theme.text
                    font.family: Theme.textFont; font.pixelSize: 14
                    font.weight: row.modelData.connected ? Font.DemiBold : Font.Normal
                }
                Text {
                    id: signal
                    anchors.right: parent.right; anchors.rightMargin: 8
                    anchors.verticalCenter: parent.verticalCenter
                    text: (row.modelData.security === "open" ? "OPEN  " : "")
                        + "||||....".substr(4 - root.bars(row.modelData.signal), 4)
                    color: Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 12
                }
                MouseArea {
                    id: area
                    anchors.fill: parent
                    hoverEnabled: true
                    enabled: !root.busy
                    onClicked: root.choose(row.modelData)
                }
            }
        }

        Item {
            visible: root.asking !== ""
            width: parent.width; height: 34
            Text {
                id: arrow
                anchors.verticalCenter: pass.verticalCenter
                text: ">"
                color: Theme.cyan
                font.family: Theme.titleFont; font.pixelSize: 18
            }
            TextInput {
                id: pass
                anchors.left: arrow.right; anchors.leftMargin: 10
                anchors.right: parent.right
                color: Theme.text
                selectionColor: Theme.cyanDim
                echoMode: TextInput.Password
                font.family: Theme.textFont; font.pixelSize: 16
                Keys.onEscapePressed: root.asking = ""
                Keys.onReturnPressed: root.connect({ name: root.asking }, pass.text)
                Keys.onEnterPressed: root.connect({ name: root.asking }, pass.text)
            }
            Rectangle {
                anchors.bottom: parent.bottom
                width: parent.width; height: 1
                color: Theme.line
            }
        }

        Text {
            visible: text !== ""
            width: parent.width
            wrapMode: Text.Wrap
            text: root.busy ? "Connecting..." : root.asking !== "" && root.message === ""
                ? "Passphrase of " + root.asking + "." : root.message
            color: root.message !== "" && !root.busy ? Theme.drain : Theme.muted
            font.family: Theme.textFont; font.pixelSize: 13
        }
    }
}
       Notifications.qml      4import QtQuick
import Quickshell
import Quickshell.Services.Notifications
import Quickshell.Wayland

Scope {
    NotificationServer {
        id: server
        bodySupported: true
        actionsSupported: false
        imageSupported: false
        onNotification: n => { n.tracked = true; }
    }

    PanelWindow {
        visible: balloons.count > 0
        anchors { top: true; right: true }
        margins { top: Theme.barHeight + 16; right: 16 }
        implicitWidth: 360
        implicitHeight: column.implicitHeight
        color: "transparent"
        exclusionMode: ExclusionMode.Ignore
        WlrLayershell.layer: WlrLayer.Overlay
        WlrLayershell.namespace: "aura-notifications"

        Column {
            id: column
            width: 360
            spacing: 10

            Repeater {
                id: balloons
                model: server.trackedNotifications

                Item {
                    id: balloon
                    required property var modelData
                    readonly property bool critical: modelData.urgency === NotificationUrgency.Critical
                    // expireTimeout comes in milliseconds, as in D-Bus
                    // (Quickshell 0.3.2 keeps it so, but the
                    // documentation says seconds); -1 is the default of
                    // the server.
                    readonly property int timeout: critical || modelData.expireTimeout === 0 ? 0
                        : modelData.expireTimeout > 0 ? modelData.expireTimeout : 5000
                    property real remaining: 1

                    width: 360
                    height: body.implicitHeight + 30

                    Frame {
                        anchors.fill: parent
                        stroke: balloon.critical ? Theme.drain : Theme.line
                    }

                    Column {
                        id: body
                        x: 18; y: 14
                        width: parent.width - 36
                        spacing: 6

                        Row {
                            spacing: 8
                            Diamond {
                                anchors.verticalCenter: parent.verticalCenter
                                size: 6; filled: true
                                color: balloon.critical ? Theme.drain : Theme.cyan
                            }
                            Text {
                                text: balloon.critical ? "URGENT" : (balloon.modelData.appName || "NOTICE")
                                color: balloon.critical ? Theme.drain : Theme.cyan
                                font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
                                font.capitalization: Font.AllUppercase
                            }
                        }
                        Text {
                            width: parent.width
                            wrapMode: Text.Wrap
                            text: balloon.modelData.summary
                            color: Theme.text
                            font.family: Theme.textFont; font.pixelSize: 15; font.weight: Font.DemiBold
                        }
                        Text {
                            width: parent.width
                            wrapMode: Text.Wrap
                            visible: text !== ""
                            textFormat: Text.PlainText
                            text: balloon.modelData.body
                            color: Theme.muted
                            font.family: Theme.textFont; font.pixelSize: 13
                        }
                    }

                    Rectangle {
                        visible: balloon.timeout > 0
                        x: 1; anchors.bottom: parent.bottom; anchors.bottomMargin: 1
                        width: (parent.width - Theme.cut - 1) * balloon.remaining
                        height: 2
                        color: Theme.cyan
                    }

                    // The expiration and the progress line go through a
                    // Timer, in the event loop, and do not depend on the
                    // frame of the window.
                    readonly property real born: Date.now()
                    Timer {
                        running: balloon.timeout > 0
                        interval: 100; repeat: true
                        onTriggered: {
                            balloon.remaining = Math.max(0, 1 - (Date.now() - balloon.born) / balloon.timeout);
                            if (balloon.remaining === 0)
                                balloon.modelData.expire();
                        }
                    }

                    MouseArea {
                        anchors.fill: parent
                        onClicked: balloon.modelData.dismiss()
                    }
                }
            }
        }
    }
}
       Osd.qml      fimport QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Services.Pipewire
import Quickshell.Wayland

Scope {
    id: root
    property string kind: "volume"
    property real value: 0
    property bool muted: false
    property bool shown: false
    property bool armed: false

    readonly property var sink: Pipewire.defaultAudioSink

    PwObjectTracker { objects: root.sink ? [ root.sink ] : [] }

    Connections {
        target: root.sink ? root.sink.audio : null
        function onVolumeChanged() { root.showVolume(); }
        function onMutedChanged() { root.showVolume(); }
    }

    Timer { running: true; interval: 2000; onTriggered: root.armed = true }
    Timer { id: hide; interval: 1500; onTriggered: root.shown = false }

    function pop() {
        root.shown = true;
        hide.restart();
    }

    function showVolume() {
        if (!root.armed || !root.sink || !root.sink.audio)
            return;
        root.kind = "volume";
        root.value = root.sink.audio.volume;
        root.muted = root.sink.audio.muted;
        root.pop();
    }

    Process {
        id: readBrightness
        command: [ "brightnessctl", "-m" ]
        stdout: StdioCollector {
            // one line: device,class,current,percent,max
            onStreamFinished: {
                const f = this.text.trim().split(",");
                if (f.length >= 5 && Number(f[4]) > 0) {
                    root.kind = "brightness";
                    root.value = Number(f[2]) / Number(f[4]);
                    root.muted = false;
                    root.pop();
                }
            }
        }
    }

    IpcHandler {
        target: "osd"
        function brightness(): void { readBrightness.running = true; }
        function volume(): void { root.armed = true; root.showVolume(); }
        function state(): string { return root.shown ? root.kind : "hidden"; }
    }

    PanelWindow {
        visible: root.shown
        anchors { bottom: true }
        margins { bottom: 96 }
        implicitWidth: 340
        implicitHeight: 64
        color: "transparent"
        exclusionMode: ExclusionMode.Ignore
        mask: Region {}
        WlrLayershell.layer: WlrLayer.Overlay
        WlrLayershell.namespace: "aura-osd"

        Frame { anchors.fill: parent }

        Row {
            x: 20
            anchors.verticalCenter: parent.verticalCenter
            spacing: 14

            Diamond {
                anchors.verticalCenter: parent.verticalCenter
                size: 8; filled: !root.muted
                color: root.muted ? Theme.drain : Theme.cyan
            }
            Text {
                width: 96
                anchors.verticalCenter: parent.verticalCenter
                text: root.kind === "brightness" ? "BRIGHT" : (root.muted ? "MUTED" : "VOLUME")
                color: root.muted ? Theme.drain : Theme.cyan
                font.family: Theme.titleFont; font.pixelSize: 13; font.letterSpacing: 3
            }
            Item {
                width: 140; height: 6
                anchors.verticalCenter: parent.verticalCenter
                Rectangle { anchors.fill: parent; color: Theme.panelHi }
                Rectangle {
                    width: parent.width * Math.max(0, Math.min(1, root.value))
                    height: parent.height
                    color: root.muted ? Theme.muted : Theme.cyan
                }
            }
            Text {
                anchors.verticalCenter: parent.verticalCenter
                text: Math.round(root.value * 100)
                color: Theme.text
                font.family: Theme.titleFont; font.pixelSize: 15
            }
        }
    }
}
       	Panel.qml      Ćimport QtQuick
import Quickshell
import Quickshell.Wayland

PanelWindow {
    id: panel
    property bool open: false
    property string title: ""
    property int boxWidth: 400
    default property alias content: body.data
    signal dismissed()

    visible: open
    anchors { top: true; bottom: true; left: true; right: true }
    color: "transparent"
    exclusionMode: ExclusionMode.Ignore
    WlrLayershell.layer: WlrLayer.Overlay
    WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
    WlrLayershell.namespace: "aura-panel"

    onOpenChanged: if (open) keys.forceActiveFocus()

    MouseArea { anchors.fill: parent; onClicked: panel.dismissed() }

    Item {
        id: keys
        focus: true
        Keys.onEscapePressed: panel.dismissed()
    }

    Frame {
        x: panel.width - width - 12
        y: Theme.barHeight + 8
        width: panel.boxWidth
        height: column.implicitHeight + 40
        cut: 18
        stroke: Theme.cyan

        MouseArea { anchors.fill: parent }

        Column {
            id: column
            x: 24; y: 22
            width: parent.width - 48
            spacing: 12

            Text {
                text: "// " + panel.title
                color: Theme.gold
                font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
            }

            Column {
                id: body
                width: parent.width
                spacing: 6
            }
        }
    }
}
       
Polkit.qml      ńimport QtQuick
import Quickshell
import Quickshell.Services.Polkit
import Quickshell.Wayland

Scope {
    id: root
    readonly property var flow: agent.flow

    PolkitAgent {
        id: agent
        onAuthenticationRequestStarted: {
            const user = Quickshell.env("USER");
            const own = agent.flow.identities.find(i => !i.isGroup && i.string === user);
            if (own)
                agent.flow.selectedIdentity = own;
            input.text = "";
            input.forceActiveFocus();
        }
    }

    Connections {
        target: root.flow
        function onAuthenticationFailed() { input.text = ""; }
    }

    PanelWindow {
        id: win
        visible: agent.isActive && root.flow !== null
        anchors { top: true; bottom: true; left: true; right: true }
        color: "#b8070b14"
        exclusionMode: ExclusionMode.Ignore
        WlrLayershell.layer: WlrLayer.Overlay
        WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
        WlrLayershell.namespace: "aura-polkit"

        Frame {
            x: (win.width - width) / 2
            y: (win.height - height) / 2
            width: 480
            height: content.implicitHeight + 36
            cut: 18
            stroke: Theme.gold

            Column {
                id: content
                x: 24; y: 22
                width: parent.width - 48
                spacing: 14

                Text {
                    text: "// AUTHENTICATE"
                    color: Theme.gold
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
                }

                Text {
                    width: parent.width
                    wrapMode: Text.Wrap
                    text: root.flow ? root.flow.message : ""
                    color: Theme.text
                    font.family: Theme.textFont; font.pixelSize: 15
                }

                Text {
                    width: parent.width
                    elide: Text.ElideRight
                    text: root.flow && root.flow.selectedIdentity
                        ? "AS " + root.flow.selectedIdentity.string.toUpperCase() : ""
                    color: Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 2
                }

                Item {
                    width: parent.width; height: 34
                    Text {
                        id: arrow
                        anchors.verticalCenter: input.verticalCenter
                        text: ">"
                        color: Theme.gold
                        font.family: Theme.titleFont; font.pixelSize: 18
                    }
                    TextInput {
                        id: input
                        anchors.left: arrow.right; anchors.leftMargin: 10
                        anchors.right: parent.right
                        color: Theme.text
                        selectionColor: Theme.cyanDim
                        font.family: Theme.textFont; font.pixelSize: 18
                        echoMode: root.flow && root.flow.responseVisible ? TextInput.Normal : TextInput.Password
                        enabled: root.flow !== null && root.flow.isResponseRequired
                        focus: true
                        Keys.onEscapePressed: root.flow.cancelAuthenticationRequest()
                        Keys.onReturnPressed: root.flow.submit(input.text)
                        Keys.onEnterPressed: root.flow.submit(input.text)
                    }
                    Rectangle {
                        anchors.bottom: parent.bottom
                        width: parent.width; height: 1
                        color: Theme.line
                    }
                }

                Text {
                    width: parent.width
                    wrapMode: Text.Wrap
                    visible: text !== ""
                    text: !root.flow ? ""
                        : root.flow.supplementaryMessage !== "" ? root.flow.supplementaryMessage
                        : root.flow.failed ? "Wrong password. Try again." : ""
                    color: root.flow && (root.flow.supplementaryIsError || root.flow.failed) ? Theme.drain : Theme.muted
                    font.family: Theme.textFont; font.pixelSize: 13
                }

                Text {
                    text: "ENTER CONFIRM    ESC CANCEL"
                    color: Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 11; font.letterSpacing: 2
                }
            }
        }
    }
}
       	Power.qml      ­import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland

Scope {
    id: root
    required property var lock
    property bool open: false
    property bool suspending: false

    readonly property var actions: [
        { id: "lock", label: "LOCK" },
        { id: "suspend", label: "SUSPEND" },
        { id: "logout", label: "LOG OUT" },
        { id: "reboot", label: "REBOOT" },
        { id: "poweroff", label: "POWER OFF" },
    ]

    function run(action) {
        root.open = false;
        if (action === "lock") {
            root.lock.lock();
        } else if (action === "suspend") {
            root.suspend();
        } else if (action === "logout") {
            worker.command = [ "hyprctl", "dispatch", "hl.dsp.exit()" ];
            worker.running = true;
        } else if (action === "reboot" || action === "poweroff") {
            worker.command = [ "sudo", "-n", "/etc/aura/power", action ];
            worker.running = true;
        }
    }

    function suspend() {
        if (root.suspending)
            return;
        root.suspending = true;
        root.lock.lock();
        if (root.lock.secure)
            root.sleep();
        else
            fallback.restart();
    }

    function sleep() {
        fallback.stop();
        root.suspending = false;
        worker.command = [ "sudo", "-n", "/etc/aura/power", "suspend" ];
        worker.running = true;
    }

    Connections {
        target: root.lock
        function onSecureChanged() {
            if (root.suspending && root.lock.secure)
                root.sleep();
        }
    }

    Timer { id: fallback; interval: 2000; onTriggered: root.sleep() }

    Process {
        id: worker
        stderr: StdioCollector {
            onStreamFinished: if (this.text.trim() !== "") console.warn("power:", this.text.trim())
        }
    }

    onOpenChanged: {
        if (open) {
            list.currentIndex = 0;
            list.forceActiveFocus();
        }
    }

    IpcHandler {
        target: "power"
        function toggle(): void { root.open = !root.open; }
        function suspend(): void { root.suspend(); }
    }

    PanelWindow {
        id: win
        visible: root.open
        anchors { top: true; bottom: true; left: true; right: true }
        color: "#b8070b14"
        exclusionMode: ExclusionMode.Ignore
        WlrLayershell.layer: WlrLayer.Overlay
        WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
        WlrLayershell.namespace: "aura-power"

        MouseArea { anchors.fill: parent; onClicked: root.open = false }

        Frame {
            x: (win.width - width) / 2
            y: (win.height - height) / 2
            width: 320
            height: content.implicitHeight + 36
            cut: 18
            stroke: Theme.cyan

            MouseArea { anchors.fill: parent }

            Column {
                id: content
                x: 0; y: 22
                width: parent.width
                spacing: 14

                Text {
                    x: 24
                    text: "// POWER"
                    color: Theme.gold
                    font.family: Theme.titleFont; font.pixelSize: 12; font.letterSpacing: 3
                }

                ListView {
                    id: list
                    width: parent.width
                    height: count * 46
                    model: root.actions
                    highlightMoveDuration: 0
                    interactive: false
                    focus: true
                    Keys.onEscapePressed: root.open = false
                    Keys.onReturnPressed: root.run(root.actions[currentIndex].id)
                    Keys.onEnterPressed: root.run(root.actions[currentIndex].id)

                    delegate: Item {
                        id: item
                        required property var modelData
                        required property int index
                        readonly property bool current: ListView.isCurrentItem
                        width: list.width; height: 46

                        Rectangle {
                            anchors.fill: parent
                            color: item.current ? Theme.panelHi : "transparent"
                        }
                        Rectangle {
                            width: 2; height: parent.height
                            color: item.current ? Theme.cyan : "transparent"
                        }
                        Diamond {
                            x: 24
                            anchors.verticalCenter: parent.verticalCenter
                            size: 8
                            filled: item.current
                            color: item.modelData.id === "poweroff" ? Theme.drain : Theme.cyan
                        }
                        Text {
                            x: 52
                            anchors.verticalCenter: parent.verticalCenter
                            text: item.modelData.label
                            color: item.current ? Theme.text : Theme.muted
                            font.family: Theme.titleFont; font.pixelSize: 15; font.letterSpacing: 3
                        }
                        MouseArea {
                            anchors.fill: parent
                            hoverEnabled: true
                            onEntered: list.currentIndex = item.index
                            onClicked: root.run(item.modelData.id)
                        }
                    }
                }

                Text {
                    x: 24
                    text: "ENTER RUN    ESC CLOSE"
                    color: Theme.muted
                    font.family: Theme.titleFont; font.pixelSize: 11; font.letterSpacing: 2
                }
            }
        }
    }
}
       	Theme.qml      		pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io

Singleton {
    readonly property string stateDir: Quickshell.env("HOME") + "/.local/state/aura"

    // background and surfaces
    readonly property color void_: colors.void_
    readonly property color panel: colors.panel
    readonly property color panelHi: colors.panelHi
    readonly property color line: colors.line
    // accents: focus and selection, the mark and the clock, error and
    // urgency
    readonly property color cyan: colors.cyan
    readonly property color cyanDim: colors.cyanDim
    readonly property color gold: colors.gold
    readonly property color drain: colors.drain
    // text
    readonly property color text: colors.text
    readonly property color muted: colors.muted

    // Share Tech Mono in the labels, the titles, and the clock; Google
    // Sans Code in the text
    readonly property string titleFont: "Share Tech Mono"
    readonly property string textFont: "Google Sans Code"

    readonly property int barHeight: 36
    readonly property int cut: 14

    // after matugen writes or removes the file (Wallpaper.qml): the
    // directory of the file can be missing at the start, without a watch
    function reload() { file.reload(); }

    FileView {
        id: file
        path: stateDir + "/theme.json"
        watchChanges: true
        printErrors: false
        onFileChanged: reload()
        // without the file (or after its removal), the sketch
        onLoadFailed: colors.reset()

        JsonAdapter {
            id: colors
            property string void_: "#070b14"
            property string panel: "#0d1626"
            property string panelHi: "#13203a"
            property string line: "#24486a"
            property string cyan: "#6fd3e8"
            property string cyanDim: "#3b8ea6"
            property string gold: "#d8b25a"
            property string drain: "#e0506a"
            property string text: "#e4edf5"
            property string muted: "#8ea3b8"

            function reset() {
                void_ = "#070b14"; panel = "#0d1626"; panelHi = "#13203a"; line = "#24486a";
                cyan = "#6fd3e8"; cyanDim = "#3b8ea6"; gold = "#d8b25a"; drain = "#e0506a";
                text = "#e4edf5"; muted = "#8ea3b8";
            }
        }
    }
}
       Wallpaper.qml      £import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland

Scope {
    id: root
    property string state: "idle"
    readonly property string config: "/etc/xdg/aura/matugen/config.toml"

    function run(script, args) {
        if (worker.running)
            return "busy";
        root.state = "running";
        worker.command = [ "sh", "-c", 'mkdir -p "$HOME/.local/state/aura" && ' + script, "aura-theme" ].concat(args);
        worker.running = true;
        return "started";
    }

    IpcHandler {
        target: "theme"
        function image(path: string): string {
            if (!path.startsWith("/"))
                return "the path must be absolute";
            return root.run('matugen image "$1" -c "$2" -m dark --source-color-index 0 -q'
                + ' && printf "%s\\n" "$1" > "$HOME/.local/state/aura/wallpaper"'
                + ' && hyprctl reload > /dev/null', [ path, root.config ]);
        }
        function color(hex: string): string {
            if (!/^#[0-9a-fA-F]{6}$/.test(hex))
                return "the color must be #rrggbb";
            return root.run('matugen color hex "$1" -c "$2" -m dark -q'
                + ' && rm -f "$HOME/.local/state/aura/wallpaper"'
                + ' && hyprctl reload > /dev/null', [ hex, root.config ]);
        }
        function reset(): string {
            return root.run('cd "$HOME/.local/state/aura" && rm -f theme.json hyprland-theme.lua wallpaper'
                + ' && hyprctl reload > /dev/null', []);
        }
        function state(): string { return root.state; }
    }

    Process {
        id: worker
        stderr: StdioCollector {
            onStreamFinished: if (this.text.trim() !== "") console.warn("theme:", this.text.trim())
        }
        onExited: (code, status) => {
            root.state = code === 0 ? "idle" : "failed";
            Theme.reload();
            wallpaperFile.reload();
        }
    }

    FileView {
        id: wallpaperFile
        path: Theme.stateDir + "/wallpaper"
        printErrors: false
    }

    readonly property string wallpaper: wallpaperFile.loaded ? wallpaperFile.text().trim() : ""

    Variants {
        model: Quickshell.screens

        PanelWindow {
            required property var modelData
            screen: modelData
            anchors { top: true; bottom: true; left: true; right: true }
            color: Theme.void_
            exclusionMode: ExclusionMode.Ignore
            mask: Region {}
            WlrLayershell.layer: WlrLayer.Background
            WlrLayershell.namespace: "aura-wallpaper"

            Image {
                anchors.fill: parent
                visible: root.wallpaper !== ""
                source: root.wallpaper !== "" ? "file://" + root.wallpaper : ""
                fillMode: Image.PreserveAspectCrop
                asynchronous: true
                sourceSize.width: width
                sourceSize.height: height
            }
        }
    }
}
       	shell.qml      Vimport QtQuick
import Quickshell

ShellRoot {
    // before the bars, which use them. The ids are not the names of the
    // properties: in "power: power", the name on the right is the
    // property of the object itself.
    Lock { id: lockScreen }
    Power { id: powerMenu; lock: lockScreen }
    NetworkPanel { id: networkPanel }
    BluetoothPanel { id: bluetoothPanel }

    Wallpaper {}
    Variants {
        model: Quickshell.screens
        Bar { network: networkPanel; bluetooth: bluetoothPanel; power: powerMenu }
    }
    Launcher {}
    Notifications {}
    Osd {}
    Polkit {}
}
       sw       @/shikumi/software/profile-env-1/01k2l8xpsx8s2w2mlxkl57abpm6qm6pk