2026-07-21 18:55:02 -04:00
|
|
|
import QtQuick
|
|
|
|
|
import Quickshell
|
|
|
|
|
import Quickshell.Io
|
|
|
|
|
import QtQuick.Layouts
|
|
|
|
|
import qs.services
|
|
|
|
|
import qs.modules.common
|
|
|
|
|
import qs.modules.common.functions
|
|
|
|
|
import qs.modules.common.widgets
|
|
|
|
|
|
|
|
|
|
ContentPage {
|
|
|
|
|
forceWidth: true
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "volume_up"
|
|
|
|
|
title: Translation.tr("Audio")
|
|
|
|
|
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "hearing"
|
|
|
|
|
text: Translation.tr("Earbang protection")
|
|
|
|
|
checked: Config.options.audio.protection.enable
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.audio.protection.enable = checked;
|
|
|
|
|
}
|
|
|
|
|
StyledToolTip {
|
|
|
|
|
text: Translation.tr("Prevents abrupt increments and restricts volume limit")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigRow {
|
|
|
|
|
enabled: Config.options.audio.protection.enable
|
|
|
|
|
ConfigSpinBox {
|
|
|
|
|
icon: "arrow_warm_up"
|
|
|
|
|
text: Translation.tr("Max allowed increase")
|
|
|
|
|
value: Config.options.audio.protection.maxAllowedIncrease
|
|
|
|
|
from: 0
|
|
|
|
|
to: 100
|
|
|
|
|
stepSize: 2
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
Config.options.audio.protection.maxAllowedIncrease = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigSpinBox {
|
|
|
|
|
icon: "vertical_align_top"
|
|
|
|
|
text: Translation.tr("Volume limit")
|
|
|
|
|
value: Config.options.audio.protection.maxAllowed
|
|
|
|
|
from: 0
|
|
|
|
|
to: 154 // pavucontrol allows up to 153%
|
|
|
|
|
stepSize: 2
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
Config.options.audio.protection.maxAllowed = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "battery_android_full"
|
|
|
|
|
title: Translation.tr("Battery")
|
|
|
|
|
|
|
|
|
|
ConfigRow {
|
|
|
|
|
uniform: true
|
|
|
|
|
ConfigSpinBox {
|
|
|
|
|
icon: "warning"
|
|
|
|
|
text: Translation.tr("Low warning")
|
|
|
|
|
value: Config.options.battery.low
|
|
|
|
|
from: 0
|
|
|
|
|
to: 100
|
|
|
|
|
stepSize: 5
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
Config.options.battery.low = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigSpinBox {
|
|
|
|
|
icon: "dangerous"
|
|
|
|
|
text: Translation.tr("Critical warning")
|
|
|
|
|
value: Config.options.battery.critical
|
|
|
|
|
from: 0
|
|
|
|
|
to: 100
|
|
|
|
|
stepSize: 5
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
Config.options.battery.critical = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigRow {
|
|
|
|
|
uniform: false
|
|
|
|
|
Layout.fillWidth: false
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "pause"
|
|
|
|
|
text: Translation.tr("Automatic suspend")
|
|
|
|
|
checked: Config.options.battery.automaticSuspend
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.battery.automaticSuspend = checked;
|
|
|
|
|
}
|
|
|
|
|
StyledToolTip {
|
|
|
|
|
text: Translation.tr("Automatically suspends the system when battery is low")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigSpinBox {
|
|
|
|
|
enabled: Config.options.battery.automaticSuspend
|
|
|
|
|
text: Translation.tr("at")
|
|
|
|
|
value: Config.options.battery.suspend
|
|
|
|
|
from: 0
|
|
|
|
|
to: 100
|
|
|
|
|
stepSize: 5
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
Config.options.battery.suspend = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigRow {
|
|
|
|
|
uniform: true
|
|
|
|
|
ConfigSpinBox {
|
|
|
|
|
icon: "charger"
|
|
|
|
|
text: Translation.tr("Full warning")
|
|
|
|
|
value: Config.options.battery.full
|
|
|
|
|
from: 0
|
|
|
|
|
to: 101
|
|
|
|
|
stepSize: 5
|
|
|
|
|
onValueChanged: {
|
|
|
|
|
Config.options.battery.full = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "language"
|
|
|
|
|
title: Translation.tr("Language")
|
|
|
|
|
|
|
|
|
|
ContentSubsection {
|
|
|
|
|
title: Translation.tr("Interface Language")
|
|
|
|
|
tooltip: Translation.tr("Select the language for the user interface.\n\"Auto\" will use your system's locale.")
|
|
|
|
|
|
|
|
|
|
StyledComboBox {
|
|
|
|
|
id: languageSelector
|
|
|
|
|
buttonIcon: "language"
|
|
|
|
|
textRole: "displayName"
|
|
|
|
|
|
|
|
|
|
model: [
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("Auto (System)"),
|
|
|
|
|
value: "auto"
|
|
|
|
|
},
|
|
|
|
|
...Translation.allAvailableLanguages.map(lang => {
|
|
|
|
|
return {
|
|
|
|
|
displayName: lang,
|
|
|
|
|
value: lang
|
|
|
|
|
};
|
|
|
|
|
})]
|
|
|
|
|
|
|
|
|
|
currentIndex: {
|
|
|
|
|
const index = model.findIndex(item => item.value === Config.options.language.ui);
|
|
|
|
|
return index !== -1 ? index : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onActivated: index => {
|
|
|
|
|
Config.options.language.ui = model[index].value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-16 14:02:22 -04:00
|
|
|
// Upstream's "Generate translation with Gemini" subsection is cut. It
|
|
|
|
|
// shelled to `Directories.aiTranslationScriptPath` with its own API key
|
|
|
|
|
// and a hardcoded provider — a second model path beside `services/Ai.qml`
|
|
|
|
|
// and the Bifrost server, which is the "no hardcoded models" rule and a
|
|
|
|
|
// two-writer shape besides.
|
2026-07-21 18:55:02 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "rule"
|
|
|
|
|
title: Translation.tr("Policies")
|
|
|
|
|
|
|
|
|
|
ConfigRow {
|
|
|
|
|
|
|
|
|
|
// AI policy
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
ContentSubsectionLabel {
|
|
|
|
|
text: Translation.tr("AI")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ConfigSelectionArray {
|
|
|
|
|
currentValue: Config.options.policies.ai
|
|
|
|
|
onSelected: newValue => {
|
|
|
|
|
Config.options.policies.ai = newValue;
|
|
|
|
|
}
|
|
|
|
|
options: [
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("No"),
|
|
|
|
|
icon: "close",
|
|
|
|
|
value: 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("Yes"),
|
|
|
|
|
icon: "check",
|
|
|
|
|
value: 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("Local only"),
|
|
|
|
|
icon: "sync_saved_locally",
|
|
|
|
|
value: 2
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Weeb policy
|
|
|
|
|
ColumnLayout {
|
|
|
|
|
|
|
|
|
|
ContentSubsectionLabel {
|
|
|
|
|
text: Translation.tr("Weeb")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ConfigSelectionArray {
|
|
|
|
|
currentValue: Config.options.policies.weeb
|
|
|
|
|
onSelected: newValue => {
|
|
|
|
|
Config.options.policies.weeb = newValue;
|
|
|
|
|
}
|
|
|
|
|
options: [
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("No"),
|
|
|
|
|
icon: "close",
|
|
|
|
|
value: 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("Yes"),
|
|
|
|
|
icon: "check",
|
|
|
|
|
value: 1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("Closet"),
|
|
|
|
|
icon: "ev_shadow",
|
|
|
|
|
value: 2
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "notification_sound"
|
|
|
|
|
title: Translation.tr("Sounds")
|
|
|
|
|
ConfigRow {
|
|
|
|
|
uniform: true
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "battery_android_full"
|
|
|
|
|
text: Translation.tr("Battery")
|
|
|
|
|
checked: Config.options.sounds.battery
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.sounds.battery = checked;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "av_timer"
|
|
|
|
|
text: Translation.tr("Pomodoro")
|
|
|
|
|
checked: Config.options.sounds.pomodoro
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.sounds.pomodoro = checked;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "nest_clock_farsight_analog"
|
|
|
|
|
title: Translation.tr("Time")
|
|
|
|
|
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "pace"
|
|
|
|
|
text: Translation.tr("Second precision")
|
|
|
|
|
checked: Config.options.time.secondPrecision
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.time.secondPrecision = checked;
|
|
|
|
|
}
|
|
|
|
|
StyledToolTip {
|
|
|
|
|
text: Translation.tr("Enable if you want clocks to show seconds accurately")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSubsection {
|
|
|
|
|
title: Translation.tr("Format")
|
|
|
|
|
tooltip: ""
|
|
|
|
|
|
|
|
|
|
ConfigSelectionArray {
|
|
|
|
|
currentValue: Config.options.time.format
|
2026-08-16 14:02:22 -04:00
|
|
|
// The two `sed`s that used to rewrite `~/.config/hypr/
|
|
|
|
|
// hyprlock.conf` are gone. `lock.useHyprlock` is false on this
|
|
|
|
|
// device — the lock surface is `modules/souveraine/lock` — so
|
|
|
|
|
// they edited a file nothing reads, and did it by shelling out
|
|
|
|
|
// to bash on every selection.
|
2026-07-21 18:55:02 -04:00
|
|
|
onSelected: newValue => {
|
|
|
|
|
Config.options.time.format = newValue;
|
|
|
|
|
}
|
|
|
|
|
options: [
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("24h"),
|
|
|
|
|
value: "hh:mm"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("12h am/pm"),
|
|
|
|
|
value: "h:mm ap"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
displayName: Translation.tr("12h AM/PM"),
|
|
|
|
|
value: "h:mm AP"
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ContentSection {
|
|
|
|
|
icon: "work_alert"
|
|
|
|
|
title: Translation.tr("Work safety")
|
|
|
|
|
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "assignment"
|
|
|
|
|
text: Translation.tr("Hide clipboard images copied from sussy sources")
|
|
|
|
|
checked: Config.options.workSafety.enable.clipboard
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.workSafety.enable.clipboard = checked;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ConfigSwitch {
|
|
|
|
|
buttonIcon: "wallpaper"
|
|
|
|
|
text: Translation.tr("Hide sussy/anime wallpapers")
|
|
|
|
|
checked: Config.options.workSafety.enable.wallpaper
|
|
|
|
|
onCheckedChanged: {
|
|
|
|
|
Config.options.workSafety.enable.wallpaper = checked;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|