This commit is contained in:
2026-03-25 18:19:37 +01:00
parent 24a14b41d7
commit 3114ecb690
30 changed files with 1787 additions and 12 deletions
+14 -1
View File
@@ -14,7 +14,20 @@ Item {
required property Item content
implicitHeight: clayout.contentHeight + Appearance.padding.smaller * 2
signal settingSelected(string category, string section, string settingName)
// Function to select category by key
function selectCategory(categoryKey: string) {
for (let i = 0; i < listModel.count; i++) {
if (listModel.get(i).key === categoryKey) {
clayout.currentIndex = i;
root.content.currentCategory = categoryKey;
return;
}
}
}
implicitHeight: searchBar.implicitHeight + Appearance.spacing.smaller + clayout.contentHeight + Appearance.padding.smaller * 2
implicitWidth: clayout.contentWidth + Appearance.padding.smaller * 2
ListModel {
@@ -5,6 +5,8 @@ SettingsPage {
id: root
SettingsSection {
sectionId: "Scale"
SettingsHeader {
name: "Scale"
}
@@ -58,6 +60,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Fonts"
SettingsHeader {
name: "Fonts"
}
@@ -97,6 +101,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Animation"
SettingsHeader {
name: "Animation"
}
@@ -122,6 +128,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Transparency"
SettingsHeader {
name: "Transparency"
}
@@ -5,6 +5,8 @@ SettingsPage {
id: root
SettingsSection {
sectionId: "Wallpaper"
SettingsHeader {
name: "Wallpaper"
}
+8
View File
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Bar"
SettingsHeader {
name: "Bar"
}
@@ -45,6 +47,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Popouts"
SettingsHeader {
name: "Popouts"
}
@@ -111,6 +115,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Entries"
SettingsHeader {
name: "Entries"
}
@@ -123,6 +129,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Dock"
SettingsHeader {
name: "Dock"
}
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Dashboard"
SettingsHeader {
name: "Dashboard"
}
@@ -47,6 +49,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Performance"
SettingsHeader {
name: "Performance"
}
@@ -104,6 +108,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Layout Sizes"
SettingsHeader {
name: "Layout Sizes"
}
+5
View File
@@ -16,6 +16,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "General"
SettingsHeader {
name: "General"
}
@@ -46,6 +48,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Color"
SettingsHeader {
name: "Color"
}
@@ -175,6 +179,7 @@ SettingsPage {
}
SettingsSection {
sectionId: "Default Apps"
z: -1
SettingsHeader {
+8
View File
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Launcher"
SettingsHeader {
name: "Launcher"
}
@@ -44,6 +46,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Fuzzy Search"
SettingsHeader {
name: "Fuzzy Search"
}
@@ -92,6 +96,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Sizes"
SettingsHeader {
name: "Sizes"
}
@@ -135,6 +141,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Actions"
SettingsHeader {
name: "Actions"
}
@@ -6,6 +6,8 @@ SettingsPage {
id: root
SettingsSection {
sectionId: "Lockscreen"
SettingsHeader {
name: "Lockscreen"
}
@@ -84,6 +86,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Idle"
Idle {
}
}
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Notifications"
SettingsHeader {
name: "Notifications"
}
@@ -78,6 +80,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Sizes"
SettingsHeader {
name: "Sizes"
}
+4
View File
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "On Screen Display"
SettingsHeader {
name: "On Screen Display"
}
@@ -53,6 +55,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Sizes"
SettingsHeader {
name: "Sizes"
}
+4
View File
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Services"
SettingsHeader {
name: "Services"
}
@@ -51,6 +53,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Media"
SettingsHeader {
name: "Media"
}
+2
View File
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Sidebar"
SettingsHeader {
name: "Sidebar"
}
@@ -3,6 +3,8 @@ import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Utilities"
SettingsHeader {
name: "Utilities"
}
@@ -45,6 +47,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "Toasts"
SettingsHeader {
name: "Toasts"
}
@@ -147,6 +151,8 @@ SettingsPage {
}
SettingsSection {
sectionId: "VPN"
SettingsHeader {
name: "VPN"
}
+44 -2
View File
@@ -14,12 +14,35 @@ Item {
property string currentCategory: "general"
readonly property real nonAnimHeight: Math.floor(screen.height / 1.5) + viewWrapper.anchors.margins * 2
readonly property real nonAnimWidth: view.implicitWidth + Math.floor(screen.width / 2) + viewWrapper.anchors.margins * 2
property string pendingSection: ""
property string pendingSetting: ""
required property ShellScreen screen
required property PersistentProperties visibilities
function scrollToSetting(section: string, settingName: string) {
// Wait for the StackView transition to complete, then scroll
root.pendingSection = section;
root.pendingSetting = settingName;
scrollTimer.restart();
}
implicitHeight: nonAnimHeight
implicitWidth: nonAnimWidth
Timer {
id: scrollTimer
interval: 50
onTriggered: {
if (root.pendingSection && stack.currentItem) {
stack.currentItem.scrollToSectionAndHighlight(root.pendingSection, root.pendingSetting);
root.pendingSection = "";
root.pendingSetting = "";
}
}
}
Connections {
function onCurrentCategoryChanged() {
stack.pop();
@@ -59,12 +82,26 @@ Item {
anchors.margins: Appearance.padding.smaller
radius: Appearance.rounding.large - Appearance.padding.smaller
SettingsSearch {
id: searchBar
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
onSettingSelected: (category, section, settingName) => {
root.selectCategory(category);
root.settingSelected(category, section, settingName);
}
}
Item {
id: view
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.top: parent.top
anchors.top: searchBar.bottom
anchors.topMargin: Appearance.spacing.smaller
implicitWidth: layout.implicitWidth
Categories {
@@ -72,6 +109,10 @@ Item {
anchors.fill: parent
content: root
onSettingSelected: (category, section, settingName) => {
root.scrollToSetting(section, settingName);
}
}
}
@@ -82,7 +123,8 @@ Item {
anchors.left: view.right
anchors.leftMargin: Appearance.spacing.smaller
anchors.right: parent.right
anchors.top: parent.top
anchors.top: searchBar.bottom
anchors.topMargin: Appearance.spacing.smaller
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.normal
@@ -4,10 +4,12 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
ColumnLayout {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property string setting
@@ -45,6 +47,22 @@ ColumnLayout {
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: root.implicitHeight
Layout.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
z: -1
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
@@ -4,10 +4,12 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
ColumnLayout {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property string setting
@@ -41,6 +43,22 @@ ColumnLayout {
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: root.implicitHeight
Layout.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
z: -1
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
CustomText {
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
@@ -6,6 +6,7 @@ import QtQuick.Layouts
import QtQml.Models
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
@@ -19,6 +20,7 @@ Item {
property var draggedModelData: null
property string draggedUid: ""
property bool dropAnimating: false
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
property var pendingCommitEntries: []
@@ -231,6 +233,21 @@ Item {
Component.onCompleted: root.rebuildVisualEntries()
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
z: -1
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
ParallelAnimation {
id: settleAnim
@@ -2,10 +2,12 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property list<string> settings
@@ -33,6 +35,20 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
@@ -2,10 +2,12 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property string setting
@@ -22,6 +24,20 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
@@ -2,16 +2,32 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property string value
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
+18 -2
View File
@@ -2,20 +2,36 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
property real max: Infinity
property real min: -Infinity
required property string name
required property var object
required property string setting
property real max: Infinity
property real min: -Infinity
property real step: 1
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
@@ -2,10 +2,12 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property list<string> settings
@@ -33,6 +35,20 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
@@ -2,18 +2,34 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
property string addLabel: qsTr("Add entry")
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property string setting
property string addLabel: qsTr("Add entry")
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
ColumnLayout {
id: layout
@@ -2,10 +2,12 @@ import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Config
import qs.Helpers
Item {
id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property string setting
@@ -13,6 +15,20 @@ Item {
Layout.fillWidth: true
Layout.preferredHeight: row.implicitHeight + Appearance.padding.smaller * 2
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
@@ -9,6 +9,24 @@ CustomFlickable {
default property alias contentData: clayout.data
// Find and scroll to a section by its sectionId, then highlight a specific setting
function scrollToSectionAndHighlight(sectionId: string, settingName: string) {
// Find the section with matching sectionId
for (let i = 0; i < clayout.children.length; i++) {
const section = clayout.children[i];
if (section.sectionId === sectionId) {
// Scroll to the section with some padding
const targetY = section.y - Appearance.padding.normal;
contentY = Math.max(0, Math.min(targetY, contentHeight - height));
// Use the singleton to highlight the setting
SettingsHighlight.highlight(settingName);
return true;
}
}
return false;
}
contentHeight: clayout.implicitHeight
TapHandler {
@@ -8,6 +8,7 @@ CustomRect {
default property alias contentData: layout.data
property real contentPadding: Appearance.padding.large
property string sectionId: ""
Layout.fillWidth: true
Layout.preferredHeight: layout.implicitHeight + contentPadding * 2
File diff suppressed because it is too large Load Diff
+310
View File
@@ -0,0 +1,310 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import qs.Components
import qs.Config
import "../../scripts/fuzzysort.js" as Fuzzy
import "./SettingsIndex.mjs" as SettingsIndex
Item {
id: root
property alias text: searchField.text
signal settingSelected(string category, string section, string settingName)
function close() {
searchField.text = "";
searchField.focus = false;
popup.close();
}
function search(query) {
resultsModel.clear();
if (!query || query.trim() === "") {
popup.close();
return;
}
const results = SettingsIndex.searchSettings(query, Fuzzy);
for (const result of results.slice(0, 10)) {
resultsModel.append({
name: result.name,
category: result.category,
categoryName: result.categoryName,
section: result.section,
matchType: result.matchType
});
}
if (resultsModel.count > 0) {
popup.open();
} else {
popup.close();
}
}
implicitHeight: searchContainer.implicitHeight
implicitWidth: 200
ListModel {
id: resultsModel
}
CustomRect {
id: searchContainer
anchors.fill: parent
color: DynamicColors.tPalette.m3surfaceContainerHigh
implicitHeight: searchRow.implicitHeight + Appearance.padding.small * 2
radius: Appearance.rounding.full
RowLayout {
id: searchRow
anchors.fill: parent
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.small
spacing: Appearance.spacing.small
MaterialIcon {
Layout.alignment: Qt.AlignVCenter
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.larger
text: "search"
}
CustomTextField {
id: searchField
Layout.alignment: Qt.AlignVCenter
Layout.fillWidth: true
font.pointSize: Appearance.font.size.small
placeholderText: qsTr("Search settings...")
Keys.onDownPressed: {
if (popup.visible && resultsList.count > 0) {
resultsList.currentIndex = Math.min(resultsList.currentIndex + 1, resultsList.count - 1);
}
}
Keys.onEscapePressed: {
root.close();
}
Keys.onReturnPressed: {
if (popup.visible && resultsList.currentIndex >= 0) {
const item = resultsModel.get(resultsList.currentIndex);
root.settingSelected(item.category, item.section, item.name);
root.close();
}
}
Keys.onUpPressed: {
if (popup.visible && resultsList.count > 0) {
resultsList.currentIndex = Math.max(resultsList.currentIndex - 1, 0);
}
}
onTextChanged: {
searchTimer.restart();
}
}
// Clear button
IconButton {
Layout.alignment: Qt.AlignVCenter
font.pointSize: Appearance.font.size.larger
icon: "close"
opacity: searchField.text.length > 0 ? 1 : 0
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.small
}
}
onClicked: {
root.close();
}
}
}
}
// Debounce timer for search
Timer {
id: searchTimer
interval: 150
onTriggered: root.search(searchField.text)
}
// Results dropdown
Popup {
id: popup
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
implicitHeight: Math.min(resultsList.contentHeight + Appearance.padding.small * 2 + 10, (contentItem.view.delegate.implicitHeight + Appearance.spacing.smaller) * 5 - Appearance.spacing.smaller + 10)
implicitWidth: root.width + Appearance.padding.small * 2
modal: false
padding: 0
x: root.width / 2 - popup.width / 2
y: searchContainer.height + Appearance.spacing.small
background: Item {
}
contentItem: Item {
property alias view: resultsList
Elevation {
id: popupShadow
anchors.centerIn: parent
height: popup.implicitHeight - 10
level: 2
radius: Appearance.rounding.normal
width: popup.implicitWidth - 10
CustomRect {
anchors.fill: parent
color: DynamicColors.palette.m3surfaceContainer
radius: Appearance.rounding.normal
CustomListView {
id: resultsList
anchors.fill: parent
anchors.margins: Appearance.padding.small
clip: true
currentIndex: 0
highlightFollowsCurrentItem: false
highlightRangeMode: ListView.ApplyRange
model: resultsModel
preferredHighlightBegin: 0
preferredHighlightEnd: height
spacing: Appearance.spacing.smaller
delegate: SearchResultItem {
required property string category
required property string categoryName
required property int index
required property string matchType
required property string name
required property string section
highlighted: index === resultsList.currentIndex
width: resultsList.width
onClicked: {
root.settingSelected(category, section, name);
root.close();
}
}
highlight: CustomRect {
color: DynamicColors.palette.m3primary
implicitHeight: resultsList.currentItem?.implicitHeight ?? 0
implicitWidth: resultsList.width
radius: Appearance.rounding.normal - Appearance.padding.smaller
y: resultsList.currentItem?.y ?? 0
Behavior on y {
Anim {
duration: Appearance.anim.durations.small
easing.bezierCurve: Appearance.anim.curves.expressiveEffects
}
}
}
}
}
}
}
enter: Transition {
Anim {
duration: Appearance.anim.durations.small
from: 0
property: "opacity"
to: 1
}
Anim {
duration: Appearance.anim.durations.small
from: 0.95
property: "scale"
to: 1.0
}
}
exit: Transition {
Anim {
duration: Appearance.anim.durations.smaller
from: 1
property: "opacity"
to: 0
}
}
}
// Search result item component
component SearchResultItem: CustomRect {
id: resultItem
property bool highlighted: false
signal clicked
implicitHeight: resultLayout.implicitHeight + Appearance.padding.small * 2
radius: Appearance.rounding.small
ColumnLayout {
id: resultLayout
anchors.fill: parent
anchors.margins: Appearance.padding.small
spacing: 2
// Setting name
CustomText {
Layout.fillWidth: true
color: highlighted ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurface
elide: Text.ElideRight
font.pointSize: Appearance.font.size.small
font.weight: Font.Medium
text: resultItem.name
}
// Category and section path
RowLayout {
Layout.fillWidth: true
spacing: Appearance.spacing.smaller
CustomText {
color: highlighted ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.smaller
opacity: 0.8
text: resultItem.categoryName
}
CustomText {
color: highlighted ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.smaller
opacity: 0.6
text: ""
}
CustomText {
Layout.fillWidth: true
color: highlighted ? DynamicColors.palette.m3onPrimary : DynamicColors.palette.m3onSurfaceVariant
elide: Text.ElideRight
font.pointSize: Appearance.font.size.smaller
opacity: 0.8
text: resultItem.section
}
}
}
StateLayer {
onClicked: resultItem.clicked()
}
}
}