settings: reorganize and add settings

This commit is contained in:
end-4 2025-06-21 11:59:40 +02:00
parent 5ffbd55f58
commit 7e46e40eeb
12 changed files with 489 additions and 317 deletions

View file

@ -203,7 +203,7 @@ Singleton {
animation: QtObject {
property QtObject elementMove: QtObject {
property int duration: 500
property int duration: animationCurves.expressiveDefaultSpatialDuration
property int type: Easing.BezierSpline
property list<real> bezierCurve: animationCurves.expressiveDefaultSpatial
property int velocity: 650
@ -249,7 +249,7 @@ Singleton {
}
}
property QtObject elementMoveFast: QtObject {
property int duration: 200
property int duration: animationCurves.expressiveEffectsDuration
property int type: Easing.BezierSpline
property list<real> bezierCurve: animationCurves.expressiveEffects
property int velocity: 850

View file

@ -17,6 +17,6 @@ ColumnLayout {
}
ColumnLayout {
id: sectionContent
spacing: 4
spacing: 8
}
}

View file

@ -0,0 +1,26 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "root:/modules/common/"
import "root:/modules/common/widgets/"
ColumnLayout {
id: root
property string title: ""
default property alias data: sectionContent.data
Layout.fillWidth: true
Layout.topMargin: 4
spacing: 2
ContentSubsectionLabel {
Layout.fillWidth: true
visible: root.title && root.title.length > 0
text: root.title
}
ColumnLayout {
id: sectionContent
Layout.fillWidth: true
spacing: 2
}
}

View file

@ -0,0 +1,10 @@
import QtQuick
import QtQuick.Layouts
import "root:/modules/common/"
import "root:/modules/common/widgets/"
StyledText {
text: "Subsection"
color: Appearance.colors.colSubtext
Layout.leftMargin: 4
}

View file

@ -0,0 +1,53 @@
import "root:/modules/common"
import "root:/modules/common/functions/color_utils.js" as ColorUtils
import QtQuick
import QtQuick.Controls.Material
import QtQuick.Controls
/**
* Material 3 styled TextArea (filled style)
* https://m3.material.io/components/text-fields/overview
* Note: We don't use NativeRendering because it makes the small placeholder text look weird
*/
TextArea {
id: root
Material.theme: Material.System
Material.accent: Appearance.m3colors.m3primary
Material.primary: Appearance.m3colors.m3primary
Material.background: Appearance.m3colors.m3surface
Material.foreground: Appearance.m3colors.m3onSurface
Material.containerStyle: Material.Filled
renderType: Text.QtRendering
selectedTextColor: Appearance.m3colors.m3onSecondaryContainer
selectionColor: Appearance.colors.colSecondaryContainer
placeholderTextColor: Appearance.m3colors.m3outline
background: Rectangle {
implicitHeight: 56
color: Appearance.m3colors.m3surface
topLeftRadius: 4
topRightRadius: 4
Rectangle {
anchors {
left: parent.left
right: parent.right
bottom: parent.bottom
}
height: 1
color: root.focus ? Appearance.m3colors.m3primary :
root.hovered ? Appearance.m3colors.m3outline : Appearance.m3colors.m3outlineVariant
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
}
}
font {
family: Appearance?.font.family.main ?? "sans-serif"
pixelSize: Appearance?.font.pixelSize.small ?? 15
hintingPreference: Font.PreferFullHinting
}
wrapMode: TextEdit.Wrap
}

View file

@ -14,6 +14,12 @@ RippleButton {
parent.expanded = !parent.expanded;
}
buttonRadius: Appearance.rounding.full
rotation: root.parent.expanded ? 0 : -180
Behavior on rotation {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
contentItem: MaterialSymbol {
id: icon
anchors.centerIn: parent

View file

@ -1,65 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "root:/services/"
import "root:/modules/common/"
import "root:/modules/common/widgets/"
ContentPage {
ContentSection {
title: "Policies"
ConfigRow {
ColumnLayout { // Weeb policy
StyledText {
text: "Weeb"
color: Appearance.colors.colSubtext
}
ConfigSelectionArray {
currentValue: ConfigOptions.policies.weeb
configOptionName: "policies.weeb"
onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.weeb", newValue);
}
options: [
{ displayName: "No", value: 0 },
{ displayName: "Yes", value: 1 },
{ displayName: "Closet", value: 2 }
]
}
}
ColumnLayout { // AI policy
StyledText {
text: "AI"
color: Appearance.colors.colSubtext
}
ConfigSelectionArray {
currentValue: ConfigOptions.policies.ai
configOptionName: "policies.ai"
onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.ai", newValue);
}
options: [
{ displayName: "No", value: 0 },
{ displayName: "Yes", value: 1 },
{ displayName: "Local only", value: 2 }
]
}
}
}
}
ContentSection {
title: "Audio"
ConfigSwitch {
text: "Earbang protection"
checked: ConfigOptions.audio.protection.enable
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("audio.protection.enable", checked);
}
StyledToolTip {
content: "Prevents abrupt increments and restricts volume limit"
}
}
}
}

View file

@ -0,0 +1,144 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "root:/services/"
import "root:/modules/common/"
import "root:/modules/common/widgets/"
ContentPage {
forceWidth: true
ContentSection {
title: "Policies"
ConfigRow {
ColumnLayout { // Weeb policy
ContentSubsectionLabel {
text: "Weeb"
}
ConfigSelectionArray {
currentValue: ConfigOptions.policies.weeb
configOptionName: "policies.weeb"
onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.weeb", newValue);
}
options: [
{ displayName: "No", value: 0 },
{ displayName: "Yes", value: 1 },
{ displayName: "Closet", value: 2 }
]
}
}
ColumnLayout { // AI policy
ContentSubsectionLabel {
text: "AI"
}
ConfigSelectionArray {
currentValue: ConfigOptions.policies.ai
configOptionName: "policies.ai"
onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("policies.ai", newValue);
}
options: [
{ displayName: "No", value: 0 },
{ displayName: "Yes", value: 1 },
{ displayName: "Local only", value: 2 }
]
}
}
}
}
ContentSection {
title: "Audio"
ConfigSwitch {
text: "Earbang protection"
checked: ConfigOptions.audio.protection.enable
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("audio.protection.enable", checked);
}
StyledToolTip {
content: "Prevents abrupt increments and restricts volume limit"
}
}
}
ContentSection {
title: "AI"
MaterialTextField {
id: systemPromptField
Layout.fillWidth: true
placeholderText: "System prompt"
text: ConfigOptions.ai.systemPrompt
wrapMode: TextEdit.Wrap
onTextChanged: {
ConfigLoader.setConfigValueAndSave("ai.systemPrompt", text);
}
}
}
ContentSection {
title: "Bar"
ContentSubsection {
title: "Appearance"
ConfigRow {
uniform: true
ConfigSwitch {
text: 'Borderless'
checked: ConfigOptions.bar.borderless
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.borderless", checked);
}
}
ConfigSwitch {
text: 'Show background'
checked: ConfigOptions.bar.showBackground
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.showBackground", checked);
}
StyledToolTip {
content: "Note: turning off can hurt readability"
}
}
}
}
ContentSubsection {
title: "Buttons"
ConfigRow {
uniform: true
ConfigSwitch {
text: "Screen snip"
checked: ConfigOptions.bar.utilButtons.showScreenSnip
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showScreenSnip", checked);
}
}
ConfigSwitch {
text: "Color picker"
checked: ConfigOptions.bar.utilButtons.showColorPicker
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showColorPicker", checked);
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: "Mic toggle"
checked: ConfigOptions.bar.utilButtons.showMicToggle
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showMicToggle", checked);
}
}
ConfigSwitch {
text: "Keyboard toggle"
checked: ConfigOptions.bar.utilButtons.showKeyboardToggle
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.utilButtons.showKeyboardToggle", checked);
}
}
}
}
}
}

