Files
kadence/desktop/kadence_desktop/qml/BlockerPage.qml
T
2026-10-18 18:02:05 +03:00

192 lines
7.7 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.
// What the blocker is doing right now, and what it will do.
//
// The rules themselves are server-side (edit them in the web UI or below); this
// page is about *enforcement on this machine* — the helper, the hosts file and
// the process watcher.
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Layouts
import "components"
ScrollView {
id: page
contentWidth: availableWidth
clip: true
ColumnLayout {
width: page.availableWidth
spacing: 16
Banner {
Layout.fillWidth: true
visible: !controller.helperInstalled
text: "The privileged helper is not installed, so websites cannot be blocked. "
+ "Run: sudo desktop/helper/install.sh"
actionText: ""
}
Banner {
Layout.fillWidth: true
visible: controller.blockerError !== ""
text: controller.blockerError
}
ColumnLayout {
Layout.fillWidth: true
Layout.margins: 20
spacing: 16
Card {
title: controller.blockerActive ? "🛡 Blocking is ON" : "Blocking is off"
subtitle: controller.blockerReason
RowLayout {
Layout.fillWidth: true
spacing: 20
StatTile {
label: "Domains"
value: controller.blockedDomains.length
caption: "redirected to 127.0.0.1"
}
StatTile {
label: "Apps"
value: controller.blockedApps.length
caption: "closed on sight"
}
StatTile {
label: "Attempts today"
value: controller.stats.today ? controller.stats.today.blocked_attempts : 0
caption: "and counting"
}
}
RowLayout {
Layout.fillWidth: true
Switch {
text: "Enforce on this machine"
checked: controller.config.enforce_blocking
onToggled: controller.setConfig("enforce_blocking", checked)
}
Switch {
text: "Websites"
checked: controller.config.block_hosts_file
onToggled: controller.setConfig("block_hosts_file", checked)
}
Switch {
text: "Apps"
checked: controller.config.block_apps
onToggled: controller.setConfig("block_apps", checked)
}
}
}
Card {
title: "Blocked websites"
subtitle: "One hostname per line. `www.` and `m.` are added automatically."
TextArea {
id: domainsArea
Layout.fillWidth: true
Layout.minimumHeight: 140
wrapMode: TextArea.NoWrap
font.family: "Roboto Mono, monospace"
text: (controller.settings.blocker ? controller.settings.blocker.blocked_domains : []).join("\n")
placeholderText: "youtube.com\nreddit.com\ntwitter.com"
}
RowLayout {
PrimaryButton {
text: "Save websites"
onClicked: {
var list = domainsArea.text.split("\n").map(function (s) { return s.trim() })
.filter(function (s) { return s.length > 0 })
controller.patchSettings({ blocker: { blocked_domains: list } })
}
}
Item { Layout.fillWidth: true }
}
}
Card {
title: "Blocked applications"
subtitle: "Process names, matched loosely: `steam` also catches `steamwebhelper`."
TextArea {
id: appsArea
Layout.fillWidth: true
Layout.minimumHeight: 100
wrapMode: TextArea.NoWrap
font.family: "Roboto Mono, monospace"
text: (controller.settings.blocker ? controller.settings.blocker.blocked_apps : []).join("\n")
placeholderText: "steam\ndiscord\ntelegram-desktop"
}
RowLayout {
PrimaryButton {
text: "Save applications"
onClicked: {
var list = appsArea.text.split("\n").map(function (s) { return s.trim() })
.filter(function (s) { return s.length > 0 })
controller.patchSettings({ blocker: { blocked_apps: list } })
}
}
Item { Layout.fillWidth: true }
}
}
Card {
title: "When to block"
subtitle: "Server-side, so every device agrees."
RowLayout {
Layout.fillWidth: true
Switch {
text: "Blocking enabled"
checked: controller.settings.blocker ? controller.settings.blocker.enabled : false
onToggled: controller.patchSettings({ blocker: { enabled: checked } })
}
ComboBox {
Layout.preferredWidth: 220
model: ["During focus intervals", "Always", "On a schedule"]
currentIndex: {
var mode = controller.settings.blocker ? controller.settings.blocker.mode : "during_work"
return mode === "always" ? 1 : (mode === "scheduled" ? 2 : 0)
}
onActivated: function (index) {
var modes = ["during_work", "always", "scheduled"]
controller.patchSettings({ blocker: { mode: modes[index] } })
}
}
Switch {
text: "Keep blocking during breaks"
checked: controller.settings.blocker ? controller.settings.blocker.block_during_breaks : false
onToggled: controller.patchSettings({ blocker: { block_during_breaks: checked } })
}
}
}
Card {
title: "Today's temptations"
subtitle: "Every attempt the blocker turned away — this is what the daily report jokes about."
Repeater {
model: controller.stats.today ? controller.stats.today.blocked_top : []
delegate: RowLayout {
required property var modelData
Layout.fillWidth: true
Label { text: modelData.target; Layout.fillWidth: true }
Label { text: "× " + modelData.count; font.weight: Font.DemiBold }
}
}
Label {
visible: !controller.stats.today || controller.stats.today.blocked_top.length === 0
text: "Nothing yet today. Either the blocker is off, or you are behaving."
opacity: 0.6
font.pixelSize: 12
}
}
}
}
Component.onCompleted: controller.loadSettings()
}