1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-25 05:52:50 -05:00

changelog: capability to display new release message

This commit is contained in:
bbedward
2026-01-07 20:15:50 -05:00
parent 646d60dcbf
commit a5e107c89d
6 changed files with 619 additions and 2 deletions

View File

@@ -2,6 +2,7 @@ import QtQuick
import Quickshell
import qs.Common
import qs.Modals
import qs.Modals.Changelog
import qs.Modals.Clipboard
import qs.Modals.Greeter
import qs.Modals.Settings
@@ -836,9 +837,29 @@ Item {
function onGreeterRequested() {
if (greeterLoader.active && greeterLoader.item) {
greeterLoader.item.show();
} else {
greeterLoader.active = true;
return;
}
greeterLoader.active = true;
}
}
}
Loader {
id: changelogLoader
active: false
sourceComponent: ChangelogModal {
onChangelogDismissed: changelogLoader.active = false
Component.onCompleted: show()
}
Connections {
target: ChangelogService
function onChangelogRequested() {
if (changelogLoader.active && changelogLoader.item) {
changelogLoader.item.show();
return;
}
changelogLoader.active = true;
}
}
}

View File

@@ -0,0 +1,246 @@
import QtQuick
import QtQuick.Effects
import qs.Common
import qs.Services
import qs.Widgets
Column {
id: root
readonly property real logoSize: Math.round(Theme.iconSize * 2.8)
readonly property real badgeHeight: Math.round(Theme.fontSizeSmall * 1.7)
topPadding: Theme.spacingL
spacing: Theme.spacingL
Column {
width: parent.width
spacing: Theme.spacingM
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
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
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
Row {
spacing: Theme.spacingS
StyledText {
text: "DMS " + ChangelogService.currentVersion
font.pixelSize: Theme.fontSizeXLarge + 2
font.weight: Font.Bold
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: codenameText.implicitWidth + Theme.spacingM * 2
height: root.badgeHeight
radius: root.badgeHeight / 2
color: Theme.primaryContainer
anchors.verticalCenter: parent.verticalCenter
StyledText {
id: codenameText
anchors.centerIn: parent
text: "Spicy Miso"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.primary
}
}
}
StyledText {
text: "Desktop widgets, theme registry, native clipboard & more"
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: Font.Medium
color: Theme.surfaceText
}
Grid {
width: parent.width
columns: 2
rowSpacing: Theme.spacingS
columnSpacing: Theme.spacingS
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "widgets"
title: "Desktop Widgets"
description: "Widgets on your desktop"
onClicked: PopoutService.openSettingsWithTab("desktop_widgets")
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "palette"
title: "Theme Registry"
description: "Community themes"
onClicked: PopoutService.openSettingsWithTab("theme")
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "content_paste"
title: "Native Clipboard"
description: "Zero-dependency history"
onClicked: PopoutService.openSettingsWithTab("clipboard")
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "display_settings"
title: "Monitor Config"
description: "Full display setup"
onClicked: PopoutService.openSettingsWithTab("display_config")
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "notifications_active"
title: "Notifications"
description: "History & gestures"
onClicked: PopoutService.openSettingsWithTab("notifications")
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "healing"
title: "DMS Doctor"
description: "Diagnose issues"
onClicked: FirstLaunchService.showDoctor()
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "keyboard"
title: "Keybinds Editor"
description: "niri, Hyprland, & MangoWC"
visible: KeybindsService.available
onClicked: PopoutService.openSettingsWithTab("keybinds")
}
ChangelogFeatureCard {
width: (parent.width - Theme.spacingS) / 2
iconName: "search"
title: "Settings Search"
description: "Find settings fast"
onClicked: PopoutService.openSettingsWithTab("general")
}
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outlineMedium
opacity: 0.3
}
Column {
width: parent.width
spacing: Theme.spacingS
Row {
spacing: Theme.spacingS
DankIcon {
name: "warning"
size: Theme.iconSizeSmall
color: Theme.warning
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: "Upgrade Notes"
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
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: "Ghostty theme path changed to ~/.config/ghostty/themes/danktheme"
}
ChangelogUpgradeNote {
width: parent.width
text: "VS Code theme reinstall required"
}
ChangelogUpgradeNote {
width: parent.width
text: "Clipboard history migration available from cliphist"
}
}
}
StyledText {
text: "See full release notes for migration steps"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
}
}
}

View File

@@ -0,0 +1,78 @@
import QtQuick
import qs.Common
import qs.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.surfaceContainerHigh
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
DankIcon {
anchors.centerIn: parent
name: root.iconName
size: Theme.iconSize - 6
color: Theme.primary
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - root.iconContainerSize - Theme.spacingS
StyledText {
text: root.title
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
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()
}
}