View file

@ -1,238 +0,0 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import "root:/services/"
import "root:/modules/common/"
import "root:/modules/common/widgets/"
import "root:/modules/common/functions/color_utils.js" as ColorUtils
import "root:/modules/common/functions/file_utils.js" as FileUtils
ContentPage {
baseWidth: lightDarkButtonGroup.implicitWidth
forceWidth: true
Process {
id: konachanWallProc
property string status: ""
command: ["bash", "-c", FileUtils.trimFileProtocol(`${Directories.config}/quickshell/scripts/colors/random_konachan_wall.sh`)]
stdout: SplitParser {
onRead: data => {
console.log(`Konachan wall proc output: ${data}`);
konachanWallProc.status = data.trim();
}
}
}
ContentSection {
title: "Colors & Wallpaper"
// Light/Dark mode preference
ButtonGroup {
id: lightDarkButtonGroup
Layout.fillWidth: true
LightDarkPreferenceButton {
dark: false
}
LightDarkPreferenceButton {
dark: true
}
}
// Material palette selection
StyledText {
text: "Material palette"
color: Appearance.colors.colSubtext
}
ConfigSelectionArray {
currentValue: ConfigOptions.appearance.palette.type
configOptionName: "appearance.palette.type"
onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("appearance.palette.type", newValue);
}
options: [
{"value": "auto", "displayName": "Auto"},
{"value": "scheme-content", "displayName": "Content"},
{"value": "scheme-expressive", "displayName": "Expressive"},
{"value": "scheme-fidelity", "displayName": "Fidelity"},
{"value": "scheme-fruit-salad", "displayName": "Fruit Salad"},
{"value": "scheme-monochrome", "displayName": "Monochrome"},
{"value": "scheme-neutral", "displayName": "Neutral"},
{"value": "scheme-rainbow", "displayName": "Rainbow"},
{"value": "scheme-tonal-spot", "displayName": "Tonal Spot"}
]
}
// Wallpaper selection
StyledText {
text: "Wallpaper"
color: Appearance.colors.colSubtext
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
RippleButtonWithIcon {
id: rndWallBtn
Layout.alignment: Qt.AlignHCenter
buttonRadius: Appearance.rounding.small
materialIcon: "wallpaper"
mainText: konachanWallProc.running ? "Be patient..." : "Random: Konachan"
onClicked: {
console.log(konachanWallProc.command.join(" "))
konachanWallProc.running = true;
}
StyledToolTip {
content: "Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers"
}
}
RippleButtonWithIcon {
materialIcon: "wallpaper"
StyledToolTip {
content: "Pick wallpaper image on your system"
}
onClicked: {
Quickshell.execDetached(`${Directories.wallpaperSwitchScriptPath}`)
}
mainContentComponent: Component {
RowLayout {
spacing: 10
StyledText {
font.pixelSize: Appearance.font.pixelSize.small
text: "Choose file"
color: Appearance.colors.colOnSecondaryContainer
}
RowLayout {
spacing: 3
KeyboardKey {
key: "Ctrl"
}
KeyboardKey {
key: "󰖳"
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: "+"
}
KeyboardKey {
key: "T"
}
}
}
}
}
}
StyledText {
Layout.alignment: Qt.AlignHCenter
text: "Change any time later with /dark, /light, /img in the launcher"
font.pixelSize: Appearance.font.pixelSize.smaller
color: Appearance.colors.colSubtext
}
}
ContentSection {
title: "Shell style"
ColumnLayout { // Fake screen rounding
StyledText {
text: "Fake screen rounding"
color: Appearance.colors.colSubtext
}
ButtonGroup {
id: fakeScreenRoundingButtonGroup
property int selectedPolicy: ConfigOptions.appearance.fakeScreenRounding
spacing: 2
SelectionGroupButton {
property int value: 0
leftmost: true
buttonText: "No"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
}
}
SelectionGroupButton {
property int value: 1
buttonText: "Yes"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
}
}
SelectionGroupButton {
property int value: 2
rightmost: true
buttonText: "When not fullscreen"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
}
}
}
}
ConfigRow {
ConfigSwitch {
text: "Transparency"
checked: ConfigOptions.appearance.transparency
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("appearance.transparency", checked);
}
StyledToolTip {
content: "Might look ass. Unsupported."
}
}
}
StyledText {
text: "Bar"
color: Appearance.colors.colSubtext
}
ConfigRow {
uniform: true
ConfigSwitch {
text: 'Borderless'
checked: ConfigOptions.bar.borderless
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.borderless", checked);
}
}
ConfigSwitch {
text: 'Show background'
checked: ConfigOptions.bar.showBackground
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("bar.showBackground", checked);
}
StyledToolTip {
content: "Note: turning off can hurt readability"
}
}
}
}
ContentSection {
title: "Shell windows"
spacing: 4
ConfigRow {
uniform: true
ConfigSwitch {
text: "Title bar"
checked: ConfigOptions.windows.showTitlebar
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("windows.showTitlebar", checked);
}
}
ConfigSwitch {
text: "Center title"
checked: ConfigOptions.windows.centerTitle
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("windows.centerTitle", checked);
}
}
}
}
}

