add blocker presets
This commit is contained in:
12 files changed
+426
-83
No files matched your search
@@ -29,27 +29,21 @@ ScrollView {
|
||||
controller.patchSettings({ notifications: { telegram: patch } })
|
||||
}
|
||||
|
||||
// Presets are a saved list on the server (`pomodoro.presets`), each one a
|
||||
// name plus its own work/short/long minutes — editable here, not baked
|
||||
// into the UI. `_merge` on the backend replaces list fields wholesale, so
|
||||
// editing one preset's number means resending the whole list.
|
||||
function patchPreset(index, key, value) {
|
||||
if (!page.pomodoro || !page.pomodoro.presets) return
|
||||
var presets = page.pomodoro.presets.map(function (p) { return Object.assign({}, p) })
|
||||
presets[index][key] = value
|
||||
controller.patchSettings({ pomodoro: { presets: presets } })
|
||||
}
|
||||
function applyPreset(index) {
|
||||
if (!page.pomodoro || !page.pomodoro.presets) return
|
||||
var preset = page.pomodoro.presets[index]
|
||||
controller.patchSettings({
|
||||
pomodoro: {
|
||||
work_minutes: preset.work_minutes,
|
||||
short_break_minutes: preset.short_break_minutes,
|
||||
long_break_minutes: preset.long_break_minutes,
|
||||
cycles_before_long_break: preset.cycles_before_long_break
|
||||
}
|
||||
})
|
||||
// The Focus/Short break/Long break fields always show and edit the live
|
||||
// settings. When they still match a saved preset, the edit also rewrites
|
||||
// that preset's own numbers, so picking it again later gets you back to
|
||||
// where you left off rather than to some older saved value.
|
||||
function patchDuration(key, value) {
|
||||
if (!page.pomodoro) return
|
||||
var patch = {}; patch[key] = value
|
||||
var idx = controller.activePresetIndex
|
||||
if (idx >= 0 && page.pomodoro.presets) {
|
||||
var presets = page.pomodoro.presets.map(function (p) { return Object.assign({}, p) })
|
||||
presets[idx] = Object.assign(presets[idx], patch)
|
||||
controller.patchSettings({ pomodoro: Object.assign({ presets: presets }, patch) })
|
||||
} else {
|
||||
controller.patchSettings({ pomodoro: patch })
|
||||
}
|
||||
}
|
||||
|
||||
component Field: ColumnLayout {
|
||||
@@ -127,68 +121,32 @@ ScrollView {
|
||||
spacing: 12
|
||||
SectionTitle { text: "Timer" }
|
||||
|
||||
// Presets: a saved list of work/short/long combos. "Apply" copies
|
||||
// one onto the live settings below; the numbers on each row are
|
||||
// the preset's own and edit it in place.
|
||||
ColumnLayout {
|
||||
// The preset switcher: pick one and it applies at once. The fields
|
||||
// below always belong to whichever one is lit — there is nothing
|
||||
// to show for the others until you switch to them.
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Repeater {
|
||||
model: page.pomodoro && page.pomodoro.presets ? page.pomodoro.presets : []
|
||||
|
||||
RowLayout {
|
||||
id: presetRow
|
||||
delegate: PresetChip {
|
||||
required property var modelData
|
||||
required property int index
|
||||
Layout.fillWidth: true
|
||||
spacing: 16
|
||||
|
||||
readonly property bool isActive: page.pomodoro
|
||||
&& page.pomodoro.work_minutes === modelData.work_minutes
|
||||
&& page.pomodoro.short_break_minutes === modelData.short_break_minutes
|
||||
&& page.pomodoro.long_break_minutes === modelData.long_break_minutes
|
||||
|
||||
Label {
|
||||
text: presetRow.modelData.name
|
||||
color: presetRow.isActive ? Theme.ember : Theme.ink
|
||||
font.pixelSize: 13
|
||||
font.weight: presetRow.isActive ? Font.DemiBold : Font.Medium
|
||||
font.family: Theme.sansFamily
|
||||
Layout.preferredWidth: 70
|
||||
}
|
||||
Field {
|
||||
label: "Focus"
|
||||
SpinBox {
|
||||
from: 1; to: 240
|
||||
value: presetRow.modelData.work_minutes
|
||||
onValueModified: page.patchPreset(presetRow.index, "work_minutes", value)
|
||||
}
|
||||
}
|
||||
Field {
|
||||
label: "Short break"
|
||||
SpinBox {
|
||||
from: 1; to: 120
|
||||
value: presetRow.modelData.short_break_minutes
|
||||
onValueModified: page.patchPreset(presetRow.index, "short_break_minutes", value)
|
||||
}
|
||||
}
|
||||
Field {
|
||||
label: "Long break"
|
||||
SpinBox {
|
||||
from: 1; to: 240
|
||||
value: presetRow.modelData.long_break_minutes
|
||||
onValueModified: page.patchPreset(presetRow.index, "long_break_minutes", value)
|
||||
}
|
||||
}
|
||||
GhostButton {
|
||||
text: presetRow.isActive ? "Active" : "Apply"
|
||||
enabled: !presetRow.isActive
|
||||
onClicked: page.applyPreset(presetRow.index)
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
text: modelData.name
|
||||
active: controller.activePresetIndex === index
|
||||
onClicked: controller.applyPreset(index)
|
||||
}
|
||||
}
|
||||
Label {
|
||||
visible: controller.activePresetIndex === -1
|
||||
text: "Custom"
|
||||
color: Theme.muted
|
||||
font.pixelSize: 12
|
||||
font.family: Theme.sansFamily
|
||||
leftPadding: 6
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
|
||||
Flow {
|
||||
@@ -199,7 +157,7 @@ ScrollView {
|
||||
SpinBox {
|
||||
from: 1; to: 240
|
||||
value: page.pomodoro ? page.pomodoro.work_minutes : 25
|
||||
onValueModified: page.patchPomodoro("work_minutes", value)
|
||||
onValueModified: page.patchDuration("work_minutes", value)
|
||||
}
|
||||
}
|
||||
Field {
|
||||
@@ -207,7 +165,7 @@ ScrollView {
|
||||
SpinBox {
|
||||
from: 1; to: 120
|
||||
value: page.pomodoro ? page.pomodoro.short_break_minutes : 5
|
||||
onValueModified: page.patchPomodoro("short_break_minutes", value)
|
||||
onValueModified: page.patchDuration("short_break_minutes", value)
|
||||
}
|
||||
}
|
||||
Field {
|
||||
@@ -215,7 +173,7 @@ ScrollView {
|
||||
SpinBox {
|
||||
from: 1; to: 240
|
||||
value: page.pomodoro ? page.pomodoro.long_break_minutes : 15
|
||||
onValueModified: page.patchPomodoro("long_break_minutes", value)
|
||||
onValueModified: page.patchDuration("long_break_minutes", value)
|
||||
}
|
||||
}
|
||||
Field {
|
||||
|
||||
@@ -102,6 +102,29 @@ ScrollView {
|
||||
idle: !controller.timerEnabled || !controller.running
|
||||
}
|
||||
|
||||
// Switching here takes effect at once — it resizes whatever
|
||||
// is already running or paused too, not just the next one.
|
||||
RowLayout {
|
||||
visible: controller.timerEnabled
|
||||
&& controller.settings.pomodoro
|
||||
&& controller.settings.pomodoro.presets
|
||||
&& controller.settings.pomodoro.presets.length > 0
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 14
|
||||
spacing: 8
|
||||
|
||||
Repeater {
|
||||
model: controller.settings.pomodoro ? controller.settings.pomodoro.presets : []
|
||||
delegate: PresetChip {
|
||||
required property var modelData
|
||||
required property int index
|
||||
text: modelData.name
|
||||
active: controller.activePresetIndex === index
|
||||
onClicked: controller.applyPreset(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: controller.timerEnabled && controller.running
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// A pill in a preset switcher: filled ember when it is the one the live
|
||||
// settings currently match, outlined otherwise. Clicking any pill applies it
|
||||
// at once — there is no separate "Apply" step. Shared by SettingsPage (the
|
||||
// full switcher, with the numbers editable below it) and TimerPage (a quick
|
||||
// way to change the length of the *next* interval without leaving the dial).
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: chip
|
||||
property string text: ""
|
||||
property bool active: false
|
||||
signal clicked()
|
||||
|
||||
implicitWidth: label.implicitWidth + 28
|
||||
implicitHeight: 32
|
||||
radius: 16
|
||||
color: chip.active ? Theme.ember : (chipHover.hovered ? Qt.alpha(Theme.ember, 0.10) : "transparent")
|
||||
border.width: chip.active ? 0 : 1
|
||||
border.color: chipHover.hovered ? Theme.ember : Theme.rule
|
||||
Behavior on color { ColorAnimation { duration: 110 } }
|
||||
|
||||
Label {
|
||||
id: label
|
||||
anchors.centerIn: parent
|
||||
text: chip.text
|
||||
color: chip.active ? "white" : Theme.ink
|
||||
font.pixelSize: 12
|
||||
font.weight: chip.active ? Font.DemiBold : Font.Medium
|
||||
font.family: Theme.sansFamily
|
||||
}
|
||||
HoverHandler { id: chipHover; cursorShape: Qt.PointingHandCursor }
|
||||
TapHandler {
|
||||
grabPermissions: PointerHandler.TakeOverForbidden
|
||||
onTapped: chip.clicked()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user