mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
changelog: capability to display new release message
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
246
quickshell/Modals/Changelog/ChangelogContent.qml
Normal file
246
quickshell/Modals/Changelog/ChangelogContent.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
78
quickshell/Modals/Changelog/ChangelogFeatureCard.qml
Normal file
78
quickshell/Modals/Changelog/ChangelogFeatureCard.qml
Normal 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()
|
||||
}
|
||||
}
|
||||
155
quickshell/Modals/Changelog/ChangelogModal.qml
Normal file
155
quickshell/Modals/Changelog/ChangelogModal.qml
Normal 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;
|
||||
}
|
||||
}
|
||||
27
quickshell/Modals/Changelog/ChangelogUpgradeNote.qml
Normal file
27
quickshell/Modals/Changelog/ChangelogUpgradeNote.qml
Normal 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
|
||||
}
|
||||
}
|
||||
90
quickshell/Services/ChangelogService.qml
Normal file
90
quickshell/Services/ChangelogService.qml
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user