View File

@@ -0,0 +1,155 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Services
import qs.Widgets
FloatingWindow {
id: root
readonly property int modalWidth: 680
readonly property int modalHeight: screen ? Math.min(720, screen.height - 80) : 720
signal changelogDismissed
function show() {
visible = true;
}
objectName: "changelogModal"
title: "What's New"
minimumSize: Qt.size(modalWidth, modalHeight)
maximumSize: Qt.size(modalWidth, modalHeight)
color: Theme.surfaceContainer
visible: false
FocusScope {
id: contentFocusScope
anchors.fill: parent
focus: true
Keys.onEscapePressed: event => {
root.dismiss();
event.accepted = true;
}
Keys.onPressed: event => {
switch (event.key) {
case Qt.Key_Return:
case Qt.Key_Enter:
root.dismiss();
event.accepted = true;
break;
}
}
MouseArea {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: headerRow.height + Theme.spacingM
onPressed: windowControls.tryStartMove()
onDoubleClicked: windowControls.tryToggleMaximize()
}
Item {
id: headerRow
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Theme.spacingM
height: Math.round(Theme.fontSizeMedium * 2.85)
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
DankActionButton {
visible: windowControls.supported && windowControls.canMaximize
iconName: root.maximized ? "fullscreen_exit" : "fullscreen"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: windowControls.tryToggleMaximize()
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: root.dismiss()
DankTooltip {
text: "Close"
}
}
}
}
DankFlickable {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: headerRow.bottom
anchors.bottom: footerRow.top
anchors.topMargin: Theme.spacingS
clip: true
contentHeight: mainColumn.height + Theme.spacingL * 2
contentWidth: width
ChangelogContent {
id: mainColumn
anchors.horizontalCenter: parent.horizontalCenter
width: Math.min(600, parent.width - Theme.spacingXL * 2)
}
}
Rectangle {
id: footerRow
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: Math.round(Theme.fontSizeMedium * 4.5)
color: Theme.surfaceContainerHigh
Rectangle {
anchors.top: parent.top
width: parent.width
height: 1
color: Theme.outlineMedium
opacity: 0.5
}
Row {
anchors.centerIn: parent
spacing: Theme.spacingM
DankButton {
text: "Read Full Release Notes"
iconName: "open_in_new"
backgroundColor: Theme.surfaceContainerHighest
textColor: Theme.surfaceText
onClicked: Qt.openUrlExternally("https://danklinux.com/blog/dms-1-2-spicy-miso")
}
DankButton {
text: "Got It"
iconName: "check"
backgroundColor: Theme.primary
textColor: Theme.primaryText
onClicked: root.dismiss()
}
}
}
}
FloatingWindowControls {
id: windowControls
targetWindow: root
}
function dismiss() {
ChangelogService.dismissChangelog();
changelogDismissed();
visible = false;
}
}

View File

@@ -0,0 +1,27 @@
import QtQuick
import qs.Common
import qs.Widgets
Row {
id: root
property alias text: noteText.text
spacing: Theme.spacingS
DankIcon {
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
}
}

View File

@@ -0,0 +1,90 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtCore
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
Singleton {
id: root
readonly property string currentVersion: "1.2"
readonly property bool changelogEnabled: false
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion
property bool checkComplete: false
property bool changelogDismissed: false
readonly property bool shouldShowChangelog: {
if (!checkComplete)
return false;
if (!changelogEnabled)
return false;
if (changelogDismissed)
return false;
if (typeof FirstLaunchService !== "undefined" && FirstLaunchService.isFirstLaunch)
return false;
return true;
}
signal changelogRequested
signal changelogCompleted
Component.onCompleted: {
if (!changelogEnabled)
return;
changelogCheckProcess.running = true;
}
function showChangelog() {
changelogRequested();
}
function dismissChangelog() {
changelogDismissed = true;
touchMarkerProcess.running = true;
changelogCompleted();
}
Process {
id: changelogCheckProcess
command: ["sh", "-c", "[ -f '" + changelogMarkerPath + "' ] && echo 'seen' || echo 'show'"]
running: false
stdout: SplitParser {
onRead: data => {
const result = data.trim();
root.checkComplete = true;
switch (result) {
case "seen":
root.changelogDismissed = true;
break;
case "show":
if (typeof FirstLaunchService === "undefined" || !FirstLaunchService.isFirstLaunch) {
root.changelogRequested();
}
break;
}
}
}
}
Process {
id: touchMarkerProcess
command: ["sh", "-c", "mkdir -p '" + configDir + "' && touch '" + changelogMarkerPath + "'"]
running: false
onExited: exitCode => {
if (exitCode !== 0) {
console.warn("ChangelogService: Failed to create changelog marker");
}
}
}
}