Files
Panama/config/dot/quickshell/modules/settings/FocusAllowChips.qml
T

258 lines
7.9 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// The applications a focus mode lets through, as chips rather than a second
// unbounded list of every application that has ever notified.
//
// The old editor unfolded the whole application universe under every mode,
// which meant scrolling a hundred switches to add one exception. What a person
// wants to read is the short list of things that may interrupt; adding to it is
// a search, not a scan.
//
// An id that is allowed but no longer known still gets a chip, spelled as the
// raw id, so an exception can always be removed even after the application that
// earned it is gone.
import QtQuick
import qs.config
import qs.modules.clipboard
Column {
id: root
// The mode's allow list: application ids.
property var allow: []
// The same universe the per-application rules use: [{ id, name }].
property var knownApps: []
property bool divider: true
signal toggled(string appId, bool allowed)
property bool adding: false
function nameOf(appId: string): string {
const known = root.knownApps.find(app => String(app.id) === appId);
return known ? String(known.name) : appId;
}
readonly property var allowed: (root.allow ?? []).map(String)
// Capped at eight: this is a search box, not a browser, and a list long
// enough to scroll defeats the point of having replaced one.
readonly property var matches: {
const needle = search.text.trim().toLowerCase();
const out = [];
for (const app of root.knownApps) {
const id = String(app.id);
if (root.allowed.indexOf(id) >= 0)
continue;
const haystack = (String(app.name) + " " + id).toLowerCase();
if (needle !== "" && haystack.indexOf(needle) < 0)
continue;
out.push(app);
if (out.length >= 8)
break;
}
return out;
}
width: parent ? parent.width : 620
spacing: 0
Item {
id: head
width: parent.width
implicitHeight: Math.max(56, Math.max(copy.implicitHeight, chips.implicitHeight) + 20)
Column {
id: copy
anchors.left: parent.left
anchors.right: chips.left
anchors.rightMargin: 16
anchors.verticalCenter: parent.verticalCenter
spacing: 3
Text {
width: parent.width
text: "May interrupt"
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize
font.weight: Font.Medium
elide: Text.ElideRight
}
Text {
width: parent.width
text: "Apps that break through while this mode is on"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
wrapMode: Text.WordWrap
}
}
Flow {
id: chips
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: Math.max(160, parent.width * 0.45)
spacing: 7
Repeater {
model: root.allowed
Rectangle {
id: chip
required property string modelData
height: 26
width: chipLabel.implicitWidth + remove.width + 22
radius: Theme.pillRadius
color: Theme.alpha(Theme.accent, 0.1)
border.width: 1
border.color: Theme.alpha(Theme.accent, 0.28)
Text {
id: chipLabel
anchors.left: parent.left
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
text: root.nameOf(chip.modelData)
color: Theme.fg
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
Item {
id: remove
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: 20
height: 20
Text {
anchors.centerIn: parent
text: "×"
color: removeHover.hovered ? Theme.danger : Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSize + 2
}
HoverHandler {
id: removeHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: root.toggled(chip.modelData, false)
}
}
}
}
Rectangle {
id: addChip
height: 26
width: addLabel.implicitWidth + 20
radius: Theme.pillRadius
color: Theme.alpha(Theme.fg, addHover.hovered ? 0.1 : 0.05)
border.width: 1
border.color: Theme.alpha(Theme.fg, 0.2)
Text {
id: addLabel
anchors.centerIn: parent
text: root.adding ? "Cancel" : "+ Add app"
color: Theme.fgDim
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
}
HoverHandler {
id: addHover
cursorShape: Qt.PointingHandCursor
}
TapHandler {
onTapped: {
root.adding = !root.adding;
if (!root.adding)
search.text = "";
}
}
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 1
visible: root.divider && !root.adding
color: Theme.alpha(Theme.fg, 0.065)
}
}
Column {
width: parent.width
visible: root.adding
spacing: 0
Item {
width: parent.width
height: 40
SearchField {
id: search
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
placeholder: "Search apps"
}
}
Repeater {
model: root.matches
SettingRow {
id: candidate
required property var modelData
required property int index
width: parent.width
label: String(candidate.modelData.name ?? "")
detail: String(candidate.modelData.id ?? "")
controlWidth: 86
divider: candidate.index < root.matches.length - 1
SettingsButton {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: "Add"
onClicked: {
root.toggled(String(candidate.modelData.id), true);
search.text = "";
}
}
}
}
SettingRow {
width: parent.width
visible: root.matches.length === 0
label: "No applications left to add"
detail: "Applications appear here after their first notification"
divider: false
}
}
}