View file

@ -0,0 +1,213 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import Quickshell.Hyprland
import "root:/services/"
import "root:/modules/common/"
import "root:/modules/common/widgets/"
import "root:/modules/common/functions/color_utils.js" as ColorUtils
import "root:/modules/common/functions/file_utils.js" as FileUtils
ContentPage {
baseWidth: lightDarkButtonGroup.implicitWidth
forceWidth: true
Process {
id: konachanWallProc
property string status: ""
command: ["bash", "-c", FileUtils.trimFileProtocol(`${Directories.config}/quickshell/scripts/colors/random_konachan_wall.sh`)]
stdout: SplitParser {
onRead: data => {
console.log(`Konachan wall proc output: ${data}`);
konachanWallProc.status = data.trim();
}
}
}
ContentSection {
title: "Colors & Wallpaper"
// Light/Dark mode preference
ButtonGroup {
id: lightDarkButtonGroup
Layout.fillWidth: true
LightDarkPreferenceButton {
dark: false
}
LightDarkPreferenceButton {
dark: true
}
}
// Material palette selection
ContentSubsection {
title: "Material palette"
ConfigSelectionArray {
currentValue: ConfigOptions.appearance.palette.type
configOptionName: "appearance.palette.type"
onSelected: (newValue) => {
ConfigLoader.setConfigValueAndSave("appearance.palette.type", newValue);
}
options: [
{"value": "auto", "displayName": "Auto"},
{"value": "scheme-content", "displayName": "Content"},
{"value": "scheme-expressive", "displayName": "Expressive"},
{"value": "scheme-fidelity", "displayName": "Fidelity"},
{"value": "scheme-fruit-salad", "displayName": "Fruit Salad"},
{"value": "scheme-monochrome", "displayName": "Monochrome"},
{"value": "scheme-neutral", "displayName": "Neutral"},
{"value": "scheme-rainbow", "displayName": "Rainbow"},
{"value": "scheme-tonal-spot", "displayName": "Tonal Spot"}
]
}
}
// Wallpaper selection
ContentSubsection {
title: "Wallpaper"
RowLayout {
Layout.alignment: Qt.AlignHCenter
RippleButtonWithIcon {
id: rndWallBtn
buttonRadius: Appearance.rounding.small
materialIcon: "wallpaper"
mainText: konachanWallProc.running ? "Be patient..." : "Random: Konachan"
onClicked: {
console.log(konachanWallProc.command.join(" "))
konachanWallProc.running = true;
}
StyledToolTip {
content: "Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers"
}
}
RippleButtonWithIcon {
materialIcon: "wallpaper"
StyledToolTip {
content: "Pick wallpaper image on your system"
}
onClicked: {
Quickshell.execDetached(`${Directories.wallpaperSwitchScriptPath}`)
}
mainContentComponent: Component {
RowLayout {
spacing: 10
StyledText {
font.pixelSize: Appearance.font.pixelSize.small
text: "Choose file"
color: Appearance.colors.colOnSecondaryContainer
}
RowLayout {
spacing: 3
KeyboardKey {
key: "Ctrl"
}
KeyboardKey {
key: "󰖳"
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: "+"
}
KeyboardKey {
key: "T"
}
}
}
}
}
}
}
StyledText {
Layout.topMargin: 5
Layout.alignment: Qt.AlignHCenter
text: "Alternatively use /dark, /light, /img in the launcher"
font.pixelSize: Appearance.font.pixelSize.smaller
color: Appearance.colors.colSubtext
}
}
ContentSection {
title: "Decorations & Effects"
ContentSubsection {
title: "Transparency"
ConfigRow {
ConfigSwitch {
text: "Enable"
checked: ConfigOptions.appearance.transparency
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("appearance.transparency", checked);
}
StyledToolTip {
content: "Might look ass. Unsupported."
}
}
}
}
ContentSubsection {
title: "Fake screen rounding"
ButtonGroup {
id: fakeScreenRoundingButtonGroup
property int selectedPolicy: ConfigOptions.appearance.fakeScreenRounding
spacing: 2
SelectionGroupButton {
property int value: 0
leftmost: true
buttonText: "No"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
}
}
SelectionGroupButton {
property int value: 1
buttonText: "Yes"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
}
}
SelectionGroupButton {
property int value: 2
rightmost: true
buttonText: "When not fullscreen"
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
ConfigLoader.setConfigValueAndSave("appearance.fakeScreenRounding", value);
}
}
}
}
ContentSubsection {
title: "Shell windows"
ConfigRow {
uniform: true
ConfigSwitch {
text: "Title bar"
checked: ConfigOptions.windows.showTitlebar
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("windows.showTitlebar", checked);
}
}
ConfigSwitch {
text: "Center title"
checked: ConfigOptions.windows.centerTitle
onCheckedChanged: {
ConfigLoader.setConfigValueAndSave("windows.centerTitle", checked);
}
}
}
}
}
}

