161 lines
5.8 KiB
QML
161 lines
5.8 KiB
QML
// The focus tab: the modes that quiet this machine, and the timed session that
|
|
// is deliberately not one of them.
|
|
//
|
|
// Modes are conditions rather than alarms -- a mode is on because something is
|
|
// true right now -- so the editor never asks anyone to schedule an event. It
|
|
// asks what has to be true. Order is priority, which is why the list can be
|
|
// reordered and says so.
|
|
|
|
import QtQuick
|
|
import qs.config
|
|
import qs.services
|
|
|
|
SettingsPage {
|
|
id: root
|
|
|
|
// One mode is open for editing at a time; the point is a card you can read,
|
|
// not every mode unfolded at once.
|
|
property string expandedMode: ""
|
|
|
|
// The exception list belongs to the page rather than to the row: the
|
|
// applications it is chosen from are the same universe the per-application
|
|
// notification rules use, and the page is what reads it.
|
|
function toggleAllowed(mode: var, appId: string, allowed: bool): void {
|
|
const current = Array.isArray(mode.allow) ? mode.allow.map(String) : [];
|
|
const at = current.indexOf(appId);
|
|
if (allowed && at < 0)
|
|
current.push(appId);
|
|
else if (!allowed && at >= 0)
|
|
current.splice(at, 1);
|
|
FocusModes.update(String(mode.id), { allow: current });
|
|
}
|
|
|
|
title: "Focus"
|
|
lede: "Modes quiet this machine on their own terms — first matching mode wins, and the order below is the priority."
|
|
|
|
SettingsCard {
|
|
title: "Focus modes"
|
|
subtitle: FocusModes.active
|
|
? FocusModes.activeName + " is on because " + FocusModes.activeReason + "."
|
|
: "Drag a mode by its grip, or press up and down on it, to change which one wins."
|
|
|
|
TextRow {
|
|
visible: FocusModes.modes.length === 0
|
|
label: "No focus modes"
|
|
detail: "Add one below and give it something to react to"
|
|
divider: false
|
|
}
|
|
|
|
Repeater {
|
|
model: FocusModes.modes
|
|
|
|
delegate: FocusModeRow {
|
|
id: modeRow
|
|
|
|
required property var modelData
|
|
|
|
width: parent.width
|
|
mode: modeRow.modelData
|
|
knownApps: Notifs.applications
|
|
expanded: root.expandedMode === String(modeRow.modelData.id ?? "")
|
|
running: FocusModes.activeMode?.id === String(modeRow.modelData.id ?? "")
|
|
onActivated: root.expandedMode = modeRow.expanded
|
|
? ""
|
|
: String(modeRow.modelData.id ?? "")
|
|
onAllowToggled: (appId, allowed) =>
|
|
root.toggleAllowed(modeRow.modelData, appId, allowed)
|
|
}
|
|
}
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: 58
|
|
|
|
Rectangle {
|
|
id: newMode
|
|
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
height: 44
|
|
radius: Theme.cardRadius
|
|
color: Theme.alpha(Theme.fg, newModeHover.hovered ? 0.06 : 0.02)
|
|
border.width: 1
|
|
border.color: Theme.alpha(Theme.fg, 0.16)
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: "+ New focus mode"
|
|
color: newModeHover.hovered ? Theme.fg : Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
font.weight: Font.Medium
|
|
}
|
|
|
|
HoverHandler {
|
|
id: newModeHover
|
|
cursorShape: Qt.PointingHandCursor
|
|
}
|
|
|
|
// Created open, so the first thing anyone sees is the editor
|
|
// rather than a row named "New mode" with nothing to react to.
|
|
TapHandler {
|
|
onTapped: root.expandedMode = String(FocusModes.createMode("New mode"))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
title: "Focus sessions"
|
|
subtitle: "A timed, workspace-bound sprint — separate from modes, and it owns Do Not Disturb while it runs."
|
|
|
|
SegmentRow {
|
|
label: "Default duration"
|
|
detail: "Used by Super+Shift+F and Quick Settings"
|
|
options: [
|
|
{ value: 25, label: "25 min" },
|
|
{ value: 45, label: "45 min" },
|
|
{ value: 60, label: "60 min" },
|
|
{ value: 90, label: "90 min" }
|
|
]
|
|
value: DesktopPreferences.get("focusDurationMinutes")
|
|
onSelected: value => SystemSettings.commitPreference("focusDurationMinutes", value)
|
|
}
|
|
|
|
SettingRow {
|
|
label: "Keep the machine awake"
|
|
detail: Caffeine.enabled
|
|
? "The display will not blank or lock while this is on"
|
|
: "Caffeine — outside of sessions and modes too"
|
|
controlWidth: 48
|
|
|
|
SettingsToggle {
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
checked: Caffeine.enabled
|
|
onToggled: value => Caffeine.enabled = value
|
|
}
|
|
}
|
|
|
|
SettingRow {
|
|
label: FocusSession.active
|
|
? `Active on ${FocusSession.workspaceLabel}`
|
|
: "No session running"
|
|
detail: FocusSession.active
|
|
? `${FocusSession.remainingText} remaining`
|
|
: "Start one without leaving Settings"
|
|
divider: false
|
|
controlWidth: 120
|
|
|
|
SettingsButton {
|
|
anchors.right: parent.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: FocusSession.active ? "Show controls" : "Start focus"
|
|
tone: FocusSession.active ? "normal" : "accent"
|
|
onClicked: FocusSession.reveal()
|
|
}
|
|
}
|
|
}
|
|
}
|