aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/modules
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/modules')
-rw-r--r--desktop/modules/appearance/WallpaperTab.qml20
-rw-r--r--desktop/modules/companion/ArtistsModule.qml67
-rw-r--r--desktop/modules/companion/CompanionModule.qml131
-rw-r--r--desktop/modules/companion/PhrasesModule.qml64
-rw-r--r--desktop/modules/companion/PhrasesPage.qml195
5 files changed, 0 insertions, 477 deletions
diff --git a/desktop/modules/appearance/WallpaperTab.qml b/desktop/modules/appearance/WallpaperTab.qml
index d9876ed..b204c6c 100644
--- a/desktop/modules/appearance/WallpaperTab.qml
+++ b/desktop/modules/appearance/WallpaperTab.qml
@@ -12,7 +12,6 @@
import Quickshell
import QtQuick
import "../.."
-import "../../companion"
// Wallpapers by folder, staged per screen and set together with Apply, beside
// a mock of the two screens above them. Sized by its host: the thumbnail list scrolls
@@ -340,25 +339,6 @@ Column {
}
}
- // The companion blushes at the hearted ones
- // (companion/Admired.qml). After the pick
- // MouseArea, so it takes the click. Outlined,
- // so it reads on a light image too.
- Text {
- readonly property bool on: Admired.listed(modelData)
- anchors { top: parent.top; right: parent.right; margins: 10 }
- visible: on || thumbHover.hovered
- text: on ? "\u{F02D1}" : "\u{F02D5}"
- color: on ? Theme.red : Theme.text
- style: Text.Outline
- styleColor: Qt.alpha(Theme.base, 0.6)
- font { family: Theme.iconFamily; pixelSize: Theme.fontSize + 8 }
- MouseArea {
- anchors { fill: parent; margins: -4 }
- cursorShape: Qt.PointingHandCursor
- onClicked: Admired.toggle(modelData)
- }
- }
}
}
}
diff --git a/desktop/modules/companion/ArtistsModule.qml b/desktop/modules/companion/ArtistsModule.qml
deleted file mode 100644
index a0d23f4..0000000
--- a/desktop/modules/companion/ArtistsModule.qml
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-import QtQuick
-import "../.."
-import "../../companion/Lines.js" as Lines
-
-// The lines the companion says when a track by an artist she knows starts,
-// matched as a case-insensitive substring of the player's artist. Same
-// draft, Save and Reset as PhrasesModule, on Prefs.companionArtists and
-// Lines.artists; the page's cls field holds the artist.
-Module {
- id: am
- name: "artists"
- label: "Companion artists"
- // nf-fa-music, present in Inconsolata Nerd Font.
- icon: "\uf001"
- settings: true
- group: "Companion"
- keywords: ["companion", "artist", "music", "song", "track", "line", "say", "2b"]
- searchItems: am.shown.map((a, i) => ({ text: a.cls + ": " + a.lines.join(" / "), key: "app:" + i }))
-
- property var draft: null
- property bool resetting: false
- readonly property var shown: am.draft ?? Lines.appList(Prefs.companionArtists, Lines.artists)
- readonly property bool valid: am.shown.every(a => String(a.cls).trim() !== ""
- && (a.lines || []).some(l => String(l).trim() !== ""))
- dirty: am.draft !== null
-
- function edit(list) { am.draft = list; am.resetting = false; }
- function reset() { am.draft = Lines.appList(null, Lines.artists); am.resetting = true; }
- function save() {
- if (am.resetting) Prefs.resetCompanionArtists();
- else Prefs.setCompanionArtists(Lines.toMap(am.draft));
- am.discard();
- }
- function discard() { am.draft = null; am.resetting = false; }
-
- page: Component {
- Page {
- title: "Companion artists"
- actions: Component {
- SaveBar { dirty: am.dirty; valid: am.valid; note: "every artist needs a name and a phrase"
- onSave: am.save(); onDiscard: am.discard() }
- }
- PhrasesPage {
- width: parent.width
- owner: am
- intro: "When a track by an artist she knows starts or changes, she says one of their lines at "
- + "random, under her 30 s line cooldown. The name matches any part of the player's artist, "
- + "ignoring case, so \"daft punk\" also catches \"Daft Punk, Pharrell Williams\". "
- + "Save applies at once."
- keyHint: "artist, e.g. linkin park"
- addText: "Add artist"
- saved: Prefs.companionArtists
- }
- }
- }
-}
diff --git a/desktop/modules/companion/CompanionModule.qml b/desktop/modules/companion/CompanionModule.qml
deleted file mode 100644
index 8d6a68d..0000000
--- a/desktop/modules/companion/CompanionModule.qml
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-import QtQuick
-import "../.."
-import "../appearance"
-import "../../companion"
-
-// The desktop companion's settings: whether she is shown, the same
-// preference SUPER+\ toggles, so the switch follows the key; and where her
-// wallpaper list is, marked with the heart in the wallpaper picker.
-Module {
- name: "companion"
- label: "Companion"
- // nf-md-account_heart, present in Inconsolata Nerd Font.
- icon: "\u{F0899}"
- settings: true
- group: "Companion"
- keywords: ["companion", "2b", "mascot", "character", "show", "hide", "wallpaper", "blush", "leotard", "timeout"]
-
- page: Component {
- Page {
- title: "Companion"
- Column {
- width: parent.width
- spacing: 6
-
- Item {
- width: parent.width
- height: 34
- Text {
- id: lbl
- anchors { left: parent.left; verticalCenter: parent.verticalCenter }
- width: 160
- text: "Shown"
- color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
- }
- Switch {
- id: sw
- anchors { left: lbl.right; leftMargin: 8; verticalCenter: parent.verticalCenter }
- checked: Prefs.companion
- onToggled: on => Prefs.setCompanion(on)
- }
- Text {
- anchors { left: sw.right; leftMargin: 10; right: parent.right; verticalCenter: parent.verticalCenter }
- elide: Text.ElideRight
- text: "Also SUPER+\\. Kept across restarts."
- color: Theme.overlay
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 }
- }
- }
- // After the self-destruct. Off keeps the leotard until she is
- // hidden and shown again; turning it back on starts from the
- // seconds in the field.
- Item {
- width: parent.width
- height: 34
- Text {
- id: lblSk
- anchors { left: parent.left; verticalCenter: parent.verticalCenter }
- width: 160
- text: "Leotard timeout"
- color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
- }
- Switch {
- id: swSk
- anchors { left: lblSk.right; leftMargin: 8; verticalCenter: parent.verticalCenter }
- checked: Prefs.companionSkirtless > 0
- onToggled: on => Prefs.setCompanionSkirtless(on ? (parseInt(fSk.value) || 60) : 0)
- }
- Field {
- id: fSk
- anchors { left: swSk.right; leftMargin: 10; verticalCenter: parent.verticalCenter }
- width: 60
- enabled: swSk.checked
- opacity: enabled ? 1 : 0.4
- value: String(Prefs.companionSkirtless || 60)
- placeholder: "60"
- onEdited: {
- const n = parseInt(value);
- if (n >= 1 && String(n) === value.trim()) Prefs.setCompanionSkirtless(n);
- else value = String(Prefs.companionSkirtless || 60);
- }
- }
- Text {
- anchors { left: fSk.right; leftMargin: 10; right: parent.right; verticalCenter: parent.verticalCenter }
- elide: Text.ElideRight
- text: swSk.checked ? "seconds" : "until she is hidden and shown again"
- color: Theme.overlay
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 }
- }
- }
- Item {
- width: parent.width
- height: 34
- Text {
- id: lbl2
- anchors { left: parent.left; verticalCenter: parent.verticalCenter }
- width: 160
- text: "Wallpaper list"
- color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
- }
- Field {
- anchors { left: lbl2.right; leftMargin: 8; right: parent.right; verticalCenter: parent.verticalCenter }
- value: Prefs.companionBlushFile
- placeholder: Admired.defaultPath.replace(Admired.home, "~")
- onEdited: Prefs.setCompanionBlushFile(value)
- }
- }
- Text {
- width: parent.width
- wrapMode: Text.WordWrap
- text: "One path per line. She blushes at these on an empty workspace; the heart in Wallpaper adds and removes them."
- color: Theme.overlay
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 5 }
- }
- }
- }
- }
-}
diff --git a/desktop/modules/companion/PhrasesModule.qml b/desktop/modules/companion/PhrasesModule.qml
deleted file mode 100644
index 7e4895a..0000000
--- a/desktop/modules/companion/PhrasesModule.qml
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-import QtQuick
-import "../.."
-import "../../companion/Lines.js" as Lines
-
-// The lines the companion says when focus moves to a program she
-// recognizes, by its lowercased window class. They live in Prefs and she
-// reads them live, so a save needs no restart. The page edits a draft here;
-// Save hands it to Prefs, Reset drops the saved set so Lines.js' defaults
-// show again.
-Module {
- id: pm
- name: "phrases"
- label: "Companion phrases"
- // nf-fa-comment, present in Inconsolata Nerd Font.
- icon: "\uf075"
- settings: true
- group: "Companion"
- keywords: ["companion", "phrase", "line", "say", "speak", "app", "program",
- "window", "class", "firefox", "2b"]
- searchItems: pm.shown.map((a, i) => ({ text: a.cls + ": " + a.lines.join(" / "), key: "app:" + i }))
-
- // null while there are no edits: the page then shows the saved set, or
- // Lines.js' defaults when nothing is saved.
- property var draft: null
- // Reset was pressed: Save drops the saved set rather than saving a copy
- // of the defaults, so later default changes still arrive.
- property bool resetting: false
- readonly property var shown: pm.draft ?? Lines.appList(Prefs.companionApps)
- // Every app needs a class and at least one non-empty phrase; Save waits.
- readonly property bool valid: pm.shown.every(a => String(a.cls).trim() !== ""
- && (a.lines || []).some(l => String(l).trim() !== ""))
- dirty: pm.draft !== null
-
- function edit(list) { pm.draft = list; pm.resetting = false; }
- function reset() { pm.draft = Lines.appList(null); pm.resetting = true; }
- function save() {
- if (pm.resetting) Prefs.resetCompanionApps();
- else Prefs.setCompanionApps(Lines.toMap(pm.draft));
- pm.discard();
- }
- function discard() { pm.draft = null; pm.resetting = false; }
-
- page: Component {
- Page {
- title: "Companion phrases"
- actions: Component {
- SaveBar { dirty: pm.dirty; valid: pm.valid; note: "every app needs a class and a phrase"
- onSave: pm.save(); onDiscard: pm.discard() }
- }
- PhrasesPage { width: parent.width; owner: pm }
- }
- }
-}
diff --git a/desktop/modules/companion/PhrasesPage.qml b/desktop/modules/companion/PhrasesPage.qml
deleted file mode 100644
index 1971171..0000000
--- a/desktop/modules/companion/PhrasesPage.qml
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 2 as
-// published by the Free Software Foundation.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-import QtQuick
-import "../.."
-
-// One card per recognized program: its window class and the lines she says
-// when focus moves to it. Every change edits the module's draft; the
-// header's Save hands the set to Prefs. Reset fills the draft with the
-// built-in set from Lines.js.
-Column {
- id: page
- spacing: 10
-
- // The module, holding the draft. Not named pm, its id (it would bind to
- // itself, AGENTS.md).
- required property QtObject owner
- // What the cards are keyed by; the defaults are the app set's, so
- // PhrasesModule passes nothing.
- property string intro: "When focus moves to a program she recognizes, she says one of its lines at random, a third "
- + "of the time and under her 30 s line cooldown. The class is Hyprland's window class, "
- + "lowercased (hyprctl activewindow shows it). Save applies at once."
- property string keyHint: "window class, e.g. firefox"
- property string addText: "Add app"
- // The saved set, for Reset's enabled state; null means the defaults.
- property var saved: Prefs.companionApps
- readonly property var list: owner.shown
- // The app card awaiting a second click on Remove.
- property int confirming: -1
-
- // Saves a copy of the list with app i replaced by fn(app), or removed
- // when fn returns null.
- function edit(i, fn) {
- const out = [];
- for (let j = 0; j < page.list.length; j++) {
- const a = page.list[j];
- const c = { cls: a.cls, lines: a.lines.slice() };
- if (j !== i) { out.push(c); continue; }
- const r = fn(c);
- if (r) out.push(r);
- }
- page.confirming = -1;
- page.owner.edit(out);
- }
-
- function addApp() { page.owner.edit(page.list.concat([{ cls: "", lines: [""] }])); }
- function removeApp(i) { page.edit(i, () => null); }
- function setCls(i, t) { page.edit(i, a => Object.assign(a, { cls: t })); }
- function addLine(i) { page.edit(i, a => Object.assign(a, { lines: a.lines.concat([""]) })); }
- function setLine(i, j, t) {
- page.edit(i, a => {
- const ls = a.lines.slice();
- ls[j] = t;
- return Object.assign(a, { lines: ls });
- });
- }
- function removeLine(i, j) { page.edit(i, a => Object.assign(a, { lines: a.lines.filter((_, k) => k !== j) })); }
-
- component Small: Text {
- color: Theme.subtext
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 }
- }
-
- // Reports every keystroke into the draft. Not bound to value, which
- // would reset the cursor; it follows the value only when the draft moves
- // under it (Discard, Reset). Empty is outlined, since Save refuses it.
- component Field: Rectangle {
- id: field
- property string value: ""
- property string placeholder: ""
- signal edited(string text)
- height: 32
- radius: 8
- color: Qt.alpha(Theme.base, 0.6)
- border.width: ti.text.trim() === "" ? 1 : 0
- border.color: Theme.red
- onValueChanged: if (ti.text !== field.value) ti.text = field.value
- TextInput {
- activeFocusOnTab: true
- id: ti
- anchors { fill: parent; leftMargin: 10; rightMargin: 10 }
- verticalAlignment: TextInput.AlignVCenter
- clip: true
- selectByMouse: true
- color: Theme.text
- font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 3 }
- Component.onCompleted: text = field.value
- onTextEdited: field.edited(text)
- Text {
- anchors.verticalCenter: parent.verticalCenter
- visible: parent.text === ""
- text: field.placeholder
- color: Theme.overlay
- font: parent.font
- }
- }
- }
-
- Small {
- width: page.width
- wrapMode: Text.Wrap
- text: page.intro
- }
-
- Repeater {
- // A count, not the list: a new list on every keystroke would rebuild
- // every card and drop the focus of the field being typed in.
- model: page.list.length
-
- delegate: Rectangle {
- id: card
- required property int index
- readonly property var modelData: page.list[index] ?? { cls: "", lines: [] }
- objectName: "app:" + index
- width: page.width
- height: body.implicitHeight + 20
- radius: 10
- color: Qt.alpha(Theme.surface, 0.45)
-
- Column {
- id: body
- anchors { left: parent.left; right: parent.right; top: parent.top; margins: 10 }
- spacing: 8
-
- Item {
- width: parent.width
- height: 32
- Field {
- anchors { left: parent.left; right: del.left; rightMargin: 8; top: parent.top; bottom: parent.bottom }
- value: card.modelData.cls
- placeholder: page.keyHint
- onEdited: t => page.setCls(card.index, t)
- }
- Button {
- id: del
- anchors { right: parent.right; verticalCenter: parent.verticalCenter }
- danger: true
- text: page.confirming === card.index ? "Confirm" : "Remove"
- onClicked: {
- if (page.confirming === card.index) page.removeApp(card.index);
- else page.confirming = card.index;
- }
- }
- }
-
- Repeater {
- model: card.modelData.lines.length
- delegate: Row {
- id: phraseRow
- required property int index
- width: body.width
- spacing: 6
- Field {
- width: phraseRow.width - removeBtn.width - phraseRow.spacing
- value: card.modelData.lines[phraseRow.index] ?? ""
- placeholder: "a line she says"
- onEdited: t => page.setLine(card.index, phraseRow.index, t)
- }
- Button {
- id: removeBtn
- // nf-fa-xmark, present in Inconsolata Nerd Font.
- icon: "\uf00d"
- danger: true
- onClicked: page.removeLine(card.index, phraseRow.index)
- }
- }
- }
-
- Button {
- text: "Add phrase"
- onClicked: page.addLine(card.index)
- }
- }
- }
- }
-
- Row {
- spacing: 8
- Button { text: page.addText; onClicked: page.addApp() }
- Button {
- text: "Reset to defaults"
- danger: true
- enabled: !page.owner.resetting && (page.saved !== null || page.owner.dirty)
- onClicked: page.owner.reset()
- }
- }
-}