View file

@ -30,12 +30,12 @@ ApplicationWindow {
{
name: "Style",
icon: "palette",
component: "modules/settings/Style.qml"
component: "modules/settings/StyleConfig.qml"
},
{
name: "Behavior",
name: "General",
icon: "settings",
component: "modules/settings/BehaviorConfig.qml"
component: "modules/settings/GeneralConfig.qml"
},
{
name: "About",
@ -66,6 +66,28 @@ ApplicationWindow {
margins: contentPadding
}
Keys.onPressed: (event) => {
console.log(`Key pressed: ${event.key}, Modifiers: ${event.modifiers}`);
if (event.modifiers === Qt.ControlModifier) {
if (event.key === Qt.Key_PageDown) {
root.currentPage = Math.min(root.currentPage + 1, root.pages.length - 1)
event.accepted = true;
}
else if (event.key === Qt.Key_PageUp) {
root.currentPage = Math.max(root.currentPage - 1, 0)
event.accepted = true;
}
else if (event.key === Qt.Key_Tab) {
root.currentPage = (root.currentPage + 1) % root.pages.length;
event.accepted = true;
}
else if (event.key === Qt.Key_Backtab) {
root.currentPage = (root.currentPage - 1 + root.pages.length) % root.pages.length;
event.accepted = true;
}
}
}
Item { // Titlebar
visible: ConfigOptions?.windows.showTitlebar
Layout.fillWidth: true
@ -125,7 +147,9 @@ ApplicationWindow {
spacing: 10
expanded: root.width > 900
NavigationRailExpandButton {}
NavigationRailExpandButton {
focus: root.visible
}
FloatingActionButton {
id: fab
@ -180,7 +204,8 @@ ApplicationWindow {
target: root
function onCurrentPageChanged() {
if (pageLoader.sourceComponent !== root.pages[root.currentPage].component) {
switchAnim.restart();
switchAnim.complete();
switchAnim.start();
}
}
}
@ -193,7 +218,7 @@ ApplicationWindow {
properties: "opacity"
from: 1
to: 0
duration: 150
duration: 0
easing.type: Appearance.animation.elementMoveExit.type
easing.bezierCurve: Appearance.animationCurves.emphasizedFirstHalf
}
@ -207,7 +232,7 @@ ApplicationWindow {
properties: "opacity"
from: 0
to: 1
duration: 250
duration: 0
easing.type: Appearance.animation.elementMoveEnter.type
easing.bezierCurve: Appearance.animationCurves.emphasizedLastHalf
}

View file

@ -202,9 +202,8 @@ ApplicationWindow {
ConfigRow {
ColumnLayout { // Weeb policy
StyledText {
ContentSubsectionLabel {
text: "Weeb"
color: Appearance.colors.colSubtext
}
ConfigSelectionArray {
currentValue: ConfigOptions.policies.weeb
@ -221,9 +220,8 @@ ApplicationWindow {
}
ColumnLayout { // AI policy
StyledText {
ContentSubsectionLabel {
text: "AI"
color: Appearance.colors.colSubtext
}
ConfigSelectionArray {
currentValue: ConfigOptions.policies.ai