mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-23 03:34:01 -04:00
greeting: redesign welcome page & changelog page
+ enable changelog
This commit is contained in:
@@ -877,7 +877,7 @@ func checkWindowManagers() []checkResult {
|
||||
results = append(results, checkAqueousConfigHelper())
|
||||
}
|
||||
|
||||
if utils.CommandExists("mango") {
|
||||
if os.Getenv("MANGO_INSTANCE_SIGNATURE") != "" {
|
||||
results = append(results, checkMangoConfig(mangoconf.Dir(), mangoconf.Detect())...)
|
||||
}
|
||||
|
||||
|
||||
@@ -293,6 +293,12 @@ func (r *Registry) resetLegacyCache() {
|
||||
// declaration order (first occurrence of an ID wins). A failing registry is
|
||||
// reported in the joined error but does not block the others.
|
||||
func (r *Registry) Update() error {
|
||||
unlock, err := registries.LockCache()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
r.resetLegacyCache()
|
||||
r.plugins = []Plugin{}
|
||||
seen := make(map[string]struct{})
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package registries
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
||||
)
|
||||
|
||||
// flock is per open file, so concurrent goroutines contend like separate processes.
|
||||
func LockCache() (unlock func(), err error) {
|
||||
dir := filepath.Join(utils.RuntimeDir(), "dms")
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
return nil, fmt.Errorf("create registry lock dir: %w", err)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(filepath.Join(dir, "registry.lock"), os.O_CREATE|os.O_RDWR, 0o600)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open registry lock: %w", err)
|
||||
}
|
||||
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("acquire registry lock: %w", err)
|
||||
}
|
||||
return func() {
|
||||
_ = syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
|
||||
f.Close()
|
||||
}, nil
|
||||
}
|
||||
@@ -318,6 +318,12 @@ func (r *Registry) resetLegacyCache() {
|
||||
// declaration order (first occurrence of an ID wins). A failing registry is
|
||||
// reported in the joined error but does not block the others.
|
||||
func (r *Registry) Update() error {
|
||||
unlock, err := registries.LockCache()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unlock()
|
||||
|
||||
r.resetLegacyCache()
|
||||
r.themes = []Theme{}
|
||||
seen := make(map[string]struct{})
|
||||
|
||||
+1
-1
Submodule dank-qml-common updated: 51978d3ba6...0166a116f7
Generated
+3
-3
@@ -3,11 +3,11 @@
|
||||
"dank-qml-common": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1792374447,
|
||||
"narHash": "sha256-FlzldJJuGPxyb6IHnzYLi8HQE1Yg222UnY0KcKnKGik=",
|
||||
"lastModified": 1792424555,
|
||||
"narHash": "sha256-V1RZ9krNkeXzvyAC8OoGthhq5zsxWKUWq7Qwnpl7awo=",
|
||||
"owner": "AvengeMedia",
|
||||
"repo": "dank-qml-common",
|
||||
"rev": "51978d3ba6be3138ee39bb0c7f07e156a82805b6",
|
||||
"rev": "0166a116f7c9739008b202eee3dfef5bf76d4f0f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -1379,6 +1379,11 @@ Item {
|
||||
Component.onCompleted: show()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (ChangelogService.shouldShowChangelog)
|
||||
active = true;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ChangelogService
|
||||
function onChangelogRequested() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.DCommon.Widgets
|
||||
@@ -9,296 +10,315 @@ import qs.Modules.Settings.Widgets
|
||||
Column {
|
||||
id: root
|
||||
|
||||
readonly property real logoSize: Math.round(Theme.iconSize * 2.8)
|
||||
readonly property real badgeHeight: Math.round(Theme.fontSizeSmall * 1.7)
|
||||
readonly property string releaseNotesUrl: Site.web + "/blog/v1-6-release"
|
||||
readonly property string screenshotDocsUrl: Site.docs + "/dankmaterialshell/cli-screenshot"
|
||||
readonly property string pluginDocsUrl: Site.docs + "/dms/plugin-development"
|
||||
readonly property string compositorDocsUrl: Site.docs + "/dms/compositors"
|
||||
|
||||
topPadding: Theme.spacingL
|
||||
readonly property var features: [
|
||||
{
|
||||
"icon": "palette",
|
||||
"shape": "softBurst",
|
||||
"hoverShape": "flower",
|
||||
"accent": "purple",
|
||||
"heading": "A new design",
|
||||
"description": "Material 3 Expressive across Settings, Control Center, Dash, and every control",
|
||||
"target": "theme_surfaces"
|
||||
},
|
||||
{
|
||||
"icon": "space_dashboard",
|
||||
"shape": "cookie9",
|
||||
"hoverShape": "sunny",
|
||||
"accent": "blue",
|
||||
"heading": "Dash plugins",
|
||||
"description": "Plugins add full tabs or overview cards, sized and ordered your way",
|
||||
"target": "dank_dash"
|
||||
},
|
||||
{
|
||||
"icon": "lock",
|
||||
"shape": "clover4",
|
||||
"hoverShape": "cookie4",
|
||||
"accent": "green",
|
||||
"heading": "Build your lock screen",
|
||||
"description": "Place the clock, media, status, and any desktop widget where you want",
|
||||
"target": "lock_screen"
|
||||
},
|
||||
{
|
||||
"icon": "lyrics",
|
||||
"shape": "sunny",
|
||||
"hoverShape": "softBurst",
|
||||
"accent": "pink",
|
||||
"heading": "Lyrical Engine",
|
||||
"description": "Word synced lyrics from six providers, right in the media player",
|
||||
"target": "media_player"
|
||||
},
|
||||
{
|
||||
"icon": "wallpaper",
|
||||
"shape": "gem",
|
||||
"hoverShape": "cookie6",
|
||||
"accent": "orange",
|
||||
"heading": "Material wallpapers",
|
||||
"description": "Presets from your seed color, plus layouts from wallpaper.danklinux.com",
|
||||
"target": "personalization"
|
||||
},
|
||||
{
|
||||
"icon": "digital_wellbeing",
|
||||
"shape": "puffy",
|
||||
"hoverShape": "clover8",
|
||||
"accent": "teal",
|
||||
"heading": "Digital wellbeing",
|
||||
"description": "Screen time, daily and app limits, with its own Dash tab",
|
||||
"target": "wellbeing"
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var additions: [
|
||||
{
|
||||
"icon": "view_in_ar",
|
||||
"accent": "purple",
|
||||
"title": "Island",
|
||||
"subtitle": "Notch mode, workspace switcher, tray slot, clipboard, and shadows",
|
||||
"target": "dankbar_settings"
|
||||
},
|
||||
{
|
||||
"icon": "grid_view",
|
||||
"accent": "green",
|
||||
"title": "Launcher",
|
||||
"subtitle": "Custom keybindings, dmenu mode, Open with, and app editing",
|
||||
"target": "launcher"
|
||||
},
|
||||
{
|
||||
"icon": "dock_to_bottom",
|
||||
"accent": "orange",
|
||||
"title": "Dock",
|
||||
"subtitle": "Proximity magnification and a focused app pill",
|
||||
"target": "dock_appearance"
|
||||
},
|
||||
{
|
||||
"icon": "notifications",
|
||||
"accent": "pink",
|
||||
"title": "Notifications",
|
||||
"subtitle": "Rule conditions, timed app mutes, and two finger swipe to dismiss",
|
||||
"target": "notification_rules"
|
||||
},
|
||||
{
|
||||
"icon": "extension",
|
||||
"accent": "teal",
|
||||
"title": "Plugin browser",
|
||||
"subtitle": "Discover shelves, quick filters, upvotes, and typo tolerant search",
|
||||
"target": "plugins"
|
||||
},
|
||||
{
|
||||
"icon": "format_paint",
|
||||
"accent": "yellow",
|
||||
"title": "Themes",
|
||||
"subtitle": "Bold palettes, injected palettes, fixed radius, and terminal opacity",
|
||||
"target": "theme"
|
||||
},
|
||||
{
|
||||
"icon": "monitor",
|
||||
"accent": "red",
|
||||
"title": "Displays",
|
||||
"subtitle": "Per-output ICC profiles and color temperature",
|
||||
"target": "display_config"
|
||||
},
|
||||
{
|
||||
"icon": "system_update_alt",
|
||||
"accent": "blue",
|
||||
"title": "Software updates",
|
||||
"subtitle": "Update dms from Settings and switch between stable and beta",
|
||||
"target": "updater"
|
||||
},
|
||||
{
|
||||
"icon": "devices",
|
||||
"accent": "green",
|
||||
"title": "More platforms",
|
||||
"subtitle": "FreeBSD, Enterprise Linux 10, Mango, Hyprland 0.56, Umbriel, and Aqueous",
|
||||
"target": root.compositorDocsUrl
|
||||
}
|
||||
]
|
||||
|
||||
readonly property var featurePairs: {
|
||||
const pairs = [];
|
||||
for (let i = 0; i < features.length; i += 2)
|
||||
pairs.push(features.slice(i, i + 2));
|
||||
return pairs;
|
||||
}
|
||||
|
||||
function open(target) {
|
||||
if (target.startsWith("https://")) {
|
||||
Qt.openUrlExternally(target);
|
||||
return;
|
||||
}
|
||||
PopoutService.openSettingsWithTab(target);
|
||||
}
|
||||
|
||||
topPadding: Theme.spacingS
|
||||
spacing: Theme.spacingL
|
||||
|
||||
ChangelogHero {
|
||||
width: parent.width
|
||||
symbol: "He"
|
||||
atomicNumber: 2
|
||||
atomicMass: "4.0026"
|
||||
remainder: "isenberg"
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.featurePairs
|
||||
|
||||
delegate: Row {
|
||||
id: pair
|
||||
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
readonly property real cardWidth: (width - spacing) / 2
|
||||
readonly property real rowHeight: Math.max(first.implicitHeight, second.implicitHeight)
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
|
||||
FeatureCard {
|
||||
id: first
|
||||
width: pair.cardWidth
|
||||
height: pair.rowHeight
|
||||
iconName: pair.modelData[0].icon
|
||||
shape: pair.modelData[0].shape
|
||||
hoverShape: pair.modelData[0].hoverShape
|
||||
accent: pair.modelData[0].accent
|
||||
heading: pair.modelData[0].heading
|
||||
description: pair.modelData[0].description
|
||||
onClicked: root.open(pair.modelData[0].target)
|
||||
}
|
||||
|
||||
FeatureCard {
|
||||
id: second
|
||||
width: pair.cardWidth
|
||||
height: pair.rowHeight
|
||||
iconName: pair.modelData[1].icon
|
||||
shape: pair.modelData[1].shape
|
||||
hoverShape: pair.modelData[1].hoverShape
|
||||
accent: pair.modelData[1].accent
|
||||
heading: pair.modelData[1].heading
|
||||
description: pair.modelData[1].description
|
||||
onClicked: root.open(pair.modelData[1].target)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
title: "More in " + ChangelogService.currentVersion
|
||||
|
||||
Repeater {
|
||||
model: root.additions
|
||||
|
||||
delegate: SettingsRow {
|
||||
id: addition
|
||||
|
||||
required property var modelData
|
||||
|
||||
readonly property var accentPair: Theme.accent(modelData.accent)
|
||||
|
||||
title: modelData.title
|
||||
subtitle: modelData.subtitle
|
||||
resetKeys: []
|
||||
clickable: modelData.target !== ""
|
||||
showChevron: clickable
|
||||
onClicked: root.open(modelData.target)
|
||||
|
||||
leading: Rectangle {
|
||||
width: SettingsMetrics.navIconSize
|
||||
height: width
|
||||
radius: Theme.fullRadius(width, height)
|
||||
color: addition.accentPair?.container ?? Theme.primaryContainer
|
||||
|
||||
DIcon {
|
||||
anchors.centerIn: parent
|
||||
name: addition.modelData.icon
|
||||
size: Theme.iconSizeMedium
|
||||
color: addition.accentPair?.onContainer ?? Theme.onPrimaryContainer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DCard {
|
||||
width: parent.width
|
||||
height: pluginNote.implicitHeight + pad * 2
|
||||
tone: "tertiary"
|
||||
pad: Theme.spacingL
|
||||
restRadius: Theme.groupedListOuterRadius
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
id: pluginNote
|
||||
width: parent.width
|
||||
spacing: Theme.spacingL
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
|
||||
Image {
|
||||
width: root.logoSize
|
||||
height: width * (569.94629 / 506.50931)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
smooth: true
|
||||
mipmap: true
|
||||
asynchronous: true
|
||||
source: "file://" + Theme.shellDir + "/assets/danklogonormal.svg"
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
layer.mipmap: true
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
DMaterialShape {
|
||||
width: Theme.buttonHeightM
|
||||
height: width
|
||||
shape: "cookie6"
|
||||
color: Theme.onTertiaryContainer
|
||||
|
||||
DIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "code"
|
||||
size: Theme.iconSize
|
||||
color: Theme.tertiaryContainer
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.buttonHeightM - docsButton.width - parent.spacing * 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
spacing: Theme.spacingXXS
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "DMS " + ChangelogService.currentVersion
|
||||
font.pixelSize: Theme.fontSizeXLarge + 2
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: codenameText.implicitWidth + Theme.spacingM * 2
|
||||
height: root.badgeHeight
|
||||
radius: Theme.fullRadius(width, height)
|
||||
color: Theme.primaryContainer
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
id: codenameText
|
||||
anchors.centerIn: parent
|
||||
text: "Marble Tabby"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.accentOnPrimaryContainer
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Plugin authors"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Theme.fontWeightBold
|
||||
color: Theme.onTertiaryContainer
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Dank Island, spring motion, performance & resource optimizations"
|
||||
width: parent.width
|
||||
text: "The Dank* widget wrappers are deprecated. Import qs.DCommon.Widgets and use the D names, DankButton becomes DButton. Each old type logs its replacement."
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineMedium
|
||||
opacity: 0.3
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "What's New"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Grid {
|
||||
width: parent.width
|
||||
columns: 2
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "view_in_ar"
|
||||
title: "Dank Island"
|
||||
description: "A bar that reacts to you"
|
||||
onClicked: {
|
||||
SettingsSearchService.navigateToSection("barLayout");
|
||||
PopoutService.openSettingsWithTab("dankbar");
|
||||
color: Theme.onTertiaryContainer
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "animation"
|
||||
title: "Spring Motion"
|
||||
description: "New motion physics"
|
||||
onClicked: {
|
||||
SettingsSearchService.navigateToSection("springBounce");
|
||||
PopoutService.openSettingsWithTab("typography");
|
||||
}
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "speed"
|
||||
title: "Performance"
|
||||
description: "Big speedups, less memory"
|
||||
onClicked: Qt.openUrlExternally(root.releaseNotesUrl)
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "wifi_tethering"
|
||||
title: "Network"
|
||||
description: "Hotspot, cellular, and OWE"
|
||||
onClicked: {
|
||||
SettingsSearchService.navigateToSection("networkHotspot");
|
||||
PopoutService.openSettingsWithTab("network_wifi");
|
||||
}
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "extension"
|
||||
title: "Plugin Registries"
|
||||
description: "Add your own sources"
|
||||
onClicked: PopoutService.openSettingsWithTab("plugins")
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "photo_camera"
|
||||
title: "Capture"
|
||||
description: "Grab regions across outputs"
|
||||
onClicked: Qt.openUrlExternally(root.screenshotDocsUrl)
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "login"
|
||||
title: "Standalone Greeter"
|
||||
description: "Now its own app"
|
||||
onClicked: {
|
||||
SettingsSearchService.navigateToSection("greeterStatus");
|
||||
PopoutService.openSettingsWithTab("greeter");
|
||||
}
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "dock_to_bottom"
|
||||
title: "Dock"
|
||||
description: "Pinned apps, running apps"
|
||||
onClicked: {
|
||||
SettingsSearchService.navigateToSection("dockSeparatePinnedAndRunningApps");
|
||||
PopoutService.openSettingsWithTab("dock_general");
|
||||
}
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "content_paste"
|
||||
title: "Clipboard"
|
||||
description: "Drop in anything to store it"
|
||||
onClicked: PopoutService.openSettingsWithTab("clipboard")
|
||||
}
|
||||
|
||||
ChangelogFeatureCard {
|
||||
width: (parent.width - Theme.spacingS) / 2
|
||||
iconName: "language"
|
||||
title: "Translations"
|
||||
description: "22 languages, plugin translations"
|
||||
onClicked: {
|
||||
SettingsSearchService.navigateToSection("locale");
|
||||
PopoutService.openSettingsWithTab("locale");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineMedium
|
||||
opacity: 0.3
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DIcon {
|
||||
name: "warning"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.warning
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Upgrade Notes"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
DButton {
|
||||
id: docsButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: I18n.tr("Docs")
|
||||
iconName: "open_in_new"
|
||||
backgroundColor: Theme.onTertiaryContainer
|
||||
textColor: Theme.tertiaryContainer
|
||||
onClicked: Qt.openUrlExternally(root.pluginDocsUrl)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: upgradeNotesColumn.height + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.warning, 0.08)
|
||||
border.width: 1
|
||||
border.color: Theme.withAlpha(Theme.warning, 0.2)
|
||||
|
||||
Column {
|
||||
id: upgradeNotesColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
ChangelogUpgradeNote {
|
||||
width: parent.width
|
||||
text: "The shell is embedded in the dms binary. ~/.config/quickshell/dms is no longer auto-discovered, pass -c or set DMS_SHELL_DIR to override it"
|
||||
}
|
||||
|
||||
ChangelogUpgradeNote {
|
||||
width: parent.width
|
||||
text: "The greeter is now a standalone application. dms greeter commands become dms-greeter"
|
||||
}
|
||||
|
||||
ChangelogUpgradeNote {
|
||||
width: parent.width
|
||||
text: "settings.json only stores what differs from the defaults, and machine-specific state moved to session.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDivider {
|
||||
visible: ChangelogService.release !== null
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
visible: ChangelogService.release !== null
|
||||
spacing: Theme.spacingS
|
||||
spacing: 0
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DIcon {
|
||||
name: "auto_awesome"
|
||||
size: Theme.iconSizeSmall
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("What changed", "changelog section heading listing the changes in a release")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
SettingsSectionLabel {
|
||||
text: I18n.tr("What changed", "changelog section heading listing the changes in a release")
|
||||
}
|
||||
|
||||
ReleaseNotesCard {
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string iconName: ""
|
||||
property string title: ""
|
||||
property string description: ""
|
||||
|
||||
signal clicked
|
||||
|
||||
readonly property real iconContainerSize: Math.round(Theme.iconSize * 1.3)
|
||||
|
||||
height: Math.round(Theme.fontSizeMedium * 4.2)
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.floatingWindowNestedSurface
|
||||
border.width: Theme.layerOutlineWidth
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: Theme.primary
|
||||
opacity: mouseArea.containsMouse ? 0.12 : 0
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: root.iconContainerSize
|
||||
height: root.iconContainerSize
|
||||
radius: Math.round(root.iconContainerSize * 0.28)
|
||||
color: Theme.primaryContainer
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DIcon {
|
||||
anchors.centerIn: parent
|
||||
name: root.iconName
|
||||
size: Theme.iconSize - 6
|
||||
color: Theme.accentOnPrimaryContainer
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
width: parent.width - root.iconContainerSize - Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: root.title
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.DCommon.Widgets
|
||||
import qs.Widgets
|
||||
|
||||
ShapeHero {
|
||||
id: root
|
||||
|
||||
property string symbol: ""
|
||||
property int atomicNumber: 0
|
||||
property string atomicMass: ""
|
||||
property string remainder: ""
|
||||
|
||||
readonly property real lockupBaseSize: Theme.fontSizeDisplayLarge * 0.8
|
||||
readonly property real lockupScale: Math.min(1, availableWidth / Math.max(1, lockupBaseSize * 1.6 + Theme.spacingS + remainderMetrics.width))
|
||||
readonly property real lockupSize: lockupBaseSize * lockupScale
|
||||
readonly property real tileSize: lockupSize * 1.6
|
||||
|
||||
accentSize: tileSize
|
||||
paddingV: Theme.spacingXL
|
||||
|
||||
StyledTextMetrics {
|
||||
id: remainderMetrics
|
||||
text: root.remainder
|
||||
font.pixelSize: root.lockupBaseSize
|
||||
font.weight: Theme.fontWeightBold
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
id: tile
|
||||
width: root.tileSize
|
||||
height: width
|
||||
radius: Theme.cornerRadiusS
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.margins: tile.width * 0.07
|
||||
text: root.atomicNumber
|
||||
font.pixelSize: tile.width * 0.15
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.onPrimary
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: tile.width * 0.03
|
||||
text: root.symbol
|
||||
font.pixelSize: root.lockupSize * 0.9
|
||||
font.weight: Theme.fontWeightBold
|
||||
color: Theme.onPrimary
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: tile.width * 0.05
|
||||
text: root.atomicMass
|
||||
font.pixelSize: tile.width * 0.11
|
||||
color: Theme.onPrimary
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.remainder
|
||||
font.pixelSize: root.lockupSize
|
||||
font.weight: Theme.fontWeightBold
|
||||
color: Theme.onPrimaryContainer
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: versionText.implicitWidth + Theme.spacingL * 2
|
||||
height: Theme.buttonHeightXXS
|
||||
radius: Theme.fullRadius(width, height)
|
||||
color: Theme.primary
|
||||
|
||||
StyledText {
|
||||
id: versionText
|
||||
anchors.centerIn: parent
|
||||
text: "dms " + ChangelogService.currentVersion
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightBold
|
||||
color: Theme.onPrimary
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,8 @@ import qs.Widgets
|
||||
DFloatingWindow {
|
||||
id: root
|
||||
|
||||
readonly property int modalWidth: 680
|
||||
readonly property int modalHeight: screen ? Math.min(720, screen.height - 80) : 720
|
||||
readonly property int modalWidth: 720
|
||||
readonly property int modalHeight: screen ? Math.min(800, screen.height - 80) : 800
|
||||
|
||||
signal changelogDismissed
|
||||
|
||||
@@ -16,6 +16,12 @@ DFloatingWindow {
|
||||
visible = true;
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
ChangelogService.dismissChangelog();
|
||||
changelogDismissed();
|
||||
visible = false;
|
||||
}
|
||||
|
||||
objectName: "changelogModal"
|
||||
title: "What's New"
|
||||
minimumSize: Qt.size(modalWidth, modalHeight)
|
||||
@@ -57,58 +63,55 @@ DFloatingWindow {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: headerRow.bottom
|
||||
anchors.bottom: footerRow.top
|
||||
anchors.bottom: parent.bottom
|
||||
clip: true
|
||||
contentHeight: mainColumn.height + Theme.spacingL * 2
|
||||
contentHeight: mainColumn.height + fabBar.height + Theme.spacingL * 3
|
||||
contentWidth: width
|
||||
|
||||
ChangelogContent {
|
||||
id: mainColumn
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: Math.min(600, parent.width - Theme.spacingXL * 2)
|
||||
width: Math.min(640, parent.width - Theme.spacingXL * 2)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: footerRow
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Row {
|
||||
id: fabBar
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
height: Math.round(Theme.fontSizeMedium * 4.5)
|
||||
color: Theme.floatingWindowNestedSurface
|
||||
border.width: Theme.layerOutlineWidth
|
||||
border.color: Theme.outlineMedium
|
||||
anchors.bottomMargin: Theme.spacingL
|
||||
z: 2
|
||||
spacing: Theme.spacingM
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineMedium
|
||||
opacity: 0.5
|
||||
}
|
||||
DButton {
|
||||
id: notesButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: I18n.tr("Release notes", "settings page and card title, notes for a DMS release")
|
||||
iconName: "auto_awesome"
|
||||
buttonHeight: Theme.buttonHeightM
|
||||
backgroundColor: Theme.secondaryContainer
|
||||
textColor: Theme.onSecondaryContainer
|
||||
onClicked: PopoutService.openSettingsWithTab("updater_changelog")
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DButton {
|
||||
text: I18n.tr("Release notes", "settings page and card title, notes for a DMS release")
|
||||
iconName: "auto_awesome"
|
||||
backgroundColor: Theme.chipSurface
|
||||
textColor: Theme.surfaceText
|
||||
onClicked: {
|
||||
root.dismiss();
|
||||
PopoutService.openSettingsWithTab("updater_changelog");
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
active: Theme.elevationEnabled
|
||||
sourceComponent: ElevationShadow {
|
||||
level: Theme.elevationLevel3
|
||||
targetColor: notesButton.color
|
||||
targetRadius: notesButton.radius
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DButton {
|
||||
text: I18n.tr("OK")
|
||||
iconName: "check"
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.primaryText
|
||||
onClicked: root.dismiss()
|
||||
}
|
||||
DFab {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "Let's go"
|
||||
iconName: "rocket_launch"
|
||||
colorRole: "primary"
|
||||
onClicked: root.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,10 +120,4 @@ DFloatingWindow {
|
||||
id: windowControls
|
||||
targetWindow: root
|
||||
}
|
||||
|
||||
function dismiss() {
|
||||
ChangelogService.dismissChangelog();
|
||||
changelogDismissed();
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
Row {
|
||||
id: root
|
||||
|
||||
property alias text: noteText.text
|
||||
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DIcon {
|
||||
name: "arrow_right"
|
||||
size: Theme.iconSizeSmall - 2
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 2
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: noteText
|
||||
width: root.width - Theme.iconSizeSmall - Theme.spacingS
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string iconName: ""
|
||||
property string title: ""
|
||||
property string description: ""
|
||||
|
||||
signal clicked
|
||||
|
||||
readonly property real iconContainerSize: Math.round(Theme.iconSize * 1.5)
|
||||
|
||||
height: Math.round(Theme.fontSizeMedium * 6.4)
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.floatingWindowNestedSurface
|
||||
border.width: Theme.layerOutlineWidth
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: Theme.primary
|
||||
opacity: mouseArea.containsMouse ? 0.12 : 0
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: root.iconContainerSize
|
||||
height: root.iconContainerSize
|
||||
radius: Math.round(root.iconContainerSize * 0.28)
|
||||
color: Theme.primaryContainer
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
DIcon {
|
||||
anchors.centerIn: parent
|
||||
name: root.iconName
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.accentOnPrimaryContainer
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
|
||||
StyledText {
|
||||
text: root.title
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
@@ -154,54 +154,6 @@ DFloatingWindow {
|
||||
title: root.title
|
||||
closeTooltipText: I18n.tr("Skip setup", "greeter skip button tooltip")
|
||||
onCloseRequested: root.skip()
|
||||
|
||||
Rectangle {
|
||||
id: pageIndicatorContainer
|
||||
readonly property real indicatorHeight: Math.round(Theme.fontSizeMedium * 2)
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: pageIndicatorRow.width + Theme.spacingM * 2
|
||||
height: indicatorHeight
|
||||
radius: Theme.fullRadius(width, height)
|
||||
color: Theme.floatingWindowNestedSurface
|
||||
border.width: Theme.layerOutlineWidth
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
Row {
|
||||
id: pageIndicatorRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.totalPages
|
||||
|
||||
Rectangle {
|
||||
required property int index
|
||||
property bool isActive: index === root.currentPage
|
||||
readonly property real dotSize: Math.round(Theme.spacingS * 1.3)
|
||||
|
||||
width: isActive ? dotSize * 3 : dotSize
|
||||
height: dotSize
|
||||
radius: dotSize / 2
|
||||
color: dotColor.value
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DColorAnimation {
|
||||
id: dotColor
|
||||
to: isActive ? Theme.primary : Theme.surfaceTextAlpha
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -219,66 +171,93 @@ DFloatingWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: footerRow
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
height: Math.round(Theme.fontSizeMedium * 4.5)
|
||||
color: Theme.floatingWindowNestedSurface
|
||||
border.width: Theme.layerOutlineWidth
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineMedium
|
||||
opacity: 0.5
|
||||
}
|
||||
height: Theme.buttonHeightM + Theme.spacingL * 2
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.windowInset
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DButton {
|
||||
visible: root.currentPage < root.totalPages - 1
|
||||
text: I18n.tr("Skip", "greeter skip button")
|
||||
backgroundColor: "transparent"
|
||||
textColor: Theme.surfaceVariantText
|
||||
onClicked: root.currentPage === 1 ? root.nextPage() : root.skip()
|
||||
}
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DButton {
|
||||
visible: root.currentPage > 0
|
||||
text: I18n.tr("Back", "greeter back button")
|
||||
iconName: "arrow_back"
|
||||
backgroundColor: Theme.chipSurface
|
||||
textColor: Theme.surfaceText
|
||||
buttonHeight: Theme.buttonHeightM
|
||||
backgroundColor: Theme.secondaryContainer
|
||||
textColor: Theme.onSecondaryContainer
|
||||
onClicked: root.prevPage()
|
||||
}
|
||||
|
||||
DButton {
|
||||
visible: root.currentPage < root.totalPages - 1
|
||||
enabled: !(root.currentPage === 1 && pageLoader.item && pageLoader.item.isRunning)
|
||||
text: root.currentPage === 0 ? I18n.tr("Get Started", "greeter first page button") : I18n.tr("Next", "greeter next button")
|
||||
iconName: "arrow_forward"
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.primaryText
|
||||
onClicked: root.nextPage()
|
||||
text: I18n.tr("Skip", "greeter skip button")
|
||||
buttonHeight: Theme.buttonHeightM
|
||||
backgroundColor: "transparent"
|
||||
textColor: Theme.primary
|
||||
onClicked: root.currentPage === 1 ? root.nextPage() : root.skip()
|
||||
}
|
||||
}
|
||||
|
||||
DButton {
|
||||
visible: root.currentPage === root.totalPages - 1
|
||||
text: I18n.tr("Finish", "greeter finish button")
|
||||
iconName: "check"
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.primaryText
|
||||
onClicked: root.finish()
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.totalPages
|
||||
|
||||
Rectangle {
|
||||
required property int index
|
||||
readonly property bool isActive: index === root.currentPage
|
||||
|
||||
width: isActive ? Theme.spacingXL : Theme.spacingS
|
||||
height: Theme.spacingS
|
||||
radius: Theme.fullRadius(width, height)
|
||||
color: isActive ? Theme.primary : Theme.outlineVariant
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Behavior on width {
|
||||
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
|
||||
NumberAnimation {
|
||||
duration: Theme.expressiveDurations.expressiveFastSpatial
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Theme.expressiveCurves.expressiveFastSpatial
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
|
||||
ColorAnimation {
|
||||
duration: Theme.expressiveDurations.expressiveEffects
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DButton {
|
||||
readonly property bool lastPage: root.currentPage === root.totalPages - 1
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingL
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
enabled: !(root.currentPage === 1 && pageLoader.item && pageLoader.item.isRunning)
|
||||
text: lastPage ? I18n.tr("Finish", "greeter finish button") : root.currentPage === 0 ? I18n.tr("Get Started", "greeter first page button") : I18n.tr("Next", "greeter next button")
|
||||
iconName: lastPage ? "check" : "arrow_forward"
|
||||
buttonHeight: Theme.buttonHeightM
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.onPrimary
|
||||
onClicked: lastPage ? root.finish() : root.nextPage()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Item {
|
||||
|
||||
property var greeterRoot: parent ? parent.greeterRoot : null
|
||||
|
||||
readonly property var curatedPluginIds: ["quickCapture", "dankKDEConnect", "wallpaperCarousel", "calculator", "emojiLauncher", "dockerManager", "amdGpuMonitor", "bongoCat"]
|
||||
readonly property var curatedPluginIds: ["quickCapture", "dankKDEConnect", "wallpaperCarousel", "calculator", "emojiLauncher", "dockerManager", "dankSoftwareDepot", "homeAssistantMonitor"]
|
||||
|
||||
readonly property real headerIconContainerSize: Math.round(Theme.iconSize * 2)
|
||||
|
||||
|
||||
@@ -1,135 +1,229 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.DCommon.Widgets
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property real logoSize: Math.round(Theme.iconSize * 5.3)
|
||||
readonly property int columns: 3
|
||||
readonly property real cardWidth: (content.width - Theme.spacingS * (columns - 1)) / columns
|
||||
readonly property var features: [
|
||||
{
|
||||
"icon": "auto_awesome",
|
||||
"shape": "softBurst",
|
||||
"hoverShape": "flower",
|
||||
"accent": "purple",
|
||||
"heading": I18n.tr("Dynamic Theming", "greeter feature card title"),
|
||||
"description": I18n.tr("Colors from wallpaper", "greeter feature card description"),
|
||||
"target": "theme"
|
||||
},
|
||||
{
|
||||
"icon": "toolbar",
|
||||
"shape": "pill",
|
||||
"hoverShape": "cookie4",
|
||||
"accent": "blue",
|
||||
"heading": I18n.tr("Bar"),
|
||||
"description": I18n.tr("Modular widget bar", "greeter feature card description"),
|
||||
"target": "dankbar_settings"
|
||||
},
|
||||
{
|
||||
"icon": "extension",
|
||||
"shape": "puffy",
|
||||
"hoverShape": "clover8",
|
||||
"accent": "green",
|
||||
"heading": I18n.tr("Plugins", "greeter feature card title"),
|
||||
"description": I18n.tr("Extensible architecture", "greeter feature card description"),
|
||||
"target": "plugins"
|
||||
},
|
||||
{
|
||||
"icon": "monitor",
|
||||
"shape": "gem",
|
||||
"hoverShape": "cookie6",
|
||||
"accent": "orange",
|
||||
"heading": I18n.tr("Multi-Monitor", "greeter feature card title"),
|
||||
"description": I18n.tr("Per-screen config", "greeter feature card description"),
|
||||
"target": CompositorService.supportsDisplayConfig ? "display_config" : "display_widgets"
|
||||
},
|
||||
{
|
||||
"icon": "nightlight",
|
||||
"shape": "sunny",
|
||||
"hoverShape": "softBurst",
|
||||
"accent": "pink",
|
||||
"heading": I18n.tr("Display Control", "greeter feature card title"),
|
||||
"description": I18n.tr("Night mode & gamma", "greeter feature card description"),
|
||||
"target": "display_gamma"
|
||||
},
|
||||
{
|
||||
"icon": "tune",
|
||||
"shape": "cookie9",
|
||||
"hoverShape": "sunny",
|
||||
"accent": "teal",
|
||||
"heading": I18n.tr("Control Center", "greeter feature card title"),
|
||||
"description": I18n.tr("Quick system toggles", "greeter feature card description"),
|
||||
"target": "control_center"
|
||||
}
|
||||
]
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
anchors.centerIn: parent
|
||||
width: Math.min(Math.round(Theme.fontSizeMedium * 43), parent.width - Theme.spacingXL * 2)
|
||||
spacing: Theme.spacingXL
|
||||
function open(target) {
|
||||
switch (target) {
|
||||
case "control_center":
|
||||
BarWidgetService.getBarWindowOnFocusedScreen()?.triggerControlCenter();
|
||||
return;
|
||||
}
|
||||
PopoutService.openSettingsWithTab(target);
|
||||
}
|
||||
|
||||
DFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: width
|
||||
contentHeight: Math.max(height, content.height + Theme.spacingL * 2)
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
id: content
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
y: Math.max(Theme.spacingS, (parent.height - height) / 2)
|
||||
width: Math.min(640, parent.width - Theme.spacingXL * 2)
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Image {
|
||||
width: root.logoSize
|
||||
height: width * (569.94629 / 506.50931)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
fillMode: Image.PreserveAspectFit
|
||||
smooth: true
|
||||
mipmap: true
|
||||
asynchronous: true
|
||||
source: "file://" + Theme.shellDir + "/assets/danklogonormal.svg"
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
layer.mipmap: true
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
ShapeHero {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
paddingV: Theme.spacingXL
|
||||
backdrop: Item {
|
||||
DMaterialShape {
|
||||
width: parent.height * 1.6
|
||||
height: width
|
||||
x: parent.width - width * 0.72
|
||||
y: -height * 0.38
|
||||
shape: "cookie12"
|
||||
respectThemeShape: false
|
||||
color: Theme.withAlpha(Theme.primary, Theme.tonalTintAlpha)
|
||||
rotation: 10
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Welcome to DankMaterialShell", "greeter welcome page title")
|
||||
font.pixelSize: Theme.fontSizeXLarge + 4
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
DMaterialShape {
|
||||
width: parent.height * 1.1
|
||||
height: width
|
||||
x: parent.width - width * 1.35
|
||||
y: parent.height - height * 0.55
|
||||
shape: "softBurst"
|
||||
respectThemeShape: false
|
||||
color: Theme.withAlpha(Theme.tertiary, Theme.tonalTintAlpha)
|
||||
rotation: -12
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("A modern desktop shell for Wayland compositors", "greeter welcome page tagline")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Theme.outlineMedium
|
||||
opacity: 0.3
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Features", "greeter welcome page section header")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Grid {
|
||||
width: parent.width
|
||||
columns: 3
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
|
||||
GreeterFeatureCard {
|
||||
width: (parent.width - Theme.spacingS * 2) / 3
|
||||
iconName: "auto_awesome"
|
||||
title: I18n.tr("Dynamic Theming", "greeter feature card title")
|
||||
description: I18n.tr("Colors from wallpaper", "greeter feature card description")
|
||||
onClicked: PopoutService.openSettingsWithTab("theme")
|
||||
}
|
||||
|
||||
GreeterFeatureCard {
|
||||
width: (parent.width - Theme.spacingS * 2) / 3
|
||||
iconName: "view_carousel"
|
||||
title: I18n.tr("DankBar", "greeter feature card title")
|
||||
description: I18n.tr("Modular widget bar", "greeter feature card description")
|
||||
onClicked: PopoutService.openSettingsWithTab("dankbar_settings")
|
||||
}
|
||||
|
||||
GreeterFeatureCard {
|
||||
width: (parent.width - Theme.spacingS * 2) / 3
|
||||
iconName: "extension"
|
||||
title: I18n.tr("Plugins", "greeter feature card title")
|
||||
description: I18n.tr("Extensible architecture", "greeter feature card description")
|
||||
onClicked: PopoutService.openSettingsWithTab("plugins")
|
||||
}
|
||||
|
||||
GreeterFeatureCard {
|
||||
width: (parent.width - Theme.spacingS * 2) / 3
|
||||
iconName: "layers"
|
||||
title: I18n.tr("Multi-Monitor", "greeter feature card title")
|
||||
description: I18n.tr("Per-screen config", "greeter feature card description")
|
||||
onClicked: {
|
||||
PopoutService.openSettingsWithTab(CompositorService.supportsDisplayConfig ? "display_config" : "display_widgets");
|
||||
DMaterialShape {
|
||||
width: parent.height * 0.75
|
||||
height: width
|
||||
x: parent.width * 0.6
|
||||
y: -height * 0.2
|
||||
shape: "pill"
|
||||
respectThemeShape: false
|
||||
color: Theme.withAlpha(Theme.secondary, Theme.tonalTintAlpha)
|
||||
rotation: -35
|
||||
}
|
||||
}
|
||||
|
||||
GreeterFeatureCard {
|
||||
width: (parent.width - Theme.spacingS * 2) / 3
|
||||
iconName: "nightlight"
|
||||
title: I18n.tr("Display Control", "greeter feature card title")
|
||||
description: I18n.tr("Night mode & gamma", "greeter feature card description")
|
||||
onClicked: PopoutService.openSettingsWithTab("display_gamma")
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
Item {
|
||||
id: logo
|
||||
width: Theme.buttonHeightM * 1.6
|
||||
height: width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Image {
|
||||
readonly property real dpr: Screen.devicePixelRatio
|
||||
|
||||
anchors.centerIn: parent
|
||||
height: parent.height
|
||||
width: height
|
||||
// 2x raster plus mipmap keeps the thin rings smooth at fractional scales
|
||||
sourceSize.height: Math.ceil(height * dpr * 2)
|
||||
fillMode: Image.PreserveAspectFit
|
||||
smooth: true
|
||||
mipmap: true
|
||||
asynchronous: true
|
||||
source: "file://" + Theme.shellDir + "/assets/danklogo.svg"
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
layer.textureSize: Qt.size(Math.ceil(width * dpr), Math.ceil(height * dpr))
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - logo.width - parent.spacing
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Welcome to DankMaterialShell", "greeter welcome page title")
|
||||
font.pixelSize: Theme.fontSizeXXLarge
|
||||
font.weight: Theme.fontWeightBold
|
||||
color: Theme.onPrimaryContainer
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("A modern desktop shell for Wayland compositors", "greeter welcome page tagline")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.onPrimaryContainer
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: grid
|
||||
|
||||
readonly property real cellHeight: {
|
||||
let tallest = 0;
|
||||
for (const card of children)
|
||||
tallest = Math.max(tallest, card.implicitHeight ?? 0);
|
||||
return tallest;
|
||||
}
|
||||
|
||||
GreeterFeatureCard {
|
||||
width: (parent.width - Theme.spacingS * 2) / 3
|
||||
iconName: "tune"
|
||||
title: I18n.tr("Control Center", "greeter feature card title")
|
||||
description: I18n.tr("Quick system toggles", "greeter feature card description")
|
||||
onClicked: BarWidgetService.getBarWindowOnFocusedScreen()?.triggerControlCenter()
|
||||
width: parent.width
|
||||
columns: root.columns
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight
|
||||
|
||||
Repeater {
|
||||
model: root.features
|
||||
|
||||
delegate: FeatureCard {
|
||||
required property var modelData
|
||||
|
||||
width: root.cardWidth
|
||||
height: grid.cellHeight
|
||||
iconName: modelData.icon
|
||||
shape: modelData.shape
|
||||
hoverShape: modelData.hoverShape
|
||||
accent: modelData.accent
|
||||
heading: modelData.heading
|
||||
description: modelData.description
|
||||
onClicked: root.open(modelData.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ Item {
|
||||
settingKey: "matugenSpec"
|
||||
text: I18n.tr("Material palette", "theme settings card title, matugen palette options")
|
||||
enabled: Theme.matugenAvailable
|
||||
model: ["2021", "2025", "DMS"]
|
||||
model: ["2021", "2025", "dms"]
|
||||
currentIndex: SettingsData.matugenSpec === "dms" ? 2 : SettingsData.matugenSpec === "2025" ? 1 : 0
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
|
||||
@@ -4,12 +4,14 @@ import qs.Services
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
DHeroCard {
|
||||
brand: "DMS"
|
||||
brand: "dms"
|
||||
accent: {
|
||||
const semver = ShellVersionService.semverVersion.replace(/^v/, "");
|
||||
const base = semver.match(/^\d+\.\d+/);
|
||||
return base ? base[0] : semver || SystemUpdateService.shellRunning.replace(/^v/, "");
|
||||
}
|
||||
caption: ShellVersionService.shellCodename.toUpperCase()
|
||||
color: SettingsMetrics.rowColor
|
||||
caption: ShellVersionService.shellCodename
|
||||
symbol: "He"
|
||||
atomicNumber: 2
|
||||
atomicMass: "4.0026"
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ Singleton {
|
||||
name: I18n.tr("Settings", "settings window title"),
|
||||
icon: "svg+corner:" + dmsLogoPath + "|settings",
|
||||
cornerIcon: "settings",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
action: "ipc:settings",
|
||||
categories: ["Settings", "System"],
|
||||
defaultTrigger: "",
|
||||
@@ -206,7 +206,7 @@ Singleton {
|
||||
name: I18n.tr("Notepad", "Notepad"),
|
||||
icon: "svg+corner:" + dmsLogoPath + "|description",
|
||||
cornerIcon: "description",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
action: "ipc:notepad",
|
||||
categories: ["Office", "Utility"],
|
||||
defaultTrigger: "",
|
||||
@@ -217,7 +217,7 @@ Singleton {
|
||||
name: I18n.tr("System Monitor", "sysmon window title"),
|
||||
icon: "svg+corner:" + dmsLogoPath + "|monitor_heart",
|
||||
cornerIcon: "monitor_heart",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
action: "ipc:processlist",
|
||||
categories: ["System", "Monitor"],
|
||||
defaultTrigger: "",
|
||||
@@ -228,7 +228,7 @@ Singleton {
|
||||
name: I18n.tr("Color Picker"),
|
||||
icon: "svg+corner:" + dmsLogoPath + "|palette",
|
||||
cornerIcon: "palette",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
action: "ipc:color-picker",
|
||||
categories: ["Graphics", "Utility"],
|
||||
defaultTrigger: "",
|
||||
@@ -238,7 +238,7 @@ Singleton {
|
||||
id: "dms_power",
|
||||
name: I18n.tr("Power"),
|
||||
cornerIcon: "power_settings_new",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
defaultTrigger: "pw",
|
||||
isLauncher: true,
|
||||
viewMode: "list",
|
||||
@@ -249,7 +249,7 @@ Singleton {
|
||||
id: "dms_vpn",
|
||||
name: I18n.tr("VPN", "virtual private network, widget and page title"),
|
||||
cornerIcon: "vpn_key",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
defaultTrigger: "",
|
||||
isLauncher: true,
|
||||
viewMode: "list",
|
||||
@@ -261,7 +261,7 @@ Singleton {
|
||||
name: I18n.tr("QR Generator"),
|
||||
icon: "svg+corner:" + dmsLogoPath + "|qr_code",
|
||||
cornerIcon: "qr_code",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
action: "ipc:qr-generator",
|
||||
categories: ["Utility"],
|
||||
defaultTrigger: "qrg",
|
||||
@@ -281,7 +281,7 @@ Singleton {
|
||||
id: "dms_clipboard_search",
|
||||
name: I18n.tr("Clipboard"),
|
||||
cornerIcon: "content_paste",
|
||||
comment: "DMS",
|
||||
comment: "dms",
|
||||
defaultTrigger: "cb",
|
||||
isLauncher: true,
|
||||
viewMode: "list",
|
||||
|
||||
@@ -17,7 +17,7 @@ Singleton {
|
||||
const m = v.match(/^\d+\.\d+/);
|
||||
return m ? m[0] : "";
|
||||
}
|
||||
readonly property bool changelogEnabled: false
|
||||
readonly property bool changelogEnabled: true
|
||||
readonly property bool ready: SessionData._hasLoaded && !SessionData.isGreeterMode && FirstLaunchService.checkComplete && currentVersion !== ""
|
||||
|
||||
property bool changelogDismissed: false
|
||||
|
||||
@@ -615,7 +615,7 @@ Singleton {
|
||||
|
||||
function gamma(value: string): string {
|
||||
if (!root.gammaAdjustAvailable)
|
||||
return "Gamma adjustment not available (requires DMS API v34+)";
|
||||
return "Gamma adjustment not available (requires dms API v34+)";
|
||||
if (!value)
|
||||
return SessionData.displayGamma.toString();
|
||||
|
||||
@@ -629,7 +629,7 @@ Singleton {
|
||||
|
||||
function contrast(value: string): string {
|
||||
if (!root.gammaAdjustAvailable)
|
||||
return "Contrast adjustment not available (requires DMS API v34+)";
|
||||
return "Contrast adjustment not available (requires dms API v34+)";
|
||||
if (!value)
|
||||
return SessionData.displayContrast.toString();
|
||||
|
||||
|
||||
@@ -1088,7 +1088,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function sendTestNotification(index) {
|
||||
const notifications = [["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "preferences-system"], ["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "applications-graphics"], ["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "face-smile"]];
|
||||
const notifications = [["Notification Position Test", "dms test notification 1 of 3 ~ Hi there!", "preferences-system"], ["Second Test", "dms notification 2 of 3 ~ Check it out!", "applications-graphics"], ["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "face-smile"]];
|
||||
|
||||
if (index < 0 || index >= notifications.length) {
|
||||
return;
|
||||
|
||||
@@ -225,7 +225,7 @@ Singleton {
|
||||
|
||||
function status(): string {
|
||||
if (!root.available)
|
||||
return "Screen time tracking: unavailable (DMS server without wellbeing support)";
|
||||
return "Screen time tracking: unavailable (dms server without wellbeing support)";
|
||||
const lines = ["Screen time tracking: " + (root.enabled ? "enabled" : "disabled")];
|
||||
if (root.tracking)
|
||||
lines.push("Today: " + root.formatDuration(root.today.active ?? 0));
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
DCard {
|
||||
id: root
|
||||
|
||||
property string iconName: ""
|
||||
property string shape: "circle"
|
||||
property string hoverShape: "circle"
|
||||
property string accent: ""
|
||||
property string heading: ""
|
||||
property string description: ""
|
||||
|
||||
readonly property var accentPair: Theme.accent(accent)
|
||||
readonly property bool engaged: hover.hovered || focusTarget.visualFocus
|
||||
readonly property var morphSpring: Theme.springPreset("default", Theme.expressiveDurations.expressiveDefaultSpatial)
|
||||
|
||||
onEngagedChanged: morphMotion.retarget(engaged ? 1 : 0)
|
||||
|
||||
clickable: true
|
||||
pad: Theme.spacingL
|
||||
restRadius: Theme.groupedListOuterRadius
|
||||
bodyRadius: focusTarget.pressed ? Theme.cornerRadiusM : restRadius
|
||||
implicitHeight: body.implicitHeight + pad * 2
|
||||
Accessible.name: heading
|
||||
Accessible.description: description
|
||||
|
||||
HoverHandler {
|
||||
id: hover
|
||||
}
|
||||
|
||||
SpringMotion {
|
||||
id: morphMotion
|
||||
enabled: !Theme.springMotionDisabled
|
||||
stiffness: root.morphSpring.stiffness
|
||||
damping: root.morphSpring.damping
|
||||
}
|
||||
|
||||
Column {
|
||||
id: body
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Theme.buttonHeightM
|
||||
|
||||
MorphShape {
|
||||
id: badge
|
||||
width: parent.height
|
||||
height: width
|
||||
fromShape: root.shape
|
||||
toShape: root.hoverShape
|
||||
progress: morphMotion.value
|
||||
color: root.accentPair?.container ?? Theme.primaryContainer
|
||||
}
|
||||
|
||||
DIcon {
|
||||
anchors.centerIn: badge
|
||||
name: root.iconName
|
||||
size: Theme.iconSize
|
||||
color: root.accentPair?.onContainer ?? Theme.onPrimaryContainer
|
||||
}
|
||||
|
||||
DIcon {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
name: "arrow_outward"
|
||||
size: Theme.iconSizeMedium
|
||||
color: root.engaged ? Theme.primary : Theme.surfaceVariantText
|
||||
rotation: I18n.isRtl ? -90 : 0
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: root.heading
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Theme.fontWeightBold
|
||||
color: Theme.surfaceText
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import "../DCommon/Widgets/MaterialShapes.js" as Shapes
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
import qs.Common
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string fromShape: "circle"
|
||||
property string toShape: "circle"
|
||||
property color color: Theme.primary
|
||||
property real progress: 0
|
||||
|
||||
readonly property int samples: 128
|
||||
readonly property real clampedProgress: Math.max(0, Math.min(1, progress))
|
||||
readonly property bool morphing: clampedProgress > 0 && clampedProgress < 1 && Theme.shapeScale !== 0
|
||||
readonly property var fromProfile: Shapes.polarProfile(fromShape, samples)
|
||||
readonly property var toProfile: Shapes.polarProfile(toShape, samples)
|
||||
readonly property var outline: {
|
||||
if (!morphing)
|
||||
return [];
|
||||
const size = Math.min(width, height);
|
||||
const points = [];
|
||||
for (let i = 0; i <= samples; i++) {
|
||||
const index = i % samples;
|
||||
const angle = -Math.PI + 2 * Math.PI * index / samples;
|
||||
const radius = (fromProfile[index] + (toProfile[index] - fromProfile[index]) * clampedProgress) * size;
|
||||
points.push(Qt.point(width / 2 + Math.cos(angle) * radius, height / 2 + Math.sin(angle) * radius));
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
DMaterialShape {
|
||||
anchors.fill: parent
|
||||
shape: root.clampedProgress >= 1 ? root.toShape : root.fromShape
|
||||
color: root.color
|
||||
visible: !root.morphing
|
||||
}
|
||||
|
||||
Shape {
|
||||
anchors.fill: parent
|
||||
visible: root.morphing
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
|
||||
ShapePath {
|
||||
strokeColor: "transparent"
|
||||
strokeWidth: 0
|
||||
fillColor: root.color
|
||||
|
||||
PathPolyline {
|
||||
path: root.outline
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import QtQuick
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.DCommon.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
default property alias content: contentColumn.data
|
||||
property real paddingV: Theme.spacingXL + Theme.spacingS
|
||||
property real accentSize: Theme.buttonHeightM * 1.6
|
||||
property Component backdrop: defaultBackdrop
|
||||
|
||||
readonly property real availableWidth: width - Theme.spacingXL * 2
|
||||
|
||||
height: contentColumn.implicitHeight + paddingV * 2
|
||||
|
||||
component Decoration: DMaterialShape {
|
||||
respectThemeShape: false
|
||||
}
|
||||
|
||||
Component {
|
||||
id: defaultBackdrop
|
||||
|
||||
Item {
|
||||
Decoration {
|
||||
width: root.height * 1.15
|
||||
height: width
|
||||
x: parent.width - width * 0.62
|
||||
y: -height * 0.42
|
||||
shape: "cookie12"
|
||||
color: Theme.withAlpha(Theme.primary, Theme.tonalTintAlpha)
|
||||
rotation: 12
|
||||
}
|
||||
|
||||
Decoration {
|
||||
width: root.height * 0.8
|
||||
height: width
|
||||
x: -width * 0.38
|
||||
y: parent.height - height * 0.58
|
||||
shape: "softBurst"
|
||||
color: Theme.withAlpha(Theme.tertiary, Theme.tonalTintAlpha)
|
||||
rotation: -8
|
||||
}
|
||||
|
||||
Decoration {
|
||||
width: root.accentSize * 0.6
|
||||
height: width
|
||||
x: parent.width * 0.12
|
||||
y: root.paddingV * 0.6
|
||||
shape: "flower"
|
||||
color: Theme.withAlpha(Theme.onPrimaryContainer, Theme.stateLayerHover)
|
||||
}
|
||||
|
||||
Decoration {
|
||||
width: root.accentSize * 0.75
|
||||
height: width
|
||||
x: parent.width * 0.8
|
||||
y: parent.height - height - root.paddingV * 0.5
|
||||
shape: "pill"
|
||||
color: Theme.withAlpha(Theme.secondary, Theme.tonalTintAlpha)
|
||||
rotation: -40
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClippingRectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadiusXL
|
||||
color: Theme.primaryContainer
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.backdrop
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
anchors.centerIn: parent
|
||||
width: root.availableWidth
|
||||
spacing: Theme.spacingM
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user