1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-01 19:18:28 -04:00

Squashed commit of the following:

commit 990d86d481
Author: bbedward <bbedward@gmail.com>
Date:   Sat Jul 18 10:43:22 2026 -0400

    flake: update-common

commit 526cb157fd
Author: bbedward <bbedward@gmail.com>
Date:   Thu Jul 16 17:56:40 2026 -0400

    i18n: update sync scrirpt for dank-qml-common

commit 92ba96d9f9
Author: bbedward <bbedward@gmail.com>
Date:   Thu Jul 16 09:24:37 2026 -0400

    qs: integrate with dank-qml-common
This commit is contained in:
bbedward
2026-07-18 10:44:31 -04:00
parent 5dfd875b9e
commit 235f0668b8
128 changed files with 577 additions and 14706 deletions
+5 -60
View File
@@ -1,66 +1,11 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.DankCommon.Common as DankCommon
Singleton {
id: root
readonly property Rounding rounding: Rounding {}
readonly property Spacing spacing: Spacing {}
readonly property FontSize fontSize: FontSize {}
readonly property Anim anim: Anim {}
component Rounding: QtObject {
readonly property int small: 8
readonly property int normal: 12
readonly property int large: 16
readonly property int extraLarge: 24
readonly property int full: 1000
}
component Spacing: QtObject {
readonly property int small: 4
readonly property int normal: 8
readonly property int large: 12
readonly property int extraLarge: 16
readonly property int huge: 24
}
component FontSize: QtObject {
readonly property int small: 12
readonly property int normal: 14
readonly property int large: 16
readonly property int extraLarge: 20
readonly property int huge: 24
}
component AnimCurves: QtObject {
readonly property list<real> standard: [0.2, 0, 0, 1, 1, 1]
readonly property list<real> standardAccel: [0.3, 0, 1, 1, 1, 1]
readonly property list<real> standardDecel: [0, 0, 0, 1, 1, 1]
readonly property list<real> emphasized: [0.05, 0, 2 / 15, 0.06, 1
/ 6, 0.4, 5 / 24, 0.82, 0.25, 1, 1, 1]
readonly property list<real> emphasizedAccel: [0.3, 0, 0.8, 0.15, 1, 1]
readonly property list<real> emphasizedDecel: [0.05, 0.7, 0.1, 1, 1, 1]
readonly property list<real> expressiveFastSpatial: [0.42, 1.67, 0.21, 0.9, 1, 1]
readonly property list<real> expressiveDefaultSpatial: [0.38, 1.21, 0.22, 1, 1, 1]
readonly property list<real> expressiveEffects: [0.34, 0.8, 0.34, 1, 1, 1]
}
component AnimDurations: QtObject {
readonly property int quick: 150
readonly property int normal: 300
readonly property int slow: 500
readonly property int extraSlow: 1000
readonly property int expressiveFastSpatial: 350
readonly property int expressiveDefaultSpatial: 500
readonly property int expressiveEffects: 200
}
component Anim: QtObject {
readonly property AnimCurves curves: AnimCurves {}
readonly property AnimDurations durations: AnimDurations {}
}
readonly property var rounding: DankCommon.Appearance.rounding
readonly property var spacing: DankCommon.Appearance.spacing
readonly property var fontSize: DankCommon.Appearance.fontSize
readonly property var anim: DankCommon.Appearance.anim
}
+2 -8
View File
@@ -1,9 +1,3 @@
import QtQuick
import qs.Common
import qs.DankCommon.Common as DankCommon
// Reusable NumberAnimation wrapper
NumberAnimation {
duration: Theme.expressiveDurations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.expressiveCurves.standard
}
DankCommon.DankAnim {}
+2 -8
View File
@@ -1,9 +1,3 @@
import QtQuick
import qs.Common
import qs.DankCommon.Common as DankCommon
// Reusable ColorAnimation wrapper
ColorAnimation {
duration: Theme.expressiveDurations.normal
easing.type: Easing.BezierSpline
easing.bezierCurve: Theme.expressiveCurves.standard
}
DankCommon.DankColorAnim {}
+2 -63
View File
@@ -1,64 +1,3 @@
import QtQuick
import Quickshell.Io
import qs.DankCommon.Common as DankCommon
Item {
id: root
property alias path: socket.path
property alias parser: socket.parser
property bool connected: false
property bool linkUp: false
property int reconnectBaseMs: 400
property int reconnectMaxMs: 15000
property int _reconnectAttempt: 0
signal connectionStateChanged
onConnectedChanged: {
socket.connected = connected;
}
Socket {
id: socket
onConnectionStateChanged: {
root.linkUp = connected;
root.connectionStateChanged();
if (connected) {
root._reconnectAttempt = 0;
return;
}
if (root.connected) {
root._scheduleReconnect();
}
}
}
Timer {
id: reconnectTimer
interval: 0
repeat: false
onTriggered: {
socket.connected = false;
Qt.callLater(() => socket.connected = true);
}
}
function send(data) {
const json = typeof data === "string" ? data : JSON.stringify(data);
const message = json.endsWith("\n") ? json : json + "\n";
socket.write(message);
socket.flush();
}
function _scheduleReconnect() {
const pow = Math.min(_reconnectAttempt, 10);
const base = Math.min(reconnectBaseMs * Math.pow(2, pow), reconnectMaxMs);
const jitter = Math.floor(Math.random() * Math.floor(base / 4));
reconnectTimer.interval = base + jitter;
reconnectTimer.restart();
_reconnectAttempt++;
}
}
DankCommon.DankSocket {}
+2 -53
View File
@@ -1,54 +1,3 @@
pragma ComponentBehavior: Bound
import qs.DankCommon.Common as DankCommon
import QtQuick
import qs.Common
Item {
id: root
property var level: Theme.elevationLevel2
property string direction: Theme.elevationLightDirection
property real fallbackOffset: 4
property color targetColor: "white"
property real targetRadius: Theme.cornerRadius
property real topLeftRadius: targetRadius
property real topRightRadius: targetRadius
property real bottomLeftRadius: targetRadius
property real bottomRightRadius: targetRadius
property color borderColor: "transparent"
property real borderWidth: 0
property real sourceX: 0
property real sourceY: 0
property real sourceWidth: width
property real sourceHeight: height
property bool shadowEnabled: Theme.elevationEnabled
property real shadowBlurPx: level && level.blurPx !== undefined ? level.blurPx : 0
property real shadowSpreadPx: level && level.spreadPx !== undefined ? level.spreadPx : 0
property real shadowOffsetX: Theme.elevationOffsetXFor(level, direction, fallbackOffset)
property real shadowOffsetY: Theme.elevationOffsetYFor(level, direction, fallbackOffset)
property color shadowColor: Theme.elevationShadowColor(level)
property real shadowOpacity: 1
readonly property var _ambient: Theme.elevationAmbient(level)
readonly property real _pad: shadowEnabled ? Math.ceil(Math.max(shadowBlurPx + shadowSpreadPx + Math.max(Math.abs(shadowOffsetX), Math.abs(shadowOffsetY)), _ambient.blurPx + _ambient.spreadPx) + 2) : 0
ShaderEffect {
anchors.fill: parent
anchors.margins: -root._pad
fragmentShader: Qt.resolvedUrl("../Shaders/qsb/elevation_rect.frag.qsb")
property real widthPx: width
property real heightPx: height
property real borderWidth: root.borderWidth
property vector4d rectPx: Qt.vector4d(root._pad + root.sourceX, root._pad + root.sourceY, root.sourceWidth, root.sourceHeight)
property vector4d cornerRadius: Qt.vector4d(root.topLeftRadius, root.topRightRadius, root.bottomRightRadius, root.bottomLeftRadius)
property vector4d fillColor: Qt.vector4d(root.targetColor.r, root.targetColor.g, root.targetColor.b, root.targetColor.a)
property vector4d borderColor: Qt.vector4d(root.borderColor.r, root.borderColor.g, root.borderColor.b, root.borderColor.a)
property vector4d shadowColor: Qt.vector4d(root.shadowColor.r, root.shadowColor.g, root.shadowColor.b, root.shadowEnabled ? root.shadowColor.a * root.shadowOpacity : 0)
property vector4d shadowParam: Qt.vector4d(Math.max(0, root.shadowBlurPx), root.shadowSpreadPx, root.shadowOffsetX, root.shadowOffsetY)
property vector4d ambientParam: Qt.vector4d(root._ambient.blurPx, root._ambient.spreadPx, root.shadowEnabled ? root._ambient.alpha * root.shadowOpacity : 0, 0)
}
}
DankCommon.ElevationShadow {}
+73 -12
View File
@@ -25,6 +25,7 @@ Singleton {
readonly property bool isRtl: _rtlLanguages.includes(_lang)
readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports")
readonly property url commonTranslationsFolder: Qt.resolvedUrl("../DankCommon/translations/poexports")
readonly property alias folder: dir.folder
property var presentLocales: ({
@@ -32,8 +33,11 @@ Singleton {
})
property var translations: ({})
property bool translationsLoaded: false
property var commonTranslations: ({})
property bool commonTranslationsLoaded: false
property url _selectedPath: ""
property url _commonSelectedPath: ""
FolderListModel {
id: dir
@@ -48,6 +52,18 @@ Singleton {
}
}
FolderListModel {
id: commonDir
folder: root.commonTranslationsFolder
nameFilters: ["*.json"]
showDirs: false
showDotAndDotDot: false
onStatusChanged: if (status === FolderListModel.Ready) {
root._pickCommonTranslation();
}
}
FileView {
id: translationLoader
path: root._selectedPath
@@ -69,6 +85,22 @@ Singleton {
}
}
FileView {
id: commonTranslationLoader
path: root._commonSelectedPath
printErrors: false
onLoaded: {
try {
root.commonTranslations = JSON.parse(text());
root.commonTranslationsLoaded = true;
log.info(`I18n: Loaded DankCommon translations (${Object.keys(root.commonTranslations).length} contexts)`);
} catch (e) {
log.warn("I18n: Error parsing DankCommon translations:", e);
}
}
}
function locale() {
if (SessionData.timeLocale)
return Qt.locale(SessionData.timeLocale);
@@ -117,29 +149,58 @@ Singleton {
log.warn("Falling back to built-in English strings");
}
function _pickCommonTranslation() {
const present = {};
for (let i = 0; i < commonDir.count; i++) {
const name = commonDir.get(i, "fileName");
if (name && name.endsWith(".json"))
present[name.slice(0, -5)] = true;
}
for (let i = 0; i < _candidates.length; i++) {
if (!present[_candidates[i]])
continue;
_commonSelectedPath = commonTranslationsFolder + "/" + _candidates[i] + ".json";
return;
}
}
function _lookup(table, term, context) {
if (!table)
return "";
if (context && table[context] && table[context][term])
return table[context][term];
if (table[term] && table[term][term])
return table[term][term];
for (const c in table) {
if (table[c] && table[c][term])
return table[c][term];
}
return "";
}
// isRealContext is consumed by translations/extract_translations.py only:
// pass a literal `true` (same line) to give (term, context) its own POEditor
// translation slot. Lookup ignores it -- a real context exists as a bucket
// in the export, a comment-only context does not.
function tr(term, context, isRealContext) {
if (!translationsLoaded || !translations)
return term;
if (context && translations[context] && translations[context][term])
return translations[context][term];
if (translations[term] && translations[term][term])
return translations[term][term];
for (const c in translations) {
if (translations[c] && translations[c][term])
return translations[c][term];
if (translationsLoaded) {
const hit = _lookup(translations, term, context);
if (hit)
return hit;
}
if (commonTranslationsLoaded) {
const hit = _lookup(commonTranslations, term, context);
if (hit)
return hit;
}
return term;
}
function trContext(context, term) {
if (!translationsLoaded || !translations)
return term;
if (translations[context] && translations[context][term])
if (translationsLoaded && translations[context] && translations[context][term])
return translations[context][term];
if (commonTranslationsLoaded && commonTranslations[context] && commonTranslations[context][term])
return commonTranslations[context][term];
return term;
}
}
+6 -65
View File
@@ -1,72 +1,13 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import qs.Common
import qs.DankCommon.Common as DankCommon
// Reusable ListView/GridView transitions
Singleton {
id: root
// 0ms ViewTransitions break ListView delegate cleanup, so null the set when the shortest
// duration truncates to 0. Keep this gate - don't inline these back into add/remove/etc.
readonly property bool enabled: Math.floor(Theme.currentAnimationBaseDuration * 0.4) >= 1
readonly property Transition add: enabled ? _add : null
readonly property Transition remove: null
readonly property Transition displaced: enabled ? _displaced : null
readonly property Transition move: enabled ? _move : null
readonly property int _staggerMs: Math.round(Theme.currentAnimationBaseDuration * 0.03)
readonly property int _staggerCap: 8
readonly property Transition _add: Transition {
id: addTransition
SequentialAnimation {
PropertyAction {
property: "opacity"
value: 0
}
PauseAnimation {
duration: Math.max(0, Math.min(addTransition.ViewTransition.index - (addTransition.ViewTransition.targetIndexes[0] ?? 0), root._staggerCap)) * root._staggerMs
}
DankAnim {
property: "opacity"
from: 0
to: 1
duration: Theme.expressiveDurations.fast
easing.bezierCurve: Theme.expressiveCurves.emphasizedDecel
}
}
}
readonly property Transition _displaced: Transition {
DankAnim {
property: "y"
duration: Theme.expressiveDurations.fast
easing.bezierCurve: Theme.expressiveCurves.standard
}
DankAnim {
property: "opacity"
to: 1
duration: Theme.expressiveDurations.fast
easing.bezierCurve: Theme.expressiveCurves.standard
}
}
readonly property Transition _move: Transition {
DankAnim {
property: "y"
duration: Theme.expressiveDurations.fast
easing.bezierCurve: Theme.expressiveCurves.standard
}
DankAnim {
property: "opacity"
to: 1
duration: Theme.expressiveDurations.fast
easing.bezierCurve: Theme.expressiveCurves.standard
}
}
readonly property bool enabled: DankCommon.ListViewTransitions.enabled
readonly property Transition add: DankCommon.ListViewTransitions.add
readonly property Transition remove: DankCommon.ListViewTransitions.remove
readonly property Transition displaced: DankCommon.ListViewTransitions.displaced
readonly property Transition move: DankCommon.ListViewTransitions.move
}
+8
View File
@@ -108,6 +108,14 @@ Singleton {
return themedIconPath(iconName) || DesktopService.resolveIconPath(iconName);
}
function trashPath(path: string, callback): void {
TrashService.trashPath(path, callback);
}
function copyPathToClipboard(path: string): void {
Quickshell.execDetached([Proc.dmsBin, "cl", "copy", path]);
}
function resolveIconUrl(iconName: string): string {
if (!iconName)
return "";
+4 -148
View File
@@ -1,157 +1,13 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Services
import qs.DankCommon.Common as DankCommon
Singleton {
id: root
readonly property var log: Log.scoped("Proc")
readonly property int noTimeout: -1
readonly property string dmsBin: Quickshell.env("DMS_EXECUTABLE") || "dms"
property int defaultDebounceMs: 50
property int defaultTimeoutMs: 10000
property var _procDebouncers: ({})
readonly property int noTimeout: DankCommon.Proc.noTimeout
readonly property string dmsBin: DankCommon.Proc.dmsBin
function runCommand(id, command, callback, debounceMs, timeoutMs) {
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs;
const timeout = (typeof timeoutMs === "number") ? timeoutMs : defaultTimeoutMs;
let procId = id ? id : Math.random();
const isRandomId = !id;
if (!_procDebouncers[procId]) {
const t = debounceTimerComp.createObject(root);
t.triggered.connect(function () {
_launchProc(procId, isRandomId);
});
_procDebouncers[procId] = {
timer: t,
command: command,
callback: callback,
waitMs: wait,
timeoutMs: timeout,
isRandomId: isRandomId
};
} else {
_procDebouncers[procId].command = command;
_procDebouncers[procId].callback = callback;
_procDebouncers[procId].waitMs = wait;
_procDebouncers[procId].timeoutMs = timeout;
}
const entry = _procDebouncers[procId];
entry.timer.interval = entry.waitMs;
entry.timer.restart();
}
function _launchProc(id, isRandomId) {
const entry = _procDebouncers[id];
if (!entry)
return;
const proc = procComp.createObject(root, {
command: entry.command
});
const timeoutTimer = debounceTimerComp.createObject(root);
let capturedOut = "";
let capturedErr = "";
let exitSeen = false;
let exitCodeValue = -1;
let outSeen = false;
let errSeen = false;
let timedOut = false;
timeoutTimer.interval = entry.timeoutMs;
timeoutTimer.triggered.connect(function () {
if (!exitSeen) {
timedOut = true;
proc.running = false;
exitSeen = true;
exitCodeValue = 124;
maybeComplete();
}
});
proc.stdout.streamFinished.connect(function () {
try {
capturedOut = proc.stdout.text || "";
} catch (e) {
capturedOut = "";
}
outSeen = true;
maybeComplete();
});
proc.stderr.streamFinished.connect(function () {
try {
capturedErr = proc.stderr.text || "";
} catch (e) {
capturedErr = "";
}
errSeen = true;
maybeComplete();
});
proc.exited.connect(function (code) {
timeoutTimer.stop();
exitSeen = true;
exitCodeValue = code;
maybeComplete();
});
function maybeComplete() {
if (!exitSeen || !outSeen || !errSeen)
return;
timeoutTimer.stop();
if (entry && entry.callback && typeof entry.callback === "function") {
try {
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : "";
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1;
entry.callback(safeOutput, safeExitCode);
} catch (e) {
log.warn("runCommand callback error for command:", entry.command, "Error:", e);
}
}
try {
proc.destroy();
} catch (_) {}
try {
timeoutTimer.destroy();
} catch (_) {}
if (isRandomId || entry.isRandomId) {
Qt.callLater(function () {
if (_procDebouncers[id]) {
try {
_procDebouncers[id].timer.destroy();
} catch (_) {}
delete _procDebouncers[id];
}
});
}
}
proc.running = true;
if (entry.timeoutMs !== noTimeout)
timeoutTimer.start();
}
Component {
id: debounceTimerComp
Timer {
repeat: false
}
}
Component {
id: procComp
Process {
running: false
stdout: StdioCollector {}
stderr: StdioCollector {}
}
DankCommon.Proc.runCommand(id, command, callback, debounceMs, timeoutMs);
}
}
+17 -4
View File
@@ -6,6 +6,7 @@ import QtQuick
import Quickshell
import Quickshell.Io
import qs.Common
import qs.DankCommon.Common as DankCommon
import qs.Services
import qs.Modules.Greetd
import "StockThemes.js" as StockThemes
@@ -1230,16 +1231,28 @@ Singleton {
property string fontFamily: {
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") {
return GreetdSettings.getEffectiveFontFamily();
return resolvedFontFamily(GreetdSettings.getEffectiveFontFamily());
}
return typeof SettingsData !== "undefined" ? SettingsData.fontFamily : "Inter Variable";
return typeof SettingsData !== "undefined" ? resolvedFontFamily(SettingsData.fontFamily) : DankCommon.Fonts.sans;
}
property string monoFontFamily: {
if (typeof SessionData !== "undefined" && SessionData.isGreeterMode && typeof GreetdSettings !== "undefined") {
return GreetdSettings.monoFontFamily;
return resolvedMonoFontFamily(GreetdSettings.monoFontFamily);
}
return typeof SettingsData !== "undefined" ? SettingsData.monoFontFamily : "Fira Code";
return typeof SettingsData !== "undefined" ? resolvedMonoFontFamily(SettingsData.monoFontFamily) : DankCommon.Fonts.mono;
}
function resolvedFontFamily(family) {
if (family === defaultFontFamily)
return DankCommon.Fonts.sans;
return family;
}
function resolvedMonoFontFamily(family) {
if (family === defaultMonoFontFamily)
return DankCommon.Fonts.mono;
return family;
}
property int fontWeight: {
File diff suppressed because it is too large Load Diff