1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

Compare commits

...

27 Commits

Author SHA1 Message Date
bbedward
7a5d612599 File browser improvements 2025-10-17 21:36:09 -04:00
github-actions[bot]
205c43181b Update VERSION to v0.1.17 (from DMS) 2025-10-17 20:03:12 +00:00
purian23
05a72abf41 Update Copr Architecture logic 2025-10-17 15:39:09 -04:00
purian23
14262ba510 Silence upgrade noise 2025-10-17 11:05:54 -04:00
github-actions[bot]
d847b1e09c i18n: update translations 2025-10-17 12:48:01 +00:00
bbedward
0086e42a86 i18n: don't rely on po webhooks 2025-10-17 08:47:18 -04:00
bbedward
7474d5a7bf poeditor: disable workflow
They paywalled it even for open source
2025-10-17 08:42:56 -04:00
bbedward
5696a36115 ws: disable window scrolling toggle when not niri 2025-10-17 08:40:26 -04:00
maggster165
3cdc1a9c81 Add Workspace Indicator scrolling (#475) 2025-10-17 08:37:28 -04:00
Massimo Branchini
b095fb9005 small fix: initial space does not allow correct alignment (#477) 2025-10-17 08:37:18 -04:00
bbedward
ce6c16214c lock: allow custom lock command 2025-10-17 08:36:11 -04:00
bbedward
b6f7f2734e network: hide eth/wifi preference when apiVersion < 5 2025-10-17 08:23:56 -04:00
bbedward
4db55e4d77 Bump expected API back down, doesn't really matter 2025-10-17 08:17:16 -04:00
Massimo Branchini
b21f6e80b3 enhancement: managed NetworkManager ethernet configurations connectio… (#473)
* enhancement: managed NetworkManager ethernet configurations connection from control panel

* server API minimal version
2025-10-17 08:05:42 -04:00
bokicoder
a804fb849e Update readme (#471) 2025-10-17 07:01:12 -04:00
purian23
4ca91cd9f7 SELinux & Path DIR updates 2025-10-17 01:28:59 -04:00
purian23
16e1b587b4 Added logic for PAM users / SELinux 2025-10-16 23:56:25 -04:00
bbedward
5e2756d200 theme: don't need portal for light/dark 2025-10-16 23:38:13 -04:00
bbedward
ce9ab22ae1 notepad: use ref system for service 2025-10-16 23:01:48 -04:00
bbedward
72ad35e1f9 theme: don't depend on dms for gsettings theme mode 2025-10-16 22:58:49 -04:00
bbedward
c0d110cde0 controlcenter: fix trigger position via IPC 2025-10-16 22:03:02 -04:00
bbedward
b9d5deb2ae notifications: fix dnd tooltip & silence sounds on do not disturb 2025-10-16 21:30:45 -04:00
Nasser Alshammari
d4b13ef46b Dropbox icon workaround when DankBar is vertical (#466) 2025-10-16 21:22:15 -04:00
BB
748d9e342e Update translations/poexports/pt.json (POEditor.com) 2025-10-16 21:18:14 -04:00
purian23
f49312fc0e Update ReadMe 2025-10-16 21:17:54 -04:00
BB
e0d8bbb243 Update translations/poexports/pt.json (POEditor.com) 2025-10-16 19:59:55 -04:00
purian23
153f2a49f8 Update Copr Workflow 2025-10-16 19:59:29 -04:00
33 changed files with 8319 additions and 6700 deletions

View File

@@ -1,6 +1,9 @@
name: DMS Copr Stable Release
on:
push:
tags:
- 'v*'
release:
types: [published]
workflow_dispatch:
@@ -28,6 +31,10 @@ jobs:
VERSION="${{ github.event.release.tag_name }}"
VERSION="${VERSION#v}"
echo "Using release version: $VERSION"
elif [ "${{ github.event_name }}" = "push" ] && [[ "${{ github.ref }}" == refs/tags/* ]]; then
VERSION="${{ github.ref_name }}"
VERSION="${VERSION#v}"
echo "Using tag version: $VERSION"
else
# Fallback to latest release
VERSION=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | jq -r '.tag_name' | sed 's/^v//')
@@ -49,7 +56,7 @@ jobs:
VERSION="${{ steps.version.outputs.version }}"
cd ~/rpmbuild/SOURCES
echo "📦 Downloading DMS release assets for v${VERSION}..."
echo "📦 Downloading DMS QML source for v${VERSION}..."
# Download DMS QML source
wget "https://github.com/AvengeMedia/DankMaterialShell/releases/download/v${VERSION}/dms-qml.tar.gz" || {
@@ -57,21 +64,8 @@ jobs:
exit 1
}
# Download dms-cli (always use latest)
echo "📦 Downloading latest dms-cli..."
wget "https://github.com/AvengeMedia/danklinux/releases/latest/download/dms-distropkg-amd64.gz" || {
echo "❌ Failed to download dms-cli"
exit 1
}
# Download dgop (always use latest)
echo "📦 Downloading latest dgop..."
wget "https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-amd64.gz" || {
echo "❌ Failed to download dgop"
exit 1
}
echo "✅ All sources downloaded"
echo "✅ Source downloaded"
echo "Note: dms-cli and dgop binaries will be downloaded during build based on target architecture"
ls -lh
- name: Generate stable spec file
@@ -95,10 +89,9 @@ jobs:
URL: https://github.com/AvengeMedia/DankMaterialShell
Source0: dms-qml.tar.gz
Source1: dms-distropkg-amd64.gz
Source2: dgop-linux-amd64.gz
BuildRequires: gzip
BuildRequires: wget
Requires: (quickshell or quickshell-git)
Requires: dms-cli
@@ -150,10 +143,35 @@ jobs:
%prep
%setup -q -c -n dms-qml
gunzip -c %{SOURCE1} > %{_builddir}/dms-cli
# Download architecture-specific binaries during build
# This ensures the correct architecture is used for each build target
case "%{_arch}" in
x86_64)
ARCH_SUFFIX="amd64"
;;
aarch64)
ARCH_SUFFIX="arm64"
;;
*)
echo "Unsupported architecture: %{_arch}"
exit 1
;;
esac
# Download dms-cli for target architecture
wget -O %{_builddir}/dms-cli.gz "https://github.com/AvengeMedia/danklinux/releases/latest/download/dms-distropkg-${ARCH_SUFFIX}.gz" || {
echo "Failed to download dms-cli for architecture %{_arch}"
exit 1
}
gunzip -c %{_builddir}/dms-cli.gz > %{_builddir}/dms-cli
chmod +x %{_builddir}/dms-cli
gunzip -c %{SOURCE2} > %{_builddir}/dgop
# Download dgop for target architecture
wget -O %{_builddir}/dgop.gz "https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-${ARCH_SUFFIX}.gz" || {
echo "Failed to download dgop for architecture %{_arch}"
exit 1
}
gunzip -c %{_builddir}/dgop.gz > %{_builddir}/dgop
chmod +x %{_builddir}/dgop
%build

View File

@@ -10,106 +10,98 @@ concurrency:
cancel-in-progress: false
jobs:
diff-and-trigger:
sync-translations:
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- name: ja
po_lang: "ja"
repo_file: "translations/poexports/ja.json"
webhook_secret: "POEDITOR_WEBHOOK_JA"
- name: zh_hans
po_lang: "zh-Hans"
repo_file: "translations/poexports/zh_CN.json"
webhook_secret: "POEDITOR_WEBHOOK_ZH_HANS"
- name: pt
po_lang: "pt-br"
repo_file: "translations/poexports/pt.json"
webhook_secret: "POEDITOR_WEBHOOK_PT"
steps:
- uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Export from POEditor (key/value JSON) and compare
id: diffcheck
- name: Export and update translations from POEditor
env:
API_TOKEN: ${{ secrets.POEDITOR_API_TOKEN }}
PROJECT_ID: ${{ secrets.POEDITOR_PROJECT_ID }}
PO_LANG: ${{ matrix.po_lang }}
REPO_FILE: ${{ matrix.repo_file }}
run: |
set -euo pipefail
# 1) Request an export URL for key/value json
echo "::group::POEditor export request"
RESP=$(curl -sS -X POST https://api.poeditor.com/v2/projects/export \
-d api_token="$API_TOKEN" \
-d id="$PROJECT_ID" \
-d language="$PO_LANG" \
-d type="key_value_json")
echo "$RESP" | jq -r '.'
STATUS=$(echo "$RESP" | jq -r '.response.status')
if [[ "$STATUS" != "success" ]]; then
echo "POEditor export request failed: $RESP" >&2
exit 1
fi
URL=$(echo "$RESP" | jq -r '.result.url')
if [[ -z "$URL" || "$URL" == "null" ]]; then
echo "No export URL returned from POEditor." >&2
exit 1
fi
echo "::endgroup::"
LANGUAGES=(
"ja:translations/poexports/ja.json"
"zh-Hans:translations/poexports/zh_CN.json"
"pt-br:translations/poexports/pt.json"
)
# 2) Download exported content
curl -sS -L "$URL" -o /tmp/po_export.json
ANY_CHANGED=false
# 3) Normalize JSON (sorted keys) for stable diff
jq -S . /tmp/po_export.json > /tmp/po_export.norm.json
for lang_pair in "${LANGUAGES[@]}"; do
IFS=':' read -r PO_LANG REPO_FILE <<< "$lang_pair"
# 4) Normalize repo file (or empty {}) and diff
if [[ -f "$REPO_FILE" ]]; then
jq -S . "$REPO_FILE" > /tmp/repo.norm.json || echo "{}" > /tmp/repo.norm.json
else
echo "{}" > /tmp/repo.norm.json
fi
echo "::group::Processing $PO_LANG"
# 5) Set output changed=true|false
if diff -q /tmp/po_export.norm.json /tmp/repo.norm.json >/dev/null; then
echo "changed=false" >> "$GITHUB_OUTPUT"
echo "No changes for $PO_LANG"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
echo "Detected changes for $PO_LANG"
fi
RESP=$(curl -sS -X POST https://api.poeditor.com/v2/projects/export \
-d api_token="$API_TOKEN" \
-d id="$PROJECT_ID" \
-d language="$PO_LANG" \
-d type="key_value_json")
- name: Trigger POEditor webhook for this language, if changed
if: steps.diffcheck.outputs.changed == 'true'
env:
WEBHOOK_URL: ${{ secrets[matrix.webhook_secret] }}
STATUS=$(echo "$RESP" | jq -r '.response.status')
if [[ "$STATUS" != "success" ]]; then
echo "POEditor export request failed for $PO_LANG: $RESP" >&2
continue
fi
URL=$(echo "$RESP" | jq -r '.result.url')
if [[ -z "$URL" || "$URL" == "null" ]]; then
echo "No export URL returned for $PO_LANG" >&2
continue
fi
curl -sS -L "$URL" -o "/tmp/po_export_${PO_LANG}.json"
jq -S . "/tmp/po_export_${PO_LANG}.json" > "/tmp/po_export_${PO_LANG}.norm.json"
if [[ -f "$REPO_FILE" ]]; then
jq -S . "$REPO_FILE" > "/tmp/repo_${PO_LANG}.norm.json" || echo "{}" > "/tmp/repo_${PO_LANG}.norm.json"
else
echo "{}" > "/tmp/repo_${PO_LANG}.norm.json"
fi
if diff -q "/tmp/po_export_${PO_LANG}.norm.json" "/tmp/repo_${PO_LANG}.norm.json" >/dev/null; then
echo "No changes for $PO_LANG"
else
echo "Detected changes for $PO_LANG"
mkdir -p "$(dirname "$REPO_FILE")"
cp "/tmp/po_export_${PO_LANG}.norm.json" "$REPO_FILE"
ANY_CHANGED=true
fi
echo "::endgroup::"
done
echo "any_changed=$ANY_CHANGED" >> "$GITHUB_OUTPUT"
id: export
- name: Commit and push translation updates
if: steps.export.outputs.any_changed == 'true'
run: |
set -euo pipefail
if [[ -z "${WEBHOOK_URL:-}" ]]; then
echo "Missing webhook secret for this language: ${{ matrix.webhook_secret }}" >&2
exit 1
fi
echo "Calling POEditor export webhook for ${{ matrix.name }}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add translations/poexports/*.json
git commit -m "i18n: update translations"
for attempt in 1 2 3; do
code=$(curl -sS -o /tmp/resp.txt -w '%{http_code}' -X POST "$WEBHOOK_URL" || true)
if [[ "$code" == "200" || "$code" == "204" ]]; then
echo "Webhook OK ($code)"
if git push; then
echo "Successfully pushed translation updates"
exit 0
fi
echo "Attempt $attempt failed ($code) → $(cat /tmp/resp.txt)"
sleep $((attempt*3))
echo "Push attempt $attempt failed, pulling and retrying..."
git pull --rebase
sleep $((attempt*2))
done
echo "Webhook failed after retries." >&2
echo "Failed to push after retries" >&2
exit 1

View File

@@ -99,6 +99,7 @@ Singleton {
property bool showWorkspaceIndex: false
property bool showWorkspacePadding: false
property bool workspaceScrolling: false
property bool showWorkspaceApps: false
property int maxWorkspaceIcons: 3
property bool workspacesPerMonitor: true
@@ -238,6 +239,7 @@ Singleton {
property bool osdAlwaysShowValue: false
property bool powerActionConfirm: true
property string customPowerActionLock: ""
property string customPowerActionLogout: ""
property string customPowerActionSuspend: ""
property string customPowerActionHibernate: ""
@@ -361,6 +363,7 @@ Singleton {
]
showWorkspaceIndex = settings.showWorkspaceIndex !== undefined ? settings.showWorkspaceIndex : false
showWorkspacePadding = settings.showWorkspacePadding !== undefined ? settings.showWorkspacePadding : false
workspaceScrolling = settings.workspaceScrolling !== undefined ? settings.workspaceScrolling : false
showWorkspaceApps = settings.showWorkspaceApps !== undefined ? settings.showWorkspaceApps : false
maxWorkspaceIcons = settings.maxWorkspaceIcons !== undefined ? settings.maxWorkspaceIcons : 3
workspaceNameIcons = settings.workspaceNameIcons !== undefined ? settings.workspaceNameIcons : ({})
@@ -452,6 +455,7 @@ Singleton {
notificationPopupPosition = settings.notificationPopupPosition !== undefined ? settings.notificationPopupPosition : SettingsData.Position.Top
osdAlwaysShowValue = settings.osdAlwaysShowValue !== undefined ? settings.osdAlwaysShowValue : false
powerActionConfirm = settings.powerActionConfirm !== undefined ? settings.powerActionConfirm : true
customPowerActionLock = settings.customPowerActionLock != undefined ? settings.customPowerActionLock : ""
customPowerActionLogout = settings.customPowerActionLogout != undefined ? settings.customPowerActionLogout : ""
customPowerActionSuspend = settings.customPowerActionSuspend != undefined ? settings.customPowerActionSuspend : ""
customPowerActionHibernate = settings.customPowerActionHibernate != undefined ? settings.customPowerActionHibernate : ""
@@ -561,6 +565,7 @@ Singleton {
"controlCenterShowAudioIcon": controlCenterShowAudioIcon,
"controlCenterWidgets": controlCenterWidgets,
"showWorkspaceIndex": showWorkspaceIndex,
"workspaceScrolling": workspaceScrolling,
"showWorkspacePadding": showWorkspacePadding,
"showWorkspaceApps": showWorkspaceApps,
"maxWorkspaceIcons": maxWorkspaceIcons,
@@ -646,6 +651,7 @@ Singleton {
"notificationPopupPosition": notificationPopupPosition,
"osdAlwaysShowValue": osdAlwaysShowValue,
"powerActionConfirm": powerActionConfirm,
"customPowerActionLock": customPowerActionLock,
"customPowerActionLogout": customPowerActionLogout,
"customPowerActionSuspend": customPowerActionSuspend,
"customPowerActionHibernate": customPowerActionHibernate,
@@ -692,7 +698,7 @@ Singleton {
"selectedGpuIndex", "enabledGpuPciIds", "showSystemTray", "showClock",
"showNotificationButton", "showBattery", "showControlCenterButton",
"controlCenterShowNetworkIcon", "controlCenterShowBluetoothIcon", "controlCenterShowAudioIcon",
"controlCenterWidgets", "showWorkspaceIndex", "showWorkspacePadding", "showWorkspaceApps",
"controlCenterWidgets", "showWorkspaceIndex", "workspaceScrolling", "showWorkspacePadding", "showWorkspaceApps",
"maxWorkspaceIcons", "workspacesPerMonitor", "workspaceNameIcons", "waveProgressEnabled",
"clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode",
"runningAppsCurrentWorkspace", "clockDateFormat", "lockDateFormat", "mediaSize",
@@ -716,8 +722,8 @@ Singleton {
"hideBrightnessSlider", "widgetBackgroundColor", "surfaceBase",
"notificationTimeoutLow", "notificationTimeoutNormal", "notificationTimeoutCritical",
"notificationPopupPosition", "osdAlwaysShowValue", "powerActionConfirm",
"customPowerActionLogout", "customPowerActionSuspend", "customPowerActionHibernate",
"customPowerActionReboot", "customPowerActionPowerOff",
"customPowerActionLock", "customPowerActionLogout", "customPowerActionSuspend",
"customPowerActionHibernate", "customPowerActionReboot", "customPowerActionPowerOff",
"updaterUseCustomCommand", "updaterCustomCommand", "updaterTerminalAdditionalParams",
"screenPreferences", "animationSpeed", "acMonitorTimeout", "acLockTimeout",
"acSuspendTimeout", "acHibernateTimeout", "batteryMonitorTimeout", "batteryLockTimeout",
@@ -1155,6 +1161,11 @@ Singleton {
showWorkspaceIndex = enabled
saveSettings()
}
function setWorkspaceScrolling(enabled) {
workspaceScrolling = enabled
saveSettings()
}
function setShowWorkspacePadding(enabled) {
showWorkspacePadding = enabled
@@ -1713,6 +1724,11 @@ Singleton {
saveSettings();
}
function setCustomPowerActionLock(command) {
customPowerActionLock = command;
saveSettings();
}
function setCustomPowerActionLogout(command) {
customPowerActionLogout = command;
saveSettings();

View File

@@ -25,515 +25,517 @@ import qs.Modules.DankBar.Popouts
import qs.Modules.Plugins
import qs.Services
Item {
id: root
id: root
Instantiator {
id: daemonPluginInstantiator
asynchronous: true
model: Object.keys(PluginService.pluginDaemonComponents)
Instantiator {
id: daemonPluginInstantiator
asynchronous: true
model: Object.keys(PluginService.pluginDaemonComponents)
delegate: Loader {
id: daemonLoader
property string pluginId: modelData
sourceComponent: PluginService.pluginDaemonComponents[pluginId]
delegate: Loader {
id: daemonLoader
property string pluginId: modelData
sourceComponent: PluginService.pluginDaemonComponents[pluginId]
onLoaded: {
if (item) {
item.pluginService = PluginService
if (item.popoutService !== undefined) {
item.popoutService = PopoutService
}
item.pluginId = pluginId
console.log("Daemon plugin loaded:", pluginId)
}
}
}
}
WallpaperBackground {}
Lock {
id: lock
}
Loader {
id: dankBarLoader
asynchronous: false
property var currentPosition: SettingsData.dankBarPosition
property bool initialized: false
sourceComponent: DankBar {
onColorPickerRequested: {
if (colorPickerModal.shouldBeVisible) {
colorPickerModal.close()
} else {
colorPickerModal.show()
}
}
}
Component.onCompleted: {
initialized = true
}
onCurrentPositionChanged: {
if (!initialized) return
const component = sourceComponent
sourceComponent = null
sourceComponent = component
}
}
Loader {
id: dockLoader
active: true
asynchronous: false
property var currentPosition: SettingsData.dockPosition
property bool initialized: false
sourceComponent: Dock {
contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null
}
onLoaded: {
if (item) {
dockContextMenuLoader.active = true
}
}
Component.onCompleted: {
initialized = true
}
onCurrentPositionChanged: {
if (!initialized) return
console.log("DEBUG: Dock position changed to:", currentPosition, "- recreating dock")
const comp = sourceComponent
sourceComponent = null
sourceComponent = comp
}
}
Loader {
id: dankDashPopoutLoader
active: false
asynchronous: true
sourceComponent: Component {
DankDashPopout {
id: dankDashPopout
Component.onCompleted: {
PopoutService.dankDashPopout = dankDashPopout
}
}
}
}
LazyLoader {
id: dockContextMenuLoader
active: false
DockContextMenu {
id: dockContextMenu
}
}
LazyLoader {
id: notificationCenterLoader
active: false
NotificationCenterPopout {
id: notificationCenter
Component.onCompleted: {
PopoutService.notificationCenterPopout = notificationCenter
}
}
}
Variants {
model: SettingsData.getFilteredScreens("notifications")
delegate: NotificationPopupManager {
modelData: item
}
}
LazyLoader {
id: controlCenterLoader
active: false
property var modalRef: colorPickerModal
property LazyLoader powerModalLoaderRef: powerMenuModalLoader
ControlCenterPopout {
id: controlCenterPopout
colorPickerModal: controlCenterLoader.modalRef
powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef
onLockRequested: {
lock.activate()
}
Component.onCompleted: {
PopoutService.controlCenterPopout = controlCenterPopout
}
}
}
LazyLoader {
id: wifiPasswordModalLoader
active: false
WifiPasswordModal {
id: wifiPasswordModal
Component.onCompleted: {
PopoutService.wifiPasswordModal = wifiPasswordModal
}
}
}
LazyLoader {
id: networkInfoModalLoader
active: false
NetworkInfoModal {
id: networkInfoModal
Component.onCompleted: {
PopoutService.networkInfoModal = networkInfoModal
}
}
}
LazyLoader {
id: batteryPopoutLoader
active: false
BatteryPopout {
id: batteryPopout
Component.onCompleted: {
PopoutService.batteryPopout = batteryPopout
}
}
}
LazyLoader {
id: vpnPopoutLoader
active: false
VpnPopout {
id: vpnPopout
Component.onCompleted: {
PopoutService.vpnPopout = vpnPopout
}
}
}
LazyLoader {
id: powerMenuLoader
active: false
PowerMenu {
id: powerMenu
onPowerActionRequested: (action, title, message) => {
if (SettingsData.powerActionConfirm) {
powerConfirmModalLoader.active = true
if (powerConfirmModalLoader.item) {
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {})
onLoaded: {
if (item) {
item.pluginService = PluginService
if (item.popoutService !== undefined) {
item.popoutService = PopoutService
}
item.pluginId = pluginId
console.log("Daemon plugin loaded:", pluginId)
}
} else {
actionApply(action)
}
}
function actionApply(action) {
switch (action) {
case "logout":
SessionService.logout()
break
case "suspend":
SessionService.suspend()
break
case "hibernate":
SessionService.hibernate()
break
case "reboot":
SessionService.reboot()
break
case "poweroff":
SessionService.poweroff()
break
}
}
}
}
LazyLoader {
id: powerConfirmModalLoader
WallpaperBackground {}
active: false
Lock {
id: lock
}
ConfirmModal {
id: powerConfirmModal
}
}
Loader {
id: dankBarLoader
asynchronous: false
LazyLoader {
id: processListPopoutLoader
property var currentPosition: SettingsData.dankBarPosition
property bool initialized: false
active: false
ProcessListPopout {
id: processListPopout
Component.onCompleted: {
PopoutService.processListPopout = processListPopout
}
}
}
SettingsModal {
id: settingsModal
Component.onCompleted: {
PopoutService.settingsModal = settingsModal
}
}
LazyLoader {
id: appDrawerLoader
active: false
AppDrawerPopout {
id: appDrawerPopout
Component.onCompleted: {
PopoutService.appDrawerPopout = appDrawerPopout
}
}
}
SpotlightModal {
id: spotlightModal
Component.onCompleted: {
PopoutService.spotlightModal = spotlightModal
}
}
ClipboardHistoryModal {
id: clipboardHistoryModalPopup
Component.onCompleted: {
PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup
}
}
NotificationModal {
id: notificationModal
Component.onCompleted: {
PopoutService.notificationModal = notificationModal
}
}
DankColorPickerModal {
id: colorPickerModal
Component.onCompleted: {
PopoutService.colorPickerModal = colorPickerModal
}
}
LazyLoader {
id: processListModalLoader
active: false
ProcessListModal {
id: processListModal
Component.onCompleted: {
PopoutService.processListModal = processListModal
}
}
}
LazyLoader {
id: systemUpdateLoader
active: false
SystemUpdatePopout {
id: systemUpdatePopout
Component.onCompleted: {
PopoutService.systemUpdatePopout = systemUpdatePopout
}
}
}
Variants {
id: notepadSlideoutVariants
model: SettingsData.getFilteredScreens("notepad")
delegate: DankSlideout {
id: notepadSlideout
modelData: item
title: I18n.tr("Notepad")
slideoutWidth: 480
expandable: true
expandedWidthValue: 960
customTransparency: SettingsData.notepadTransparencyOverride
content: Component {
Notepad {
onHideRequested: {
notepadSlideout.hide()
}
}
}
function toggle() {
if (isVisible) {
hide()
} else {
show()
}
}
}
}
LazyLoader {
id: powerMenuModalLoader
active: false
PowerMenuModal {
id: powerMenuModal
onPowerActionRequested: (action, title, message) => {
if (SettingsData.powerActionConfirm) {
powerConfirmModalLoader.active = true
if (powerConfirmModalLoader.item) {
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {})
sourceComponent: DankBar {
onColorPickerRequested: {
if (colorPickerModal.shouldBeVisible) {
colorPickerModal.close()
} else {
colorPickerModal.show()
}
} else {
actionApply(action)
}
}
function actionApply(action) {
switch (action) {
case "logout":
SessionService.logout()
break
case "suspend":
SessionService.suspend()
break
case "hibernate":
SessionService.hibernate()
break
case "reboot":
SessionService.reboot()
break
case "poweroff":
SessionService.poweroff()
break
}
}
Component.onCompleted: {
PopoutService.powerMenuModal = powerMenuModal
initialized = true
}
onCurrentPositionChanged: {
if (!initialized)
return
const component = sourceComponent
sourceComponent = null
sourceComponent = component
}
}
}
LazyLoader {
id: hyprKeybindsModalLoader
Loader {
id: dockLoader
active: true
asynchronous: false
active: false
property var currentPosition: SettingsData.dockPosition
property bool initialized: false
HyprKeybindsModal {
id: hyprKeybindsModal
sourceComponent: Dock {
contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null
}
Component.onCompleted: {
PopoutService.hyprKeybindsModal = hyprKeybindsModal
}
}
}
onLoaded: {
if (item) {
dockContextMenuLoader.active = true
}
}
DMSShellIPC {
powerMenuModalLoader: powerMenuModalLoader
processListModalLoader: processListModalLoader
controlCenterLoader: controlCenterLoader
dankDashPopoutLoader: dankDashPopoutLoader
notepadSlideoutVariants: notepadSlideoutVariants
hyprKeybindsModalLoader: hyprKeybindsModalLoader
}
Component.onCompleted: {
initialized = true
}
Variants {
model: SettingsData.getFilteredScreens("toast")
onCurrentPositionChanged: {
if (!initialized)
return
delegate: Toast {
modelData: item
visible: ToastService.toastVisible
}
}
console.log("DEBUG: Dock position changed to:", currentPosition, "- recreating dock")
const comp = sourceComponent
sourceComponent = null
sourceComponent = comp
}
}
Variants {
model: SettingsData.getFilteredScreens("osd")
Loader {
id: dankDashPopoutLoader
delegate: VolumeOSD {
modelData: item
}
}
active: false
asynchronous: true
Variants {
model: SettingsData.getFilteredScreens("osd")
sourceComponent: Component {
DankDashPopout {
id: dankDashPopout
delegate: MicMuteOSD {
modelData: item
}
}
Component.onCompleted: {
PopoutService.dankDashPopout = dankDashPopout
}
}
}
}
Variants {
model: SettingsData.getFilteredScreens("osd")
LazyLoader {
id: dockContextMenuLoader
delegate: BrightnessOSD {
modelData: item
}
}
active: false
Variants {
model: SettingsData.getFilteredScreens("osd")
DockContextMenu {
id: dockContextMenu
}
}
delegate: IdleInhibitorOSD {
modelData: item
}
}
LazyLoader {
id: notificationCenterLoader
active: false
NotificationCenterPopout {
id: notificationCenter
Component.onCompleted: {
PopoutService.notificationCenterPopout = notificationCenter
}
}
}
Variants {
model: SettingsData.getFilteredScreens("notifications")
delegate: NotificationPopupManager {
modelData: item
}
}
LazyLoader {
id: controlCenterLoader
active: false
property var modalRef: colorPickerModal
property LazyLoader powerModalLoaderRef: powerMenuModalLoader
ControlCenterPopout {
id: controlCenterPopout
colorPickerModal: controlCenterLoader.modalRef
powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef
onLockRequested: {
lock.activate()
}
Component.onCompleted: {
PopoutService.controlCenterPopout = controlCenterPopout
}
}
}
LazyLoader {
id: wifiPasswordModalLoader
active: false
WifiPasswordModal {
id: wifiPasswordModal
Component.onCompleted: {
PopoutService.wifiPasswordModal = wifiPasswordModal
}
}
}
LazyLoader {
id: networkInfoModalLoader
active: false
NetworkInfoModal {
id: networkInfoModal
Component.onCompleted: {
PopoutService.networkInfoModal = networkInfoModal
}
}
}
LazyLoader {
id: batteryPopoutLoader
active: false
BatteryPopout {
id: batteryPopout
Component.onCompleted: {
PopoutService.batteryPopout = batteryPopout
}
}
}
LazyLoader {
id: vpnPopoutLoader
active: false
VpnPopout {
id: vpnPopout
Component.onCompleted: {
PopoutService.vpnPopout = vpnPopout
}
}
}
LazyLoader {
id: powerMenuLoader
active: false
PowerMenu {
id: powerMenu
onPowerActionRequested: (action, title, message) => {
if (SettingsData.powerActionConfirm) {
powerConfirmModalLoader.active = true
if (powerConfirmModalLoader.item) {
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {})
}
} else {
actionApply(action)
}
}
function actionApply(action) {
switch (action) {
case "logout":
SessionService.logout()
break
case "suspend":
SessionService.suspend()
break
case "hibernate":
SessionService.hibernate()
break
case "reboot":
SessionService.reboot()
break
case "poweroff":
SessionService.poweroff()
break
}
}
}
}
LazyLoader {
id: powerConfirmModalLoader
active: false
ConfirmModal {
id: powerConfirmModal
}
}
LazyLoader {
id: processListPopoutLoader
active: false
ProcessListPopout {
id: processListPopout
Component.onCompleted: {
PopoutService.processListPopout = processListPopout
}
}
}
SettingsModal {
id: settingsModal
Component.onCompleted: {
PopoutService.settingsModal = settingsModal
}
}
LazyLoader {
id: appDrawerLoader
active: false
AppDrawerPopout {
id: appDrawerPopout
Component.onCompleted: {
PopoutService.appDrawerPopout = appDrawerPopout
}
}
}
SpotlightModal {
id: spotlightModal
Component.onCompleted: {
PopoutService.spotlightModal = spotlightModal
}
}
ClipboardHistoryModal {
id: clipboardHistoryModalPopup
Component.onCompleted: {
PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup
}
}
NotificationModal {
id: notificationModal
Component.onCompleted: {
PopoutService.notificationModal = notificationModal
}
}
DankColorPickerModal {
id: colorPickerModal
Component.onCompleted: {
PopoutService.colorPickerModal = colorPickerModal
}
}
LazyLoader {
id: processListModalLoader
active: false
ProcessListModal {
id: processListModal
Component.onCompleted: {
PopoutService.processListModal = processListModal
}
}
}
LazyLoader {
id: systemUpdateLoader
active: false
SystemUpdatePopout {
id: systemUpdatePopout
Component.onCompleted: {
PopoutService.systemUpdatePopout = systemUpdatePopout
}
}
}
Variants {
id: notepadSlideoutVariants
model: SettingsData.getFilteredScreens("notepad")
delegate: DankSlideout {
id: notepadSlideout
modelData: item
title: I18n.tr("Notepad")
slideoutWidth: 480
expandable: true
expandedWidthValue: 960
customTransparency: SettingsData.notepadTransparencyOverride
content: Component {
Notepad {
onHideRequested: {
notepadSlideout.hide()
}
}
}
function toggle() {
if (isVisible) {
hide()
} else {
show()
}
}
}
}
LazyLoader {
id: powerMenuModalLoader
active: false
PowerMenuModal {
id: powerMenuModal
onPowerActionRequested: (action, title, message) => {
if (SettingsData.powerActionConfirm) {
powerConfirmModalLoader.active = true
if (powerConfirmModalLoader.item) {
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {})
}
} else {
actionApply(action)
}
}
function actionApply(action) {
switch (action) {
case "logout":
SessionService.logout()
break
case "suspend":
SessionService.suspend()
break
case "hibernate":
SessionService.hibernate()
break
case "reboot":
SessionService.reboot()
break
case "poweroff":
SessionService.poweroff()
break
}
}
Component.onCompleted: {
PopoutService.powerMenuModal = powerMenuModal
}
}
}
LazyLoader {
id: hyprKeybindsModalLoader
active: false
HyprKeybindsModal {
id: hyprKeybindsModal
Component.onCompleted: {
PopoutService.hyprKeybindsModal = hyprKeybindsModal
}
}
}
DMSShellIPC {
powerMenuModalLoader: powerMenuModalLoader
processListModalLoader: processListModalLoader
controlCenterLoader: controlCenterLoader
dankDashPopoutLoader: dankDashPopoutLoader
notepadSlideoutVariants: notepadSlideoutVariants
hyprKeybindsModalLoader: hyprKeybindsModalLoader
dankBarLoader: dankBarLoader
}
Variants {
model: SettingsData.getFilteredScreens("toast")
delegate: Toast {
modelData: item
visible: ToastService.toastVisible
}
}
Variants {
model: SettingsData.getFilteredScreens("osd")
delegate: VolumeOSD {
modelData: item
}
}
Variants {
model: SettingsData.getFilteredScreens("osd")
delegate: MicMuteOSD {
modelData: item
}
}
Variants {
model: SettingsData.getFilteredScreens("osd")
delegate: BrightnessOSD {
modelData: item
}
}
Variants {
model: SettingsData.getFilteredScreens("osd")
delegate: IdleInhibitorOSD {
modelData: item
}
}
}

View File

@@ -14,6 +14,7 @@ Item {
required property var dankDashPopoutLoader
required property var notepadSlideoutVariants
required property var hyprKeybindsModalLoader
required property var dankBarLoader
IpcHandler {
function open() {
@@ -76,9 +77,8 @@ Item {
IpcHandler {
function open(): string {
root.controlCenterLoader.active = true
if (root.controlCenterLoader.item) {
root.controlCenterLoader.item.open()
if (root.dankBarLoader.item) {
root.dankBarLoader.item.triggerControlCenterOnFocusedScreen()
return "CONTROL_CENTER_OPEN_SUCCESS"
}
return "CONTROL_CENTER_OPEN_FAILED"
@@ -93,9 +93,8 @@ Item {
}
function toggle(): string {
root.controlCenterLoader.active = true
if (root.controlCenterLoader.item) {
root.controlCenterLoader.item.toggle()
if (root.dankBarLoader.item) {
root.dankBarLoader.item.triggerControlCenterOnFocusedScreen()
return "CONTROL_CENTER_TOGGLE_SUCCESS"
}
return "CONTROL_CENTER_TOGGLE_FAILED"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,162 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Modals.Common
import qs.Services
import qs.Widgets
DankModal {
id: root
property bool networkWiredInfoModalVisible: false
property string networkID: ""
property var networkData: null
function showNetworkInfo(id, data) {
networkID = id
networkData = data
networkWiredInfoModalVisible = true
open()
NetworkService.fetchWiredNetworkInfo(data.uuid)
}
function hideDialog() {
networkWiredInfoModalVisible = false
close()
networkID = ""
networkData = null
}
visible: networkWiredInfoModalVisible
width: 600
height: 500
enableShadow: true
onBackgroundClicked: hideDialog()
onVisibleChanged: {
if (!visible) {
networkID = ""
networkData = null
}
}
content: Component {
Item {
anchors.fill: parent
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
Row {
width: parent.width
Column {
width: parent.width - 40
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Network Information")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: `Details for "${networkID}"`
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
elide: Text.ElideRight
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
onClicked: root.hideDialog()
}
}
Rectangle {
id: detailsRect
width: parent.width
height: parent.height - 140
radius: Theme.cornerRadius
color: Theme.surfaceHover
border.color: Theme.outlineStrong
border.width: 1
clip: true
DankFlickable {
anchors.fill: parent
anchors.margins: Theme.spacingM
contentHeight: detailsText.contentHeight
StyledText {
id: detailsText
width: parent.width
text: NetworkService.networkWiredInfoDetails && NetworkService.networkWiredInfoDetails.replace(/\\n/g, '\n') || "No information available"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
wrapMode: Text.WordWrap
}
}
}
Item {
width: parent.width
height: 40
Rectangle {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: Math.max(70, closeText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: closeArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
StyledText {
id: closeText
anchors.centerIn: parent
text: I18n.tr("Close")
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: closeArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.hideDialog()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
}

View File

@@ -391,6 +391,38 @@ Item {
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
anchors.left: parent.left
StyledText {
text: I18n.tr("Command or script to run instead of the standard lock procedure")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
DankTextField {
id: customLockCommand
width: parent.width
height: 48
placeholderText: "/usr/bin/myLock.sh"
backgroundColor: Theme.surfaceVariant
normalBorderColor: Theme.primarySelected
focusedBorderColor: Theme.primary
Component.onCompleted: {
if (SettingsData.customPowerActionLock) {
text = SettingsData.customPowerActionLock;
}
}
onTextEdited: {
SettingsData.setCustomPowerActionLock(text.trim());
}
}
}
Column {
width: parent.width
spacing: Theme.spacingXS

View File

@@ -73,21 +73,21 @@ DankPopout {
onShouldBeVisibleChanged: {
if (shouldBeVisible) {
Qt.callLater(() => {
if (NetworkService.activeService) {
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled
}
if (UserInfoService)
UserInfoService.getUptime()
})
if (NetworkService.activeService) {
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled
}
if (UserInfoService)
UserInfoService.getUptime()
})
} else {
Qt.callLater(() => {
if (NetworkService.activeService) {
NetworkService.activeService.autoRefreshEnabled = false
}
if (BluetoothService.adapter && BluetoothService.adapter.discovering)
BluetoothService.adapter.discovering = false
editMode = false
})
if (NetworkService.activeService) {
NetworkService.activeService.autoRefreshEnabled = false
}
if (BluetoothService.adapter && BluetoothService.adapter.discovering)
BluetoothService.adapter.discovering = false
editMode = false
})
}
}
@@ -108,8 +108,7 @@ DankPopout {
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
}
radius: Theme.cornerRadius
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 0
antialiasing: true
smooth: true
@@ -156,19 +155,19 @@ DankPopout {
bluetoothCodecSelector: bluetoothCodecSelector
colorPickerModal: root.colorPickerModal
onExpandClicked: (widgetData, globalIndex) => {
root.expandedWidgetIndex = globalIndex
root.expandedWidgetData = widgetData
if (widgetData.id === "diskUsage") {
root.toggleSection("diskUsage_" + (widgetData.instanceId || "default"))
} else if (widgetData.id === "brightnessSlider") {
root.toggleSection("brightnessSlider_" + (widgetData.instanceId || "default"))
} else {
root.toggleSection(widgetData.id)
}
}
onRemoveWidget: (index) => widgetModel.removeWidget(index)
root.expandedWidgetIndex = globalIndex
root.expandedWidgetData = widgetData
if (widgetData.id === "diskUsage") {
root.toggleSection("diskUsage_" + (widgetData.instanceId || "default"))
} else if (widgetData.id === "brightnessSlider") {
root.toggleSection("brightnessSlider_" + (widgetData.instanceId || "default"))
} else {
root.toggleSection(widgetData.id)
}
}
onRemoveWidget: index => widgetModel.removeWidget(index)
onMoveWidget: (fromIndex, toIndex) => widgetModel.moveWidget(fromIndex, toIndex)
onToggleWidgetSize: (index) => widgetModel.toggleWidgetSize(index)
onToggleWidgetSize: index => widgetModel.toggleWidgetSize(index)
onCollapseRequested: root.collapseAll()
}
@@ -177,12 +176,13 @@ DankPopout {
visible: editMode
popoutContent: controlContent
availableWidgets: {
if (!editMode) return []
if (!editMode)
return []
const existingIds = (SettingsData.controlCenterWidgets || []).map(w => w.id)
const allWidgets = widgetModel.baseWidgetDefinitions.concat(widgetModel.getPluginWidgets())
return allWidgets.filter(w => w.allowMultiple || !existingIds.includes(w.id))
}
onAddWidget: (widgetId) => widgetModel.addWidget(widgetId)
onAddWidget: widgetId => widgetModel.addWidget(widgetId)
onResetToDefault: () => widgetModel.resetToDefault()
onClearAll: () => widgetModel.clearAll()
}
@@ -205,10 +205,10 @@ DankPopout {
id: bluetoothDetailComponent
BluetoothDetail {
id: bluetoothDetail
onShowCodecSelector: function(device) {
onShowCodecSelector: function (device) {
if (contentLoader.item && contentLoader.item.bluetoothCodecSelector) {
contentLoader.item.bluetoothCodecSelector.show(device)
contentLoader.item.bluetoothCodecSelector.codecSelected.connect(function(deviceAddress, codecName) {
contentLoader.item.bluetoothCodecSelector.codecSelected.connect(function (deviceAddress, codecName) {
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName)
})
}
@@ -233,4 +233,4 @@ DankPopout {
property var colorPickerModal: null
property var powerMenuModalLoader: null
}
}

View File

@@ -29,6 +29,26 @@ Rectangle {
NetworkService.removeRef()
}
property int currentPreferenceIndex: {
if (DMSService.apiVersion < 5) {
return 1
}
const pref = NetworkService.userPreference
const status = NetworkService.networkStatus
let index = 1
if (pref === "ethernet") {
index = 0
} else if (pref === "wifi") {
index = 1
} else {
index = status === "ethernet" ? 0 : 1
}
return index
}
Row {
id: headerRow
anchors.left: parent.left
@@ -38,7 +58,7 @@ Rectangle {
anchors.rightMargin: Theme.spacingM
anchors.topMargin: Theme.spacingS
height: 40
StyledText {
id: headerText
text: I18n.tr("Network Settings")
@@ -47,32 +67,16 @@ Rectangle {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: Math.max(0, parent.width - headerText.implicitWidth - preferenceControls.width - Theme.spacingM)
height: parent.height
}
DankButtonGroup {
id: preferenceControls
anchors.verticalCenter: parent.verticalCenter
visible: NetworkService.ethernetConnected
property int currentPreferenceIndex: {
const pref = NetworkService.userPreference
const status = NetworkService.networkStatus
let index = 1
if (pref === "ethernet") {
index = 0
} else if (pref === "wifi") {
index = 1
} else {
index = status === "ethernet" ? 0 : 1
}
return index
}
visible: DMSService.apiVersion >= 5
model: ["Ethernet", "WiFi"]
currentIndex: currentPreferenceIndex
@@ -92,7 +96,7 @@ Rectangle {
anchors.right: parent.right
anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM
visible: NetworkService.wifiToggling
visible: currentPreferenceIndex === 1 && NetworkService.wifiToggling
height: visible ? 80 : 0
Column {
@@ -131,7 +135,7 @@ Rectangle {
anchors.right: parent.right
anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM
visible: !NetworkService.wifiEnabled && !NetworkService.wifiToggling
visible: currentPreferenceIndex === 1 && !NetworkService.wifiEnabled && !NetworkService.wifiToggling
height: visible ? 120 : 0
Column {
@@ -179,7 +183,179 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: NetworkService.toggleWifiRadio()
}
}
}
}
DankFlickable {
id: wiredContent
anchors.top: headerRow.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM
visible: currentPreferenceIndex === 0 && DMSService.apiVersion >= 5
contentHeight: wiredColumn.height
clip: true
Column {
id: wiredColumn
width: parent.width
spacing: Theme.spacingS
Repeater {
model: sortedNetworks
property var sortedNetworks: {
const currentUuid = NetworkService.ethernetConnectionUuid
const networks = NetworkService.wiredConnections
let sorted = [...networks]
sorted.sort((a, b) => {
if (a.isActive && !b.isActive) return -1
if (!a.isActive && b.isActive) return 1
return a.id.localeCompare(b.id)
})
return sorted
}
delegate: Rectangle {
required property var modelData
required property int index
width: parent.width
height: 50
radius: Theme.cornerRadius
color: wiredNetworkMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
border.color: Theme.primary
border.width: 0
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Theme.spacingM
spacing: Theme.spacingS
DankIcon {
name: "lan"
size: Theme.iconSize - 4
color: modelData.isActive ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
anchors.verticalCenter: parent.verticalCenter
width: 200
StyledText {
text: modelData.id || "Unknown Config"
font.pixelSize: Theme.fontSizeMedium
color: modelData.isActive ? Theme.primary : Theme.surfaceText
font.weight: modelData.isActive ? Font.Medium : Font.Normal
elide: Text.ElideRight
width: parent.width
}
}
}
DankActionButton {
id: wiredOptionsButton
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
iconName: "more_horiz"
buttonSize: 28
onClicked: {
if (wiredNetworkContextMenu.visible) {
wiredNetworkContextMenu.close()
} else {
wiredNetworkContextMenu.currentID = modelData.id
wiredNetworkContextMenu.currentUUID = modelData.uuid
wiredNetworkContextMenu.currentConnected = modelData.isActive
wiredNetworkContextMenu.popup(wiredOptionsButton, -wiredNetworkContextMenu.width + wiredOptionsButton.width, wiredOptionsButton.height + Theme.spacingXS)
}
}
}
MouseArea {
id: wiredNetworkMouseArea
anchors.fill: parent
anchors.rightMargin: wiredOptionsButton.width + Theme.spacingS
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: function(event) {
if (modelData.uuid !== NetworkService.ethernetConnectionUuid) {
NetworkService.connectToSpecificWiredConfig(modelData.uuid)
}
event.accepted = true
}
}
}
}
}
}
Menu {
id: wiredNetworkContextMenu
width: 150
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
property string currentID: ""
property string currentUUID: ""
property bool currentConnected: false
background: Rectangle {
color: Theme.popupBackground()
radius: Theme.cornerRadius
border.width: 0
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
}
MenuItem {
text: "Activate"
height: !wiredNetworkContextMenu.currentConnected ? 32 : 0
contentItem: StyledText {
text: parent.text
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
leftPadding: Theme.spacingS
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
radius: Theme.cornerRadius / 2
}
onTriggered: {
if (!networkContextMenu.currentConnected) {
NetworkService.connectToSpecificWiredConfig(wiredNetworkContextMenu.currentUUID)
}
}
}
MenuItem {
text: I18n.tr("Network Info")
height: wiredNetworkContextMenu.currentConnected ? 32 : 0
contentItem: StyledText {
text: parent.text
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
leftPadding: Theme.spacingS
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: parent.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
radius: Theme.cornerRadius / 2
}
onTriggered: {
let networkData = NetworkService.getWiredNetworkInfo(wiredNetworkContextMenu.currentUUID)
networkWiredInfoModal.showNetworkInfo(wiredNetworkContextMenu.currentID, networkData)
}
}
}
@@ -192,10 +368,10 @@ Rectangle {
anchors.bottom: parent.bottom
anchors.margins: Theme.spacingM
anchors.topMargin: Theme.spacingM
visible: NetworkService.wifiInterface && NetworkService.wifiEnabled && !NetworkService.wifiToggling
visible: currentPreferenceIndex === 1 && NetworkService.wifiEnabled && !NetworkService.wifiToggling
contentHeight: wifiColumn.height
clip: true
Column {
id: wifiColumn
width: parent.width
@@ -282,20 +458,20 @@ Rectangle {
spacing: Theme.spacingXS
StyledText {
text: modelData.ssid === NetworkService.currentWifiSSID ? "Connected" : (modelData.secured ? "Secured" : "Open")
text: modelData.ssid === NetworkService.currentWifiSSID ? "Connected" : (modelData.secured ? "Secured" : "Open")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: modelData.saved ? "Saved" : ""
text: modelData.saved ? "Saved" : ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
visible: text.length > 0
}
StyledText {
text: "• " + modelData.signal + "%"
text: (modelData.saved ? "• " : "") + modelData.signal + "%"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
@@ -449,6 +625,8 @@ Rectangle {
NetworkInfoModal {
id: networkInfoModal
}
NetworkWiredInfoModal {
id: networkWiredInfoModal
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -153,7 +153,10 @@ Rectangle {
const name = split[0];
const path = split[1];
const fileName = name.substring(name.lastIndexOf("/") + 1);
let fileName = name.substring(name.lastIndexOf("/") + 1);
if (fileName.startsWith("dropboxstatus")) {
fileName = `hicolor/16x16/status/${fileName}`;
}
return `file://${path}/${fileName}`;
}
if (icon.startsWith("/") && !icon.startsWith("file://")) {

View File

@@ -15,6 +15,9 @@ Rectangle {
property string screenName: ""
property real widgetHeight: 30
property real barThickness: 48
readonly property var sortedToplevels: {
return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, parentScreen?.name);
}
property int currentWorkspace: {
if (CompositorService.isNiri) {
return getNiriActiveWorkspace()
@@ -252,14 +255,84 @@ Rectangle {
const direction = deltaY < 0 ? 1 : -1
if (isMouseWheel) {
switchWorkspace(direction)
if (!SettingsData.workspaceScrolling || !CompositorService.isNiri) {
switchWorkspace(direction)
}
else {
const windows = root.sortedToplevels;
if (windows.length < 2) {
return;
}
let currentIndex = -1;
for (let i = 0; i < windows.length; i++) {
if (windows[i].activated) {
currentIndex = i;
break;
}
}
let nextIndex;
if (deltaY < 0) {
if (currentIndex === -1) {
nextIndex = 0;
} else {
nextIndex = currentIndex +1;
}
} else {
if (currentIndex === -1) {
nextIndex = windows.length -1;
} else {
nextIndex = currentIndex - 1
}
}
const nextWindow = windows[nextIndex];
if (nextWindow) {
nextWindow.activate();
}
}
} else {
scrollAccumulator += deltaY
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
const touchDirection = scrollAccumulator < 0 ? 1 : -1
switchWorkspace(touchDirection)
scrollAccumulator = 0
if (!SettingsData.workspaceScrolling || !CompositorService.isNiri) {
switchWorkspace(touchDirection)
}
else {
const windows = root.sortedToplevels;
if (windows.length < 2) {
return;
}
let currentIndex = -1;
for (let i = 0; i < windows.length; i++) {
if (windows[i].activated) {
currentIndex = i;
break;
}
}
let nextIndex;
if (deltaY < 0) {
if (currentIndex === -1) {
nextIndex = 0;
} else {
nextIndex = currentIndex +1;
}
} else {
if (currentIndex === -1) {
nextIndex = windows.length -1;
} else {
nextIndex = currentIndex - 1
}
}
const nextWindow = windows[nextIndex];
if (nextWindow) {
nextWindow.activate();
}
}
scrollAccumulator = 0
}
}

View File

@@ -22,36 +22,100 @@ paru -S greetd-dms-greeter-git
yay -S greetd-dms-greeter-git
```
Then in your `/etc/greetd/config.toml` enable dms-greeter by replacing the greeter command with dms-greeter.
```bash
# hyprland and sway are also supported as compositors
command = "/usr/bin/dms-greeter --command niri"
```
See `dms-greeter --help` for full options including custom compositor configurations.
Once installed, you should disable any existing greeter (such as gdm, sddm, lightdm), and you can configure the greeter to run at boot with:
Once installed, disable any existing display manager and enable greetd:
```bash
sudo systemctl disable gdm sddm lightdm
sudo systemctl enable greetd
```
#### Syncing themes
To sync wallpapers, colors, and other settings from the logged in user, you can add your user to the `greeter` group and symlink the shell configurations.
#### Syncing themes (Optional)
To sync your wallpaper and theme with the greeter login screen:
```bash
sudo usermod -aG greeter <username>
# LOGOUT and LOGIN after adding user to group
ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json
ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json
ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /var/cache/dms-greeter/colors.json
dms-greeter-sync
```
Then logout/login for changes to take effect. Your wallpaper and theme will appear on the greeter!
<details>
<summary>What does dms-greeter-sync do?</summary>
The `dms-greeter-sync` helper automatically:
- Adds you to the greeter group
- Sets minimal ACL permissions on parent directories (traverse only)
- Sets group ownership on your DMS config directories
- Creates symlinks to share your theme files with the greeter
This uses standard Linux ACLs (Access Control Lists) - the same security model used by GNOME, KDE, and systemd. The greeter user only gets traverse permission through your directories and can only read the specific theme files you share.
</details>
<details>
<summary>Manual theme syncing (advanced)</summary>
If you prefer to set up theme syncing manually:
```bash
# Add yourself to greeter group
sudo usermod -aG greeter <username>
# Set ACLs to allow greeter to traverse your directories
setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state
# Set group ownership on config directories
sudo chgrp -R greeter ~/.config/DankMaterialShell
sudo chgrp -R greeter ~/.local/state/DankMaterialShell
sudo chgrp -R greeter ~/.cache/quickshell
sudo chmod -R g+rX ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell
# Create symlinks
sudo ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json
sudo ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json
sudo ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /var/cache/dms-greeter/colors.json
# Logout and login for group membership to take effect
```
</details>
### Fedora / RHEL / Rocky / Alma
Install from COPR or build the RPM:
```bash
# From COPR (when available)
sudo dnf copr enable avenge/dms
sudo dnf install dms-greeter
# Or build locally
cd /path/to/DankMaterialShell
rpkg local
sudo rpm -ivh x86_64/dms-greeter-*.rpm
```
The package automatically:
- Creates the greeter user
- Sets up directories and permissions
- Configures greetd with auto-detected compositor
- Applies SELinux contexts
Then disable existing display manager and enable greetd:
```bash
sudo systemctl disable gdm sddm lightdm
sudo systemctl enable greetd
```
**Optional:** Sync your theme with the greeter:
```bash
dms-greeter-sync
```
Then logout/login to see your wallpaper on the greeter!
### Automatic
The easiest thing is to run `dms greeter install` or `dms` for interactive installation.
@@ -59,21 +123,33 @@ The easiest thing is to run `dms greeter install` or `dms` for interactive insta
### Manual
1. Install `greetd` (in most distro's standard repositories) and `quickshell`
2. Clone the dms project to `/etc/xdg/quickshell/dms-greeter`
2. Create the greeter user (if not already created by greetd):
```bash
sudo groupadd -r greeter
sudo useradd -r -g greeter -d /var/lib/greeter -s /bin/bash -c "System Greeter" greeter
sudo mkdir -p /var/lib/greeter
sudo chown greeter:greeter /var/lib/greeter
```
3. Clone the dms project to `/etc/xdg/quickshell/dms-greeter`:
```bash
sudo git clone https://github.com/AvengeMedia/DankMaterialShell.git /etc/xdg/quickshell/dms-greeter
```
3. Copy `assets/dms-greeter` to `/usr/local/bin/dms-greeter`:
4. Copy `Modules/Greetd/assets/dms-greeter` to `/usr/local/bin/dms-greeter`:
```bash
sudo cp assets/dms-greeter /usr/local/bin/dms-greeter
sudo cp /etc/xdg/quickshell/dms-greeter/Modules/Greetd/assets/dms-greeter /usr/local/bin/dms-greeter
sudo chmod +x /usr/local/bin/dms-greeter
```
4. Create greeter cache directory with proper permissions:
5. Create greeter cache directory with proper permissions:
```bash
sudo mkdir -p /var/cache/dms-greeter
sudo chown greeter:greeter /var/cache/dms-greeter
sudo chmod 750 /var/cache/dms-greeter
```
6. Edit or create `/etc/greetd/config.toml`:
```toml
[terminal]
@@ -85,7 +161,18 @@ user = "greeter"
command = "/usr/local/bin/dms-greeter --command niri"
```
Enable the greeter with `sudo systemctl enable greetd`
7. Disable existing display manager and enable greetd:
```bash
sudo systemctl disable gdm sddm lightdm
sudo systemctl enable greetd
```
8. (Optional) Install the `dms-greeter-sync` helper for easy theme syncing:
```bash
# Download or copy the dms-greeter-sync script from the spec file
sudo cp /path/to/dms-greeter-sync /usr/local/bin/dms-greeter-sync
sudo chmod +x /usr/local/bin/dms-greeter-sync
```
#### Legacy installation (deprecated)
@@ -154,21 +241,31 @@ Simply edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` to change
#### Personalization
Wallpapers and themes and weather and clock formats and things are a TODO on the documentation, but it's configured exactly the same as dms.
The greeter can be personalized with wallpapers, themes, weather, clock formats, and more - configured exactly the same as dms.
You can synchronize those configurations with a specific user if you want greeter settings to always mirror the shell.
**Easiest method:** Run `dms-greeter-sync` to automatically sync your DMS theme with the greeter.
The greeter uses the `dms-greeter` group for file access permissions, so ensure your user and the greeter user are both members of this group.
**Manual method:** You can manually synchronize configurations if you want greeter settings to always mirror your shell:
```bash
# For core settings (theme, clock formats, etc)
# Add yourself to the greeter group
sudo usermod -aG greeter $USER
# Set ACLs to allow greeter user to traverse your home directory
setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state
# Set group permissions on DMS directories
sudo chgrp -R greeter ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell
sudo chmod -R g+rX ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell
# Create symlinks for theme files
sudo ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json
# For state (mainly you would configure wallpaper in this file)
sudo ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json
# For wallpaper based theming
sudo ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /var/cache/dms-greeter/dms-colors.json
sudo ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /var/cache/dms-greeter/colors.json
# Logout and login for group membership to take effect
```
You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable or the `--cache-dir` flag when using `dms-greeter`. The default is `/var/cache/dms-greeter`.
**Advanced:** You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable or the `--cache-dir` flag when using `dms-greeter`. The default is `/var/cache/dms-greeter`.
The cache directory should be owned by `greeter:greeter` with `770` permissions.

View File

@@ -19,6 +19,10 @@ Scope {
}
function lock() {
if (SettingsData.customPowerActionLock && SettingsData.customPowerActionLock.length > 0) {
Quickshell.execDetached(SettingsData.customPowerActionLock.split(" "))
return
}
if (!processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
DMSService.lockSession(response => {
if (response.error) {

View File

@@ -28,6 +28,10 @@ Item {
signal hideRequested()
Ref {
service: NotepadStorageService
}
function hasUnsavedChanges() {
return textEditor.hasUnsavedChanges()
}

View File

@@ -34,39 +34,18 @@ Item {
buttonSize: 28
anchors.verticalCenter: parent.verticalCenter
onClicked: SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
Rectangle {
id: doNotDisturbTooltip
width: tooltipText.contentWidth + Theme.spacingS * 2
height: tooltipText.contentHeight + Theme.spacingXS * 2
radius: Theme.cornerRadius
color: Theme.surfaceContainer
border.color: Theme.outline
border.width: 1
anchors.bottom: parent.top
anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter
visible: doNotDisturbButton.children[1].containsMouse
opacity: visible ? 1 : 0
StyledText {
id: tooltipText
text: I18n.tr("Do Not Disturb")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
font.hintingPreference: Font.PreferFullHinting
onEntered: {
tooltipLoader.active = true
if (tooltipLoader.item) {
const p = mapToItem(null, width / 2, 0)
tooltipLoader.item.show(I18n.tr("Do Not Disturb"), p.x, p.y - 40, null)
}
Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide()
}
tooltipLoader.active = false
}
}
}
@@ -139,4 +118,11 @@ Item {
}
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
}

View File

@@ -65,6 +65,16 @@ Item {
checked)
}
}
DankToggle {
width: parent.width
text: I18n.tr("Window Scrolling")
description: "Scroll through windows, rather than workspaces"
checked: SettingsData.workspaceScrolling
visible: CompositorService.isNiri
onToggled: checked => {
return SettingsData.setWorkspaceScrolling(checked)
}
}
DankToggle {
width: parent.width

View File

@@ -177,20 +177,39 @@ paru -S dms-shell-bin
paru -S dms-shell-git
```
#### nixOS - via flake
#### Fedora - via COPR
```bash
# Stable release
sudo dnf copr enable avengemedia/dms && sudo dnf install dms
# Latest -git
sudo dnf copr enable avengemedia/dms-git && sudo dnf install dms
```
#### NixOS - via flake
```bash
nix profile install github:AvengeMedia/DankMaterialShell
```
#### nixOS - via home-manager
#### NixOS - via home-manager
To install using home-manager, you need to add this repo into your flake inputs:
``` nix
dgop = {
url = "github:AvengeMedia/dgop";
inputs.nixpkgs.follows = "nixpkgs";
};
dms-cli = {
url = "github:AvengeMedia/danklinux";
inputs.nixpkgs.follows = "nixpkgs";
};
dankMaterialShell = {
url = "github:AvengeMedia/DankMaterialShell";
inputs.nixpkgs.follows = "nixpkgs";
inputs.dgop.follows = "dgop";
inputs.dms-cli.follows = "dms-cli";
};
```
@@ -244,7 +263,7 @@ There are a lot of possible configurations that you can enable/disable in the fl
# Arch
paru -S quickshell-git
# Fedora
sudo dnf copr enable errornointernet/quickshell && sudo dnf install quickshell-git
sudo dnf copr enable avengemedia/danklinux && sudo dnf install quickshell-git
# ! TODO - document other distros
```
@@ -291,10 +310,10 @@ sudo pacman -S cava wl-clipboard cliphist brightnessctl qt6-multimedia
paru -S matugen-bin dgop
# Fedora
sudo dnf install cava wl-clipboard brightnessctl qt6-qtmultimedia
sudo dnf copr enable wef/cliphist && sudo dnf install cliphist
sudo dnf copr enable heus-sueh/packages && sudo dnf install matugen
sudo dnf install cava wl-clipboard brightnessctl qt6-qtmultimedia
sudo dnf copr enable avengemedia/danklinux && sudo dnf install cliphist ghostty hyprpicker material-symbols-fonts matugen
```
Note: by enabling and installing the avengemedia/dms copr above, these core dependencies will automatically be available for use.
*Other distros will just need to find sources for the above packages*
@@ -665,7 +684,7 @@ cp -R ./PLUGINS/ExampleEmojiPlugin ~/.config/DankMaterialShell/plugins
**Only install plugins from TRUSTED sources.** Plugins execute QML and javascript at runtime, plugins from third parties should be reviewed before enabling them in dms.
### nixOS - via home-manager
### NixOS - via home-manager
Add the following to your home-manager config to install a plugin:

View File

@@ -342,13 +342,13 @@ Singleton {
}
function playNormalNotificationSound() {
if (soundsAvailable && normalNotificationSound) {
if (soundsAvailable && normalNotificationSound && !SessionData.doNotDisturb) {
normalNotificationSound.play()
}
}
function playCriticalNotificationSound() {
if (soundsAvailable && criticalNotificationSound) {
if (soundsAvailable && criticalNotificationSound && !SessionData.doNotDisturb) {
criticalNotificationSound.play()
}
}

View File

@@ -20,6 +20,8 @@ Singleton {
property bool ethernetConnected: false
property string ethernetConnectionUuid: ""
property var wiredConnections: []
property string wifiIP: ""
property string wifiInterface: ""
property bool wifiConnected: false
@@ -73,6 +75,10 @@ Singleton {
property string networkInfoSSID: ""
property string networkInfoDetails: ""
property bool networkInfoLoading: false
property string networkWiredInfoUUID: ""
property string networkWiredInfoDetails: ""
property bool networkWiredInfoLoading: false
signal networksUpdated
signal connectionChanged

View File

@@ -20,6 +20,8 @@ Singleton {
property bool ethernetConnected: false
property string ethernetConnectionUuid: ""
property var wiredConnections: []
property string wifiIP: ""
property string wifiInterface: ""
property bool wifiConnected: false
@@ -69,6 +71,10 @@ Singleton {
property string networkInfoSSID: ""
property string networkInfoDetails: ""
property bool networkInfoLoading: false
property string networkWiredInfoUUID: ""
property string networkWiredInfoDetails: ""
property bool networkWiredInfoLoading: false
property int refCount: 0
property bool stateInitialized: false
@@ -179,6 +185,8 @@ Singleton {
ethernetConnected = state.ethernetConnected || false
ethernetConnectionUuid = state.ethernetConnectionUuid || ""
wiredConnections = state.wiredConnections || []
wifiIP = state.wifiIP || ""
wifiInterface = state.wifiDevice || ""
wifiConnected = state.wifiConnected || false
@@ -219,6 +227,31 @@ Singleton {
connectionChanged()
}
function connectToSpecificWiredConfig(uuid) {
if (!networkAvailable || isConnecting) return
isConnecting = true
connectionError = ""
connectionStatus = "connecting"
const params = { uuid: uuid }
DMSService.sendRequest("network.ethernet.connect.config", params, response => {
if (response.error) {
connectionError = response.error
lastConnectionError = response.error
connectionStatus = "failed"
ToastService.showError(`Failed to activate configuration`)
} else {
connectionError = ""
connectionStatus = "connected"
ToastService.showInfo(`Configuration activated`)
}
isConnecting = false
})
}
function scanWifi() {
if (!networkAvailable || isScanning || !wifiEnabled) return
@@ -413,6 +446,61 @@ Singleton {
autoScan = false
autoRefreshEnabled = false
}
function fetchWiredNetworkInfo(uuid) {
if (!networkAvailable) return
networkWiredInfoUUID = uuid
networkWiredInfoLoading = true
networkWiredInfoDetails = "Loading network information..."
DMSService.sendRequest("network.ethernet.info", { uuid: uuid }, response => {
networkWiredInfoLoading = false
if (response.error) {
networkWiredInfoDetails = "Failed to fetch network information"
} else if (response.result) {
formatWiredNetworkInfo(response.result)
}
})
}
function formatWiredNetworkInfo(info) {
let details = ""
if (!info) {
details = "Network information not found or network not available."
} else {
details += "Inteface: " + info.iface + "\\n"
details += "Driver: " + info.driver + "\\n"
details += "MAC Addr: " + info.hwAddr + "\\n"
details += "Speed: " + info.speed + " Mb/s\\n\\n"
details += "IPv4 informations:\\n"
for (const ip4 of info.IPv4s.ips) {
details += " IPv4 address: " + ip4 + "\\n"
}
details += " Gateway: " + info.IPv4s.gateway + "\\n"
details += " DNS: " + info.IPv4s.dns + "\\n"
if (info.IPv6s.ips) {
details += "\\nIPv6 informations:\\n"
for (const ip6 of info.IPv6s.ips) {
details += " IPv6 address: " + ip6 + "\\n"
}
if (info.IPv6s.gateway.length > 0) {
details += " Gateway: " + info.IPv6s.gateway + "\\n"
}
if (info.IPv6s.dns.length > 0) {
details += " DNS: " + info.IPv6s.dns + "\\n"
}
}
}
networkWiredInfoDetails = details
}
function fetchNetworkInfo(ssid) {
if (!networkAvailable) return
@@ -483,6 +571,17 @@ Singleton {
}
}
function getWiredNetworkInfo(uuid) {
const network = wiredConnections.find(n => n.uuid === uuid)
if (!network) {
return null
}
return {
"uuid": uuid,
}
}
function refreshNetworkState() {
if (networkAvailable) {
getState()

View File

@@ -19,6 +19,8 @@ Singleton {
property bool ethernetConnected: activeService?.ethernetConnected ?? false
property string ethernetConnectionUuid: activeService?.ethernetConnectionUuid ?? ""
property var wiredConnections: activeService?.wiredConnections ?? []
property string wifiIP: activeService?.wifiIP ?? ""
property string wifiInterface: activeService?.wifiInterface ?? ""
property bool wifiConnected: activeService?.wifiConnected ?? false
@@ -57,6 +59,10 @@ Singleton {
property string networkInfoSSID: activeService?.networkInfoSSID ?? ""
property string networkInfoDetails: activeService?.networkInfoDetails ?? ""
property bool networkInfoLoading: activeService?.networkInfoLoading ?? false
property string networkWiredInfoUUID: activeService?.networkWiredInfoUUID ?? ""
property string networkWiredInfoDetails: activeService?.networkWiredInfoDetails ?? ""
property bool networkWiredInfoLoading: activeService?.networkWiredInfoLoading ?? false
property int refCount: activeService?.refCount ?? 0
property bool stateInitialized: activeService?.stateInitialized ?? false
@@ -221,6 +227,12 @@ Singleton {
}
}
function fetchWiredNetworkInfo(uuid) {
if (activeService && activeService.fetchWiredNetworkInfo) {
activeService.fetchWiredNetworkInfo(uuid)
}
}
function getNetworkInfo(ssid) {
if (activeService && activeService.getNetworkInfo) {
return activeService.getNetworkInfo(ssid)
@@ -228,9 +240,22 @@ Singleton {
return null
}
function getWiredNetworkInfo(uuid) {
if (activeService && activeService.getWiredNetworkInfo) {
return activeService.getWiredNetworkInfo(uuid)
}
return null
}
function refreshNetworkState() {
if (activeService && activeService.refreshNetworkState) {
activeService.refreshNetworkState()
}
}
function connectToSpecificWiredConfig(uuid) {
if (activeService && activeService.connectToSpecificWiredConfig) {
activeService.connectToSpecificWiredConfig(uuid)
}
}
}

View File

@@ -10,6 +10,8 @@ import qs.Common
Singleton {
id: root
property int refCount: 0
readonly property string baseDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell")
readonly property string filesDir: baseDir + "/notepad-files"
readonly property string metadataPath: baseDir + "/notepad-session.json"
@@ -17,10 +19,11 @@ Singleton {
property var tabs: []
property int currentTabIndex: 0
property var tabsBeingCreated: ({})
property bool metadataLoaded: false
FileView {
id: metadataFile
path: root.metadataPath
path: root.refCount > 0 ? root.metadataPath : ""
blockWrites: true
atomicWrites: true
@@ -29,6 +32,7 @@ Singleton {
var data = JSON.parse(text())
root.tabs = data.tabs || []
root.currentTabIndex = data.currentTabIndex || 0
root.metadataLoaded = true
validateTabs()
} catch(e) {
console.warn("Failed to parse notepad metadata:", e)
@@ -41,6 +45,13 @@ Singleton {
}
}
onRefCountChanged: {
if (refCount === 1 && !metadataLoaded) {
metadataFile.path = ""
metadataFile.path = root.metadataPath
}
}
function loadMetadata() {
metadataFile.path = ""

View File

@@ -17,6 +17,7 @@ Singleton {
property int systemColorScheme: 0
property bool freedeskAvailable: false
property string colorSchemeCommand: ""
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
@@ -98,18 +99,22 @@ Singleton {
if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
return
}
if (settingsPortalAvailable) {
setSystemColorScheme(isLightMode)
}
setSystemColorScheme(isLightMode)
}
function setSystemColorScheme(isLightMode) {
if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
return
}
if (!settingsPortalAvailable || !freedeskAvailable) return
DMSService.sendRequest("freedesktop.settings.setColorScheme", { preferDark: !isLightMode }, response => {})
const targetScheme = isLightMode ? "default": "prefer-dark"
if (colorSchemeCommand === "gsettings") {
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", targetScheme])
}
if (colorSchemeCommand === "dconf") {
Quickshell.execDetached(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", `'${targetScheme}'`])
}
}
function setSystemIconTheme(themeName) {
@@ -140,6 +145,7 @@ Singleton {
} else {
console.log("PortalService: DMS_SOCKET not set")
}
colorSchemeDetector.running = true
}
Connections {
@@ -240,6 +246,23 @@ Singleton {
}
}
Process {
id: colorSchemeDetector
command: ["bash", "-c", "command -v gsettings || command -v dconf"]
running: false
stdout: StdioCollector {
onStreamFinished: {
const cmd = text.trim()
if (cmd.includes("gsettings")) {
root.colorSchemeCommand = "gsettings"
} else if (cmd.includes("dconf")) {
root.colorSchemeCommand = "dconf"
}
}
}
}
IpcHandler {
target: "profile"

View File

@@ -1 +1 @@
v0.1.16
v0.1.17

View File

@@ -20,7 +20,10 @@ BuildRequires: rpkg
Requires: greetd
Requires: (quickshell-git or quickshell)
Requires: material-symbols-fonts
Requires(post): /usr/sbin/useradd
Requires(post): /usr/sbin/groupadd
Recommends: policycoreutils-python-utils
Suggests: niri
Suggests: hyprland
Suggests: sway
@@ -50,12 +53,112 @@ cp -r * %{buildroot}%{_sysconfdir}/xdg/quickshell/dms-greeter/
# Install launcher script
install -Dm755 Modules/Greetd/assets/dms-greeter %{buildroot}%{_bindir}/dms-greeter
# Install theme sync helper script
cat > %{buildroot}%{_bindir}/dms-greeter-sync << 'SYNC_EOF'
#!/bin/bash
set -e
if [ "$EUID" -eq 0 ]; then
echo "Error: Do not run this script as root. Run as your regular user:"
echo " dms-greeter-sync"
exit 1
fi
CURRENT_USER=$(whoami)
CACHE_DIR="/var/cache/dms-greeter"
echo "=== DMS Greeter Theme Sync Setup ==="
echo
echo "This will sync your DMS theme with the greeter login screen."
echo "User: $CURRENT_USER"
echo
# Add user to greeter group
if ! groups "$CURRENT_USER" | grep -q greeter; then
echo "Adding $CURRENT_USER to greeter group..."
sudo usermod -aG greeter "$CURRENT_USER"
echo " Added to greeter group (logout/login required for group membership)"
else
echo " Already in greeter group"
fi
# Set group permissions on config directories
echo
echo "Setting group permissions on config directories..."
# First, ensure parent directories are traversable by greeter user (using ACLs)
echo "Making parent directories traversable by greeter..."
if command -v setfacl >/dev/null 2>&1; then
# Set ACL on home directory
setfacl -m u:greeter:x ~ 2>/dev/null && echo " Home directory" || echo " Home directory (may need sudo)"
# Set ACLs on parent config directories
setfacl -m u:greeter:x ~/.config 2>/dev/null && echo " .config directory" || true
setfacl -m u:greeter:x ~/.local 2>/dev/null && echo " .local directory" || true
setfacl -m u:greeter:x ~/.cache 2>/dev/null && echo " .cache directory" || true
setfacl -m u:greeter:x ~/.local/state 2>/dev/null && echo " .local/state directory" || true
else
echo " setfacl not found, you need to run:"
echo " setfacl -m u:greeter:x ~ ~/.config ~/.local ~/.cache ~/.local/state"
fi
# Then set permissions on target directories
for dir in ~/.config/DankMaterialShell ~/.local/state/DankMaterialShell ~/.cache/quickshell; do
if [ -d "$dir" ]; then
sudo chgrp -R greeter "$dir"
sudo chmod -R g+rX "$dir"
echo " $(basename $dir)"
else
echo " $dir not found (will be created when you run DMS)"
fi
done
# Set group read on parent state directory
sudo chmod g+x ~/.local/state 2>/dev/null || true
# Create symlinks
echo
echo "Creating symlinks to sync theme..."
declare -A links=(
["$HOME/.config/DankMaterialShell/settings.json"]="$CACHE_DIR/settings.json"
["$HOME/.local/state/DankMaterialShell/session.json"]="$CACHE_DIR/session.json"
["$HOME/.cache/quickshell/dankshell/dms-colors.json"]="$CACHE_DIR/colors.json"
)
for source in "${!links[@]}"; do
target="${links[$source]}"
target_name=$(basename "$source")
if [ -f "$source" ]; then
sudo ln -sf "$source" "$target"
echo " Synced $target_name"
else
echo " $target_name not found yet (run DMS to generate it)"
fi
done
echo
echo "=== Setup Complete! ==="
echo
echo "IMPORTANT: You must LOGOUT and LOGIN for group membership to take effect."
echo "After logging back in, your theme will be synced with the greeter."
SYNC_EOF
chmod 755 %{buildroot}%{_bindir}/dms-greeter-sync
# Install documentation
install -Dm644 Modules/Greetd/README.md %{buildroot}%{_docdir}/dms-greeter/README.md
# Create cache directory for greeter data
install -dm750 %{buildroot}%{_localstatedir}/cache/dms-greeter
# Create greeter home directory
install -dm755 %{buildroot}%{_sharedstatedir}/greeter
# Note: We do NOT install a PAM config here to avoid conflicting with greetd package
# Instead, we verify/fix it in %post if needed
# Remove build and development files
rm -rf %{buildroot}%{_sysconfdir}/xdg/quickshell/dms-greeter/.git*
rm -f %{buildroot}%{_sysconfdir}/xdg/quickshell/dms-greeter/.gitignore
@@ -68,23 +171,94 @@ rm -f %{buildroot}%{_sysconfdir}/xdg/quickshell/dms-greeter/dms-greeter.spec
%license LICENSE
%doc %{_docdir}/dms-greeter/README.md
%{_bindir}/dms-greeter
%{_bindir}/dms-greeter-sync
%{_sysconfdir}/xdg/quickshell/dms-greeter/
%dir %attr(0750,greeter,greeter) %{_localstatedir}/cache/dms-greeter
%dir %attr(0755,greeter,greeter) %{_sharedstatedir}/greeter
%pre
# Create greeter user/group if they don't exist (greetd expects this)
getent group greeter >/dev/null || groupadd -r greeter
getent passwd greeter >/dev/null || \
useradd -r -g greeter -d /var/lib/greeter -s /sbin/nologin \
useradd -r -g greeter -d %{_sharedstatedir}/greeter -s /bin/bash \
-c "System Greeter" greeter
exit 0
%post
# Set SELinux context for the wrapper script on Fedora systems
if [ -x /usr/sbin/semanage ]; then
semanage fcontext -a -t bin_t %{_bindir}/dms-greeter 2>/dev/null || true
restorecon -v %{_bindir}/dms-greeter 2>/dev/null || true
# Set SELinux contexts for greeter files on Fedora systems
if [ -x /usr/sbin/semanage ] && [ -x /usr/sbin/restorecon ]; then
# Greeter launcher binary
semanage fcontext -a -t bin_t '%{_bindir}/dms-greeter' >/dev/null 2>&1 || true
restorecon %{_bindir}/dms-greeter >/dev/null 2>&1 || true
# Greeter home directory
semanage fcontext -a -t user_home_dir_t '%{_sharedstatedir}/greeter(/.*)?' >/dev/null 2>&1 || true
restorecon -R %{_sharedstatedir}/greeter >/dev/null 2>&1 || true
# Cache directory for greeter data
semanage fcontext -a -t cache_home_t '%{_localstatedir}/cache/dms-greeter(/.*)?' >/dev/null 2>&1 || true
restorecon -R %{_localstatedir}/cache/dms-greeter >/dev/null 2>&1 || true
# Config directory
semanage fcontext -a -t etc_t '%{_sysconfdir}/xdg/quickshell/dms-greeter(/.*)?' >/dev/null 2>&1 || true
restorecon -R %{_sysconfdir}/xdg/quickshell/dms-greeter >/dev/null 2>&1 || true
# PAM configuration
restorecon %{_sysconfdir}/pam.d/greetd >/dev/null 2>&1 || true
fi
# Ensure proper ownership of greeter directories
chown -R greeter:greeter %{_localstatedir}/cache/dms-greeter 2>/dev/null || true
chown -R greeter:greeter %{_sharedstatedir}/greeter 2>/dev/null || true
# Verify PAM configuration - only fix if insufficient
PAM_CONFIG="/etc/pam.d/greetd"
if [ ! -f "$PAM_CONFIG" ]; then
# PAM config doesn't exist - create it
cat > "$PAM_CONFIG" << 'PAM_EOF'
#%PAM-1.0
auth substack system-auth
auth include postlogin
account required pam_nologin.so
account include system-auth
password include system-auth
session required pam_selinux.so close
session required pam_loginuid.so
session required pam_selinux.so open
session optional pam_keyinit.so force revoke
session include system-auth
session include postlogin
PAM_EOF
chmod 644 "$PAM_CONFIG"
# Only show message on initial install
[ "$1" -eq 1 ] && echo "Created PAM configuration for greetd"
elif ! grep -q "pam_systemd\|system-auth" "$PAM_CONFIG"; then
# PAM config exists but looks insufficient - back it up and replace
cp "$PAM_CONFIG" "$PAM_CONFIG.backup-dms-greeter"
cat > "$PAM_CONFIG" << 'PAM_EOF'
#%PAM-1.0
auth substack system-auth
auth include postlogin
account required pam_nologin.so
account include system-auth
password include system-auth
session required pam_selinux.so close
session required pam_loginuid.so
session required pam_selinux.so open
session optional pam_keyinit.so force revoke
session include system-auth
session include postlogin
PAM_EOF
chmod 644 "$PAM_CONFIG"
# Only show message on initial install
[ "$1" -eq 1 ] && echo "Updated PAM configuration (old config backed up to $PAM_CONFIG.backup-dms-greeter)"
fi
# Auto-configure greetd config
@@ -132,42 +306,40 @@ cat << EOF
DMS Greeter Installation Complete!
===============================================================================
Configuration status:
- Greeter cache directory: /var/cache/dms-greeter (created with proper permissions)
- SELinux contexts: Applied (if semanage available)
Status:
- Greeter user: Created
- Greeter directories: /var/cache/dms-greeter, /var/lib/greeter
- SELinux contexts: Applied
- Greetd config: $CONFIG_STATUS
Next steps to enable the greeter:
Next steps:
1. IMPORTANT: Disable any existing display managers:
1. Disable any existing display managers (IMPORTANT):
sudo systemctl disable gdm sddm lightdm
(Only greetd should run as the display manager)
2. Verify greetd configuration:
Check /etc/greetd/config.toml contains:
[default_session]
user = "greeter"
command = "/usr/bin/dms-greeter --command niri"
(Also supported: hyprland, sway)
Note: Existing config backed up to config.toml.backup-* if modified
3. Enable greetd service:
2. Enable greetd service:
sudo systemctl enable greetd
4. (Optional) Sync your user's theme with the greeter:
sudo usermod -aG greeter YOUR_USERNAME
# Then LOGOUT and LOGIN to apply group membership
ln -sf ~/.config/DankMaterialShell/settings.json /var/cache/dms-greeter/settings.json
ln -sf ~/.local/state/DankMaterialShell/session.json /var/cache/dms-greeter/session.json
ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /var/cache/dms-greeter/colors.json
3. (Optional) Sync your theme with the greeter:
dms-greeter-sync
Then logout/login to see your wallpaper on the greeter!
Ready to test? Reboot or run: sudo systemctl start greetd
Documentation: /usr/share/doc/dms-greeter/README.md
===============================================================================
EOF
fi
%postun
# Clean up SELinux contexts on package removal
if [ "$1" -eq 0 ] && [ -x /usr/sbin/semanage ]; then
semanage fcontext -d '%{_bindir}/dms-greeter' 2>/dev/null || true
semanage fcontext -d '%{_sharedstatedir}/greeter(/.*)?' 2>/dev/null || true
semanage fcontext -d '%{_localstatedir}/cache/dms-greeter(/.*)?' 2>/dev/null || true
semanage fcontext -d '%{_sysconfdir}/xdg/quickshell/dms-greeter(/.*)?' 2>/dev/null || true
fi
%changelog
{{{ git_dir_changelog }}}

View File

@@ -18,14 +18,12 @@ Source0: {{{ git_dir_pack }}}
# DMS CLI from danklinux latest commit
Source1: https://github.com/AvengeMedia/danklinux/archive/refs/heads/master.tar.gz
# DGOP binary from dgop latest release
Source2: https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-amd64.gz
BuildRequires: git-core
BuildRequires: rpkg
BuildRequires: gzip
BuildRequires: golang >= 1.24
BuildRequires: make
BuildRequires: wget
# Core requirements
Requires: (quickshell-git or quickshell)
@@ -85,8 +83,25 @@ used standalone. This package always includes the latest stable dgop release.
# Extract DankLinux source
tar -xzf %{SOURCE1} -C %{_builddir}
# Extract DGOP binary
gunzip -c %{SOURCE2} > %{_builddir}/dgop
# Download and extract DGOP binary for target architecture
case "%{_arch}" in
x86_64)
DGOP_ARCH="amd64"
;;
aarch64)
DGOP_ARCH="arm64"
;;
*)
echo "Unsupported architecture: %{_arch}"
exit 1
;;
esac
wget -O %{_builddir}/dgop.gz "https://github.com/AvengeMedia/dgop/releases/latest/download/dgop-linux-${DGOP_ARCH}.gz" || {
echo "Failed to download dgop for architecture %{_arch}"
exit 1
}
gunzip -c %{_builddir}/dgop.gz > %{_builddir}/dgop
chmod +x %{_builddir}/dgop
%build
@@ -95,8 +110,21 @@ cd %{_builddir}/danklinux-master
make dist
%install
# Install dms-cli binary (built from source)
install -Dm755 %{_builddir}/danklinux-master/bin/dms-linux-amd64 %{buildroot}%{_bindir}/dms
# Install dms-cli binary (built from source) - use architecture-specific path
case "%{_arch}" in
x86_64)
DMS_BINARY="dms-linux-amd64"
;;
aarch64)
DMS_BINARY="dms-linux-arm64"
;;
*)
echo "Unsupported architecture: %{_arch}"
exit 1
;;
esac
install -Dm755 %{_builddir}/danklinux-master/bin/${DMS_BINARY} %{buildroot}%{_bindir}/dms
# Install dgop binary
install -Dm755 %{_builddir}/dgop %{buildroot}%{_bindir}/dgop

View File

@@ -140,7 +140,7 @@
{
"term": "Always Show OSD Percentage",
"context": "Always Show OSD Percentage",
"reference": "Modules/Settings/WidgetTweaksTab.qml:637",
"reference": "Modules/Settings/WidgetTweaksTab.qml:647",
"comment": ""
},
{
@@ -152,7 +152,7 @@
{
"term": "Anonymous Identity (optional)",
"context": "Anonymous Identity (optional)",
"reference": "Modals/WifiPasswordModal.qml:388",
"reference": "Modals/WifiPasswordModal.qml:282",
"comment": ""
},
{
@@ -368,7 +368,7 @@
{
"term": "Back",
"context": "Back",
"reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:451",
"reference": "Modules/DankBar/Widgets/SystemTrayBar.qml:454",
"comment": ""
},
{
@@ -482,7 +482,7 @@
{
"term": "Cancel",
"context": "Cancel",
"reference": "Modals/DankColorPickerModal.qml:510, Modals/WifiPasswordModal.qml:491, Modals/FileBrowser/FileBrowserModal.qml:952, Modules/Settings/PluginsTab.qml:1220",
"reference": "Modals/DankColorPickerModal.qml:510, Modals/WifiPasswordModal.qml:385, Modals/FileBrowser/FileBrowserModal.qml:952, Modules/Settings/PluginsTab.qml:1220",
"comment": ""
},
{
@@ -530,7 +530,7 @@
{
"term": "Choose where notification popups appear on screen",
"context": "Choose where notification popups appear on screen",
"reference": "Modules/Settings/WidgetTweaksTab.qml:564",
"reference": "Modules/Settings/WidgetTweaksTab.qml:574",
"comment": ""
},
{
@@ -542,7 +542,7 @@
{
"term": "Clear All",
"context": "Clear All",
"reference": "Modals/Clipboard/ClipboardHistoryModal.qml:157, Modules/Notifications/Center/NotificationHeader.qml:123",
"reference": "Modals/Clipboard/ClipboardHistoryModal.qml:157, Modules/Notifications/Center/NotificationHeader.qml:102",
"comment": ""
},
{
@@ -578,7 +578,7 @@
{
"term": "Close",
"context": "Close",
"reference": "Modules/SystemUpdatePopout.qml:333, Modals/NetworkInfoModal.qml:129, Modules/DankBar/Widgets/RunningApps.qml:614",
"reference": "Modules/SystemUpdatePopout.qml:333, Modals/NetworkWiredInfoModal.qml:129, Modals/NetworkInfoModal.qml:129, Modules/DankBar/Widgets/RunningApps.qml:614",
"comment": ""
},
{
@@ -602,31 +602,37 @@
{
"term": "Command or script to run instead of the standard hibernate procedure",
"context": "Command or script to run instead of the standard hibernate procedure",
"reference": "Modals/Settings/PowerSettings.qml:464",
"reference": "Modals/Settings/PowerSettings.qml:496",
"comment": ""
},
{
"term": "Command or script to run instead of the standard lock procedure",
"context": "Command or script to run instead of the standard lock procedure",
"reference": "Modals/Settings/PowerSettings.qml:400",
"comment": ""
},
{
"term": "Command or script to run instead of the standard logout procedure",
"context": "Command or script to run instead of the standard logout procedure",
"reference": "Modals/Settings/PowerSettings.qml:400",
"reference": "Modals/Settings/PowerSettings.qml:432",
"comment": ""
},
{
"term": "Command or script to run instead of the standard power off procedure",
"context": "Command or script to run instead of the standard power off procedure",
"reference": "Modals/Settings/PowerSettings.qml:528",
"reference": "Modals/Settings/PowerSettings.qml:560",
"comment": ""
},
{
"term": "Command or script to run instead of the standard reboot procedure",
"context": "Command or script to run instead of the standard reboot procedure",
"reference": "Modals/Settings/PowerSettings.qml:496",
"reference": "Modals/Settings/PowerSettings.qml:528",
"comment": ""
},
{
"term": "Command or script to run instead of the standard suspend procedure",
"context": "Command or script to run instead of the standard suspend procedure",
"reference": "Modals/Settings/PowerSettings.qml:432",
"reference": "Modals/Settings/PowerSettings.qml:464",
"comment": ""
},
{
@@ -650,7 +656,7 @@
{
"term": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.",
"context": "Configure icons for named workspaces. Icons take priority over numbers when both are enabled.",
"reference": "Modules/Settings/WidgetTweaksTab.qml:400",
"reference": "Modules/Settings/WidgetTweaksTab.qml:410",
"comment": ""
},
{
@@ -662,13 +668,13 @@
{
"term": "Connect",
"context": "Connect",
"reference": "Modals/WifiPasswordModal.qml:527",
"reference": "Modals/WifiPasswordModal.qml:419",
"comment": ""
},
{
"term": "Connect to Wi-Fi",
"context": "Connect to Wi-Fi",
"reference": "Modals/WifiPasswordModal.qml:124",
"reference": "Modals/WifiPasswordModal.qml:114",
"comment": ""
},
{
@@ -938,7 +944,7 @@
{
"term": "Display volume and brightness percentage values by default in OSD popups",
"context": "Display volume and brightness percentage values by default in OSD popups",
"reference": "Modules/Settings/WidgetTweaksTab.qml:644",
"reference": "Modules/Settings/WidgetTweaksTab.qml:654",
"comment": ""
},
{
@@ -956,7 +962,7 @@
{
"term": "Do Not Disturb",
"context": "Do Not Disturb",
"reference": "Modules/Notifications/Center/NotificationHeader.qml:56, Modules/Notifications/Center/NotificationSettings.qml:131",
"reference": "Modules/Notifications/Center/NotificationHeader.qml:41, Modules/Notifications/Center/NotificationSettings.qml:131",
"comment": ""
},
{
@@ -977,6 +983,12 @@
"reference": "Modules/Settings/DockTab.qml:530",
"comment": ""
},
{
"term": "Domain (optional)",
"context": "Domain (optional)",
"reference": "Modals/WifiPasswordModal.qml:314",
"comment": ""
},
{
"term": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.",
"context": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.",
@@ -1028,7 +1040,7 @@
{
"term": "Enable WiFi",
"context": "Enable WiFi",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:169",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:173",
"comment": ""
},
{
@@ -1052,7 +1064,7 @@
{
"term": "Enter credentials for ",
"context": "Enter credentials for ",
"reference": "Modals/WifiPasswordModal.qml:131",
"reference": "Modals/WifiPasswordModal.qml:121",
"comment": ""
},
{
@@ -1076,7 +1088,7 @@
{
"term": "Enter password for ",
"context": "Enter password for ",
"reference": "Modals/WifiPasswordModal.qml:131",
"reference": "Modals/WifiPasswordModal.qml:121",
"comment": ""
},
{
@@ -1178,7 +1190,7 @@
{
"term": "Forget Network",
"context": "Forget Network",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:422",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:598",
"comment": ""
},
{
@@ -1574,7 +1586,7 @@
{
"term": "Max apps to show",
"context": "Max apps to show",
"reference": "Modules/Settings/WidgetTweaksTab.qml:104",
"reference": "Modules/Settings/WidgetTweaksTab.qml:114",
"comment": ""
},
{
@@ -1592,7 +1604,7 @@
{
"term": "Media Player Settings",
"context": "Media Player Settings",
"reference": "Modules/Settings/WidgetTweaksTab.qml:173",
"reference": "Modules/Settings/WidgetTweaksTab.qml:183",
"comment": ""
},
{
@@ -1664,7 +1676,7 @@
{
"term": "Named Workspace Icons",
"context": "Named Workspace Icons",
"reference": "Modules/Settings/WidgetTweaksTab.qml:390",
"reference": "Modules/Settings/WidgetTweaksTab.qml:400",
"comment": ""
},
{
@@ -1688,19 +1700,19 @@
{
"term": "Network Info",
"context": "Network Info",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:399",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:340, Modules/ControlCenter/Details/NetworkDetail.qml:575",
"comment": ""
},
{
"term": "Network Information",
"context": "Network Information",
"reference": "Modals/NetworkInfoModal.qml:59",
"reference": "Modals/NetworkWiredInfoModal.qml:59, Modals/NetworkInfoModal.qml:59",
"comment": ""
},
{
"term": "Network Settings",
"context": "Network Settings",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:44",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:64",
"comment": ""
},
{
@@ -1814,7 +1826,7 @@
{
"term": "Notepad",
"context": "Notepad",
"reference": "DMSShell.qml:406, Modules/Settings/DankBarTab.qml:175",
"reference": "DMSShell.qml:407, Modules/Settings/DankBarTab.qml:175",
"comment": ""
},
{
@@ -1844,7 +1856,7 @@
{
"term": "Notification Popups",
"context": "Notification Popups",
"reference": "Modules/Settings/WidgetTweaksTab.qml:547",
"reference": "Modules/Settings/WidgetTweaksTab.qml:557",
"comment": ""
},
{
@@ -1898,7 +1910,7 @@
{
"term": "Open Notepad File",
"context": "Open Notepad File",
"reference": "Modules/Notepad/Notepad.qml:321",
"reference": "Modules/Notepad/Notepad.qml:325",
"comment": ""
},
{
@@ -1928,7 +1940,7 @@
{
"term": "Password",
"context": "Password",
"reference": "Modals/WifiPasswordModal.qml:211",
"reference": "Modals/WifiPasswordModal.qml:203",
"comment": ""
},
{
@@ -1946,7 +1958,7 @@
{
"term": "Per-Monitor Workspaces",
"context": "Per-Monitor Workspaces",
"reference": "Modules/Settings/WidgetTweaksTab.qml:135",
"reference": "Modules/Settings/WidgetTweaksTab.qml:145",
"comment": ""
},
{
@@ -2036,7 +2048,7 @@
{
"term": "Popup Position",
"context": "Popup Position",
"reference": "Modules/Settings/WidgetTweaksTab.qml:563",
"reference": "Modules/Settings/WidgetTweaksTab.qml:573",
"comment": ""
},
{
@@ -2141,12 +2153,6 @@
"reference": "Modules/DankDash/WeatherTab.qml:448, Modules/Settings/TimeWeatherTab.qml:1275",
"comment": ""
},
{
"term": "Realm / Domain (optional)",
"context": "Realm / Domain (optional)",
"reference": "Modals/WifiPasswordModal.qml:294",
"comment": ""
},
{
"term": "Reboot",
"context": "Reboot",
@@ -2204,25 +2210,25 @@
{
"term": "Running Apps Only In Current Workspace",
"context": "Running Apps Only In Current Workspace",
"reference": "Modules/Settings/WidgetTweaksTab.qml:350",
"reference": "Modules/Settings/WidgetTweaksTab.qml:360",
"comment": ""
},
{
"term": "Running Apps Settings",
"context": "Running Apps Settings",
"reference": "Modules/Settings/WidgetTweaksTab.qml:340",
"reference": "Modules/Settings/WidgetTweaksTab.qml:350",
"comment": ""
},
{
"term": "Save",
"context": "Save",
"reference": "Modals/FileBrowser/FileBrowserModal.qml:818, Modules/Notepad/NotepadTextEditor.qml:511, Modules/Notepad/Notepad.qml:476",
"reference": "Modals/FileBrowser/FileBrowserModal.qml:818, Modules/Notepad/NotepadTextEditor.qml:511, Modules/Notepad/Notepad.qml:480",
"comment": ""
},
{
"term": "Save Notepad File",
"context": "Save Notepad File",
"reference": "Modules/Notepad/Notepad.qml:257",
"reference": "Modules/Notepad/Notepad.qml:261",
"comment": ""
},
{
@@ -2339,12 +2345,6 @@
"reference": "Modules/Settings/DankBarTab.qml:156",
"comment": ""
},
{
"term": "Server Domain for certificate (optional)",
"context": "Server Domain for certificate (optional)",
"reference": "Modals/WifiPasswordModal.qml:420",
"comment": ""
},
{
"term": "Set different wallpapers for each connected monitor",
"context": "Set different wallpapers for each connected monitor",
@@ -2396,7 +2396,7 @@
{
"term": "Show Workspace Apps",
"context": "Show Workspace Apps",
"reference": "Modules/Settings/WidgetTweaksTab.qml:82",
"reference": "Modules/Settings/WidgetTweaksTab.qml:92",
"comment": ""
},
{
@@ -2420,7 +2420,7 @@
{
"term": "Show password",
"context": "Show password",
"reference": "Modals/WifiPasswordModal.qml:463",
"reference": "Modals/WifiPasswordModal.qml:357",
"comment": ""
},
{
@@ -2612,7 +2612,7 @@
{
"term": "System Updater",
"context": "System Updater",
"reference": "Modules/Settings/WidgetTweaksTab.qml:220",
"reference": "Modules/Settings/WidgetTweaksTab.qml:230",
"comment": ""
},
{
@@ -2630,7 +2630,7 @@
{
"term": "System update custom command",
"context": "System update custom command",
"reference": "Modules/Settings/WidgetTweaksTab.qml:251",
"reference": "Modules/Settings/WidgetTweaksTab.qml:261",
"comment": ""
},
{
@@ -2654,7 +2654,7 @@
{
"term": "Terminal custom additional parameters",
"context": "Terminal custom additional parameters",
"reference": "Modules/Settings/WidgetTweaksTab.qml:284",
"reference": "Modules/Settings/WidgetTweaksTab.qml:294",
"comment": ""
},
{
@@ -2774,7 +2774,7 @@
{
"term": "Unsaved Changes",
"context": "Unsaved Changes",
"reference": "Modules/Notepad/Notepad.qml:384",
"reference": "Modules/Notepad/Notepad.qml:388",
"comment": ""
},
{
@@ -2792,7 +2792,7 @@
{
"term": "Untitled",
"context": "Untitled",
"reference": "Services/NotepadStorageService.qml:62, Services/NotepadStorageService.qml:132, Services/NotepadStorageService.qml:173",
"reference": "Services/NotepadStorageService.qml:73, Services/NotepadStorageService.qml:143, Services/NotepadStorageService.qml:184",
"comment": ""
},
{
@@ -2810,7 +2810,7 @@
{
"term": "Use Custom Command",
"context": "Use Custom Command",
"reference": "Modules/Settings/WidgetTweaksTab.qml:230",
"reference": "Modules/Settings/WidgetTweaksTab.qml:240",
"comment": ""
},
{
@@ -2840,7 +2840,7 @@
{
"term": "Use custom command for update your system",
"context": "Use custom command for update your system",
"reference": "Modules/Settings/WidgetTweaksTab.qml:231",
"reference": "Modules/Settings/WidgetTweaksTab.qml:241",
"comment": ""
},
{
@@ -2876,7 +2876,7 @@
{
"term": "Username",
"context": "Username",
"reference": "Modals/WifiPasswordModal.qml:174",
"reference": "Modals/WifiPasswordModal.qml:166",
"comment": ""
},
{
@@ -2942,7 +2942,7 @@
{
"term": "Wave Progress Bars",
"context": "Wave Progress Bars",
"reference": "Modules/Settings/WidgetTweaksTab.qml:183",
"reference": "Modules/Settings/WidgetTweaksTab.qml:193",
"comment": ""
},
{
@@ -2966,7 +2966,7 @@
{
"term": "WiFi is off",
"context": "WiFi is off",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:151",
"reference": "Modules/ControlCenter/Details/NetworkDetail.qml:155",
"comment": ""
},
{
@@ -2993,6 +2993,12 @@
"reference": "Modules/DankDash/WeatherTab.qml:354, Modules/Settings/TimeWeatherTab.qml:1181",
"comment": ""
},
{
"term": "Window Scrolling",
"context": "Window Scrolling",
"reference": "Modules/Settings/WidgetTweaksTab.qml:70",
"comment": ""
},
{
"term": "Workspace",
"context": "Workspace",
@@ -3008,7 +3014,7 @@
{
"term": "Workspace Padding",
"context": "Workspace Padding",
"reference": "Modules/Settings/WidgetTweaksTab.qml:71",
"reference": "Modules/Settings/WidgetTweaksTab.qml:81",
"comment": ""
},
{
@@ -3026,25 +3032,25 @@
{
"term": "You have unsaved changes. Save before closing this tab?",
"context": "You have unsaved changes. Save before closing this tab?",
"reference": "Modules/Notepad/Notepad.qml:394",
"reference": "Modules/Notepad/Notepad.qml:398",
"comment": ""
},
{
"term": "You have unsaved changes. Save before continuing?",
"context": "You have unsaved changes. Save before continuing?",
"reference": "Modules/Notepad/Notepad.qml:397",
"reference": "Modules/Notepad/Notepad.qml:401",
"comment": ""
},
{
"term": "You have unsaved changes. Save before creating a new file?",
"context": "You have unsaved changes. Save before creating a new file?",
"reference": "Modules/Notepad/Notepad.qml:392",
"reference": "Modules/Notepad/Notepad.qml:396",
"comment": ""
},
{
"term": "You have unsaved changes. Save before opening a file?",
"context": "You have unsaved changes. Save before opening a file?",
"reference": "Modules/Notepad/Notepad.qml:396",
"reference": "Modules/Notepad/Notepad.qml:400",
"comment": ""
},
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -706,6 +706,13 @@
"reference": "",
"comment": ""
},
{
"term": "Command or script to run instead of the standard lock procedure",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Command or script to run instead of the standard logout procedure",
"translation": "",
@@ -1140,6 +1147,13 @@
"reference": "",
"comment": ""
},
{
"term": "Domain (optional)",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.",
"translation": "",
@@ -2498,13 +2512,6 @@
"reference": "",
"comment": ""
},
{
"term": "Realm / Domain (optional)",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Reboot",
"translation": "",
@@ -2729,13 +2736,6 @@
"reference": "",
"comment": ""
},
{
"term": "Server Domain for certificate (optional)",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Set different wallpapers for each connected monitor",
"translation": "",
@@ -3492,6 +3492,13 @@
"reference": "",
"comment": ""
},
{
"term": "Window Scrolling",
"translation": "",
"context": "",
"reference": "",
"comment": ""
},
{
"term": "Workspace",
"translation": "",