mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
- Thanks Google for Material 3 Expressive stuffs - Thanks Caelestia shell for pushing qml limits to showcase the blueprint
491 lines
21 KiB
QML
491 lines
21 KiB
QML
import QtQuick
|
|
import qs.Common
|
|
import qs.Widgets
|
|
import qs.Modules.Settings.Widgets
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property var cachedFontFamilies: []
|
|
property var cachedMonoFamilies: []
|
|
property bool fontsEnumerated: false
|
|
|
|
function enumerateFonts() {
|
|
var fonts = [];
|
|
var availableFonts = Qt.fontFamilies();
|
|
|
|
for (var i = 0; i < availableFonts.length; i++) {
|
|
var fontName = availableFonts[i];
|
|
if (fontName.startsWith("."))
|
|
continue;
|
|
fonts.push(fontName);
|
|
}
|
|
fonts.sort();
|
|
fonts.unshift("Default");
|
|
cachedFontFamilies = fonts;
|
|
cachedMonoFamilies = fonts;
|
|
}
|
|
|
|
Timer {
|
|
id: fontEnumerationTimer
|
|
interval: 50
|
|
running: false
|
|
onTriggered: {
|
|
if (fontsEnumerated)
|
|
return;
|
|
enumerateFonts();
|
|
fontsEnumerated = true;
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
fontEnumerationTimer.start();
|
|
}
|
|
|
|
DankFlickable {
|
|
anchors.fill: parent
|
|
clip: true
|
|
contentHeight: mainColumn.height + Theme.spacingXL
|
|
contentWidth: width
|
|
|
|
Column {
|
|
id: mainColumn
|
|
topPadding: 4
|
|
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
spacing: Theme.spacingXL
|
|
|
|
SettingsCard {
|
|
tab: "typography"
|
|
tags: ["font", "family", "text", "typography"]
|
|
title: I18n.tr("Typography")
|
|
settingKey: "typography"
|
|
iconName: "text_fields"
|
|
|
|
SettingsDropdownRow {
|
|
tab: "typography"
|
|
tags: ["font", "family", "normal", "text"]
|
|
settingKey: "fontFamily"
|
|
text: I18n.tr("Normal Font")
|
|
description: I18n.tr("Select the font family for UI text")
|
|
options: root.fontsEnumerated ? root.cachedFontFamilies : ["Default"]
|
|
currentValue: SettingsData.fontFamily === Theme.defaultFontFamily ? "Default" : (SettingsData.fontFamily || "Default")
|
|
enableFuzzySearch: true
|
|
popupWidthOffset: 100
|
|
maxPopupHeight: 400
|
|
onValueChanged: value => {
|
|
if (value === "Default")
|
|
SettingsData.set("fontFamily", Theme.defaultFontFamily);
|
|
else
|
|
SettingsData.set("fontFamily", value);
|
|
}
|
|
}
|
|
|
|
SettingsDropdownRow {
|
|
tab: "typography"
|
|
tags: ["font", "monospace", "code", "terminal"]
|
|
settingKey: "monoFontFamily"
|
|
text: I18n.tr("Monospace Font")
|
|
description: I18n.tr("Select monospace font for process list and technical displays")
|
|
options: root.fontsEnumerated ? root.cachedMonoFamilies : ["Default"]
|
|
currentValue: SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily ? "Default" : (SettingsData.monoFontFamily || "Default")
|
|
enableFuzzySearch: true
|
|
popupWidthOffset: 100
|
|
maxPopupHeight: 400
|
|
onValueChanged: value => {
|
|
if (value === "Default")
|
|
SettingsData.set("monoFontFamily", SettingsData.defaultMonoFontFamily);
|
|
else
|
|
SettingsData.set("monoFontFamily", value);
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.15
|
|
}
|
|
|
|
SettingsDropdownRow {
|
|
tab: "typography"
|
|
tags: ["font", "weight", "bold", "light"]
|
|
settingKey: "fontWeight"
|
|
text: I18n.tr("Font Weight")
|
|
description: I18n.tr("Select font weight for UI text")
|
|
options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"]
|
|
currentValue: {
|
|
switch (SettingsData.fontWeight) {
|
|
case Font.Thin:
|
|
return "Thin";
|
|
case Font.ExtraLight:
|
|
return "Extra Light";
|
|
case Font.Light:
|
|
return "Light";
|
|
case Font.Normal:
|
|
return "Regular";
|
|
case Font.Medium:
|
|
return "Medium";
|
|
case Font.DemiBold:
|
|
return "Demi Bold";
|
|
case Font.Bold:
|
|
return "Bold";
|
|
case Font.ExtraBold:
|
|
return "Extra Bold";
|
|
case Font.Black:
|
|
return "Black";
|
|
default:
|
|
return "Regular";
|
|
}
|
|
}
|
|
onValueChanged: value => {
|
|
var weight;
|
|
switch (value) {
|
|
case "Thin":
|
|
weight = Font.Thin;
|
|
break;
|
|
case "Extra Light":
|
|
weight = Font.ExtraLight;
|
|
break;
|
|
case "Light":
|
|
weight = Font.Light;
|
|
break;
|
|
case "Regular":
|
|
weight = Font.Normal;
|
|
break;
|
|
case "Medium":
|
|
weight = Font.Medium;
|
|
break;
|
|
case "Demi Bold":
|
|
weight = Font.DemiBold;
|
|
break;
|
|
case "Bold":
|
|
weight = Font.Bold;
|
|
break;
|
|
case "Extra Bold":
|
|
weight = Font.ExtraBold;
|
|
break;
|
|
case "Black":
|
|
weight = Font.Black;
|
|
break;
|
|
default:
|
|
weight = Font.Normal;
|
|
break;
|
|
}
|
|
SettingsData.set("fontWeight", weight);
|
|
}
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
tab: "typography"
|
|
tags: ["font", "scale", "size", "zoom"]
|
|
settingKey: "fontScale"
|
|
text: I18n.tr("Font Scale")
|
|
description: I18n.tr("Scale all font sizes throughout the shell")
|
|
minimum: 75
|
|
maximum: 150
|
|
value: Math.round(SettingsData.fontScale * 100)
|
|
unit: "%"
|
|
defaultValue: 100
|
|
onSliderValueChanged: newValue => SettingsData.set("fontScale", newValue / 100)
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
tab: "typography"
|
|
tags: ["animation", "speed", "motion", "duration"]
|
|
title: I18n.tr("Animation Speed")
|
|
settingKey: "animationSpeed"
|
|
iconName: "animation"
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: animationSpeedGroup.implicitHeight
|
|
clip: true
|
|
|
|
DankButtonGroup {
|
|
id: animationSpeedGroup
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
|
minButtonWidth: parent.width < 480 ? 44 : 64
|
|
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
|
model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")]
|
|
selectionMode: "single"
|
|
currentIndex: SettingsData.animationSpeed
|
|
onSelectionChanged: (index, selected) => {
|
|
if (!selected)
|
|
return;
|
|
SettingsData.set("animationSpeed", index);
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onAnimationSpeedChanged() {
|
|
animationSpeedGroup.currentIndex = SettingsData.animationSpeed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.15
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
id: durationSlider
|
|
tab: "typography"
|
|
tags: ["animation", "duration", "custom", "speed"]
|
|
settingKey: "customAnimationDuration"
|
|
text: I18n.tr("Animation Duration")
|
|
description: I18n.tr("Globally scale all animation durations")
|
|
minimum: 0
|
|
maximum: 1000
|
|
value: Theme.currentAnimationBaseDuration
|
|
unit: "ms"
|
|
defaultValue: 200
|
|
onSliderValueChanged: newValue => {
|
|
SettingsData.set("animationSpeed", SettingsData.AnimationSpeed.Custom);
|
|
SettingsData.set("customAnimationDuration", newValue);
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onAnimationSpeedChanged() {
|
|
if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom)
|
|
return;
|
|
durationSlider.value = Theme.currentAnimationBaseDuration;
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: Theme
|
|
function onCurrentAnimationBaseDurationChanged() {
|
|
if (SettingsData.animationSpeed === SettingsData.AnimationSpeed.Custom)
|
|
return;
|
|
durationSlider.value = Theme.currentAnimationBaseDuration;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.15
|
|
}
|
|
|
|
SettingsToggleRow {
|
|
tab: "typography"
|
|
tags: ["animation", "sync", "popout", "modal", "global"]
|
|
settingKey: "syncComponentAnimationSpeeds"
|
|
text: I18n.tr("Sync Popouts & Modals")
|
|
description: I18n.tr("Popouts and Modals follow global Animation Speed (disable to customize independently)")
|
|
checked: SettingsData.syncComponentAnimationSpeeds
|
|
onToggled: checked => SettingsData.set("syncComponentAnimationSpeeds", checked)
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onSyncComponentAnimationSpeedsChanged() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
tab: "typography"
|
|
tags: ["animation", "speed", "motion", "duration", "popout", "sync"]
|
|
title: I18n.tr("%1 Animation Speed").arg(I18n.tr("Popouts"))
|
|
settingKey: "popoutAnimationSpeed"
|
|
iconName: "open_in_new"
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: popoutSpeedGroup.implicitHeight
|
|
clip: true
|
|
|
|
DankButtonGroup {
|
|
id: popoutSpeedGroup
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
|
minButtonWidth: parent.width < 480 ? 44 : 64
|
|
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
|
model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")]
|
|
selectionMode: "single"
|
|
currentIndex: SettingsData.popoutAnimationSpeed
|
|
onSelectionChanged: (index, selected) => {
|
|
if (!selected)
|
|
return;
|
|
if (SettingsData.syncComponentAnimationSpeeds)
|
|
SettingsData.set("syncComponentAnimationSpeeds", false);
|
|
SettingsData.set("popoutAnimationSpeed", index);
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onPopoutAnimationSpeedChanged() {
|
|
popoutSpeedGroup.currentIndex = SettingsData.popoutAnimationSpeed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.15
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
id: popoutDurationSlider
|
|
tab: "typography"
|
|
tags: ["animation", "duration", "custom", "speed", "popout"]
|
|
settingKey: "popoutCustomAnimationDuration"
|
|
text: I18n.tr("Custom Duration")
|
|
description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Popouts"))
|
|
minimum: 0
|
|
maximum: 1000
|
|
value: Theme.popoutAnimationDuration
|
|
unit: "ms"
|
|
defaultValue: 150
|
|
onSliderValueChanged: newValue => {
|
|
if (SettingsData.syncComponentAnimationSpeeds)
|
|
SettingsData.set("syncComponentAnimationSpeeds", false);
|
|
SettingsData.set("popoutAnimationSpeed", SettingsData.AnimationSpeed.Custom);
|
|
SettingsData.set("popoutCustomAnimationDuration", newValue);
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onPopoutAnimationSpeedChanged() {
|
|
if (SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom)
|
|
return;
|
|
popoutDurationSlider.value = Theme.popoutAnimationDuration;
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: Theme
|
|
function onPopoutAnimationDurationChanged() {
|
|
if (!SettingsData.syncComponentAnimationSpeeds && SettingsData.popoutAnimationSpeed === SettingsData.AnimationSpeed.Custom)
|
|
return;
|
|
popoutDurationSlider.value = Theme.popoutAnimationDuration;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
tab: "typography"
|
|
tags: ["animation", "speed", "motion", "duration", "modal", "sync"]
|
|
title: I18n.tr("%1 Animation Speed").arg(I18n.tr("Modals"))
|
|
settingKey: "modalAnimationSpeed"
|
|
iconName: "web_asset"
|
|
|
|
Item {
|
|
width: parent.width
|
|
height: modalSpeedGroup.implicitHeight
|
|
clip: true
|
|
|
|
DankButtonGroup {
|
|
id: modalSpeedGroup
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
|
minButtonWidth: parent.width < 480 ? 44 : 64
|
|
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
|
model: [I18n.tr("None"), I18n.tr("Short"), I18n.tr("Medium"), I18n.tr("Long"), I18n.tr("Custom")]
|
|
selectionMode: "single"
|
|
currentIndex: SettingsData.modalAnimationSpeed
|
|
onSelectionChanged: (index, selected) => {
|
|
if (!selected)
|
|
return;
|
|
if (SettingsData.syncComponentAnimationSpeeds)
|
|
SettingsData.set("syncComponentAnimationSpeeds", false);
|
|
SettingsData.set("modalAnimationSpeed", index);
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onModalAnimationSpeedChanged() {
|
|
modalSpeedGroup.currentIndex = SettingsData.modalAnimationSpeed;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: 1
|
|
color: Theme.outline
|
|
opacity: 0.15
|
|
}
|
|
|
|
SettingsSliderRow {
|
|
id: modalDurationSlider
|
|
tab: "typography"
|
|
tags: ["animation", "duration", "custom", "speed", "modal"]
|
|
settingKey: "modalCustomAnimationDuration"
|
|
text: I18n.tr("Custom Duration")
|
|
description: I18n.tr("%1 custom animation duration").arg(I18n.tr("Modals"))
|
|
minimum: 0
|
|
maximum: 1000
|
|
value: Theme.modalAnimationDuration
|
|
unit: "ms"
|
|
defaultValue: 150
|
|
onSliderValueChanged: newValue => {
|
|
if (SettingsData.syncComponentAnimationSpeeds)
|
|
SettingsData.set("syncComponentAnimationSpeeds", false);
|
|
SettingsData.set("modalAnimationSpeed", SettingsData.AnimationSpeed.Custom);
|
|
SettingsData.set("modalCustomAnimationDuration", newValue);
|
|
}
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onModalAnimationSpeedChanged() {
|
|
if (SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom)
|
|
return;
|
|
modalDurationSlider.value = Theme.modalAnimationDuration;
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: Theme
|
|
function onModalAnimationDurationChanged() {
|
|
if (!SettingsData.syncComponentAnimationSpeeds && SettingsData.modalAnimationSpeed === SettingsData.AnimationSpeed.Custom)
|
|
return;
|
|
modalDurationSlider.value = Theme.modalAnimationDuration;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SettingsCard {
|
|
tab: "typography"
|
|
tags: ["animation", "ripple", "effect", "material", "feedback"]
|
|
title: I18n.tr("Ripple Effects")
|
|
settingKey: "enableRippleEffects"
|
|
iconName: "radio_button_unchecked"
|
|
|
|
SettingsToggleRow {
|
|
tab: "typography"
|
|
tags: ["animation", "ripple", "effect", "material", "click"]
|
|
settingKey: "enableRippleEffects"
|
|
text: I18n.tr("Enable Ripple Effects")
|
|
description: I18n.tr("Show Material Design ripple animations on interactive elements")
|
|
checked: SettingsData.enableRippleEffects ?? true
|
|
onToggled: newValue => SettingsData.set("enableRippleEffects", newValue)
|
|
|
|
Connections {
|
|
target: SettingsData
|
|
function onEnableRippleEffectsChanged() {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|