mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa07a846b9 | ||
|
|
5df46b605e | ||
|
|
77cf371a21 | ||
|
|
89802dd040 | ||
|
|
59b95e9dd6 | ||
|
|
b836db5252 | ||
|
|
4dc4b15925 | ||
|
|
5c3062e699 | ||
|
|
3a7777c643 | ||
|
|
71543c35d6 | ||
|
|
f4cf66dc01 | ||
|
|
7870dff0fd | ||
|
|
9fc9c1ed19 | ||
|
|
4d0151350f | ||
|
|
dff10c8d13 | ||
|
|
362bcb9294 | ||
|
|
351b4f8a94 | ||
|
|
90955eb0a1 | ||
|
|
62669747ad | ||
|
|
466d00c666 | ||
|
|
63845ff875 | ||
|
|
d013748a51 | ||
|
|
474af3bc07 | ||
|
|
8e09e155fa | ||
|
|
7f9f4f96b9 | ||
|
|
cd488a8623 | ||
|
|
080b7a28b1 | ||
|
|
6949ed0ebd | ||
|
|
8465fa45bb | ||
|
|
40835ffc89 | ||
|
|
01a42ff330 | ||
|
|
ba49654a64 | ||
|
|
bc6577fe18 | ||
|
|
4ca3f0da67 | ||
|
|
7f2086488b | ||
|
|
3014fd8095 | ||
|
|
27885c8ac3 | ||
|
|
d6be0509ac | ||
|
|
1c85f5e857 | ||
|
|
abe5515aca | ||
|
|
6fba975490 | ||
|
|
2de6798f45 | ||
|
|
04fdfa2a35 | ||
|
|
8f3085290d | ||
|
|
0839fe45f5 | ||
|
|
18f4795fda | ||
|
|
55d9fa622a | ||
|
|
7dc723c764 | ||
|
|
5a63205972 | ||
|
|
a4ceeafb1e | ||
|
|
242e05cc0e | ||
|
|
065dddbe6e | ||
|
|
fa6825252b | ||
|
|
b06e48a444 | ||
|
|
97dbd40f07 | ||
|
|
bc23109f99 | ||
|
|
ecb9675e9c | ||
|
|
e1f9b9e7a4 | ||
|
|
067b485bb3 | ||
|
|
67a4e3074e | ||
|
|
010bc4e8c3 | ||
|
|
9de5e3253e | ||
|
|
e32622ac48 | ||
|
|
5e2371c2cb | ||
|
|
a6ce26ee87 | ||
|
|
2a72c126f1 | ||
|
|
36e1a5d379 | ||
|
|
c12eafa1db | ||
|
|
9e26d8755c | ||
|
|
90bd30e351 | ||
|
|
3fb5d5c4f3 | ||
|
|
9f3685e4d5 | ||
|
|
6565988952 | ||
|
|
10b7a0875b | ||
|
|
bb4b9f1a58 | ||
|
|
981e527560 | ||
|
|
80b2ee719c | ||
|
|
6103d6196f | ||
|
|
ed1a5bfded | ||
|
|
3909ce3350 | ||
|
|
d64cd0b8a4 | ||
|
|
676aa9f93f | ||
|
|
ebd48e2556 | ||
|
|
ad5871aae4 | ||
|
|
e327b1ca5b | ||
|
|
ad43ca11eb | ||
|
|
41ba76e2e2 | ||
|
|
15e773434e | ||
|
|
ed118f4e7a | ||
|
|
3c420f2e30 | ||
|
|
4e271d4f0e | ||
|
|
27f9b3cd0b | ||
|
|
1ed4abd347 | ||
|
|
f71dd1ed54 | ||
|
|
19828d3b06 | ||
|
|
d242e729f0 | ||
|
|
8cd0d5faa5 | ||
|
|
a741d892a9 | ||
|
|
9add3361e0 |
16
.github/ISSUE_TEMPLATE/bug_report.md
vendored
16
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -26,6 +26,14 @@ assignees: ""
|
||||
- [ ] Hyprland
|
||||
- [ ] Other (specify)
|
||||
|
||||
## Distribution
|
||||
|
||||
<!-- Arch, Fedora, Debian, etc. -->
|
||||
|
||||
## dms version
|
||||
|
||||
<!-- Output of dms version command -->
|
||||
|
||||
## Description
|
||||
|
||||
<!-- Brief description of the issue -->
|
||||
@@ -45,6 +53,14 @@ assignees: ""
|
||||
## Error Messages/Logs
|
||||
|
||||
<!-- Please include any error messages, stack traces, or relevant logs -->
|
||||
<!-- you can get a log file with the following steps:
|
||||
dms kill
|
||||
mkdir ~/dms_logs
|
||||
nohup dms run > ~/dms_logs/dms-$(date +%s).txt 2>&1 &
|
||||
|
||||
Then trigger your issue, and share the contents of ~/dms_logs/dms-<timestamp>.txt
|
||||
|
||||
-->
|
||||
|
||||
```
|
||||
Paste error messages or logs here
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/support_request.md
vendored
8
.github/ISSUE_TEMPLATE/support_request.md
vendored
@@ -12,6 +12,14 @@ assignees: ""
|
||||
- [ ] Hyprland
|
||||
- [ ] other
|
||||
|
||||
## Distribution
|
||||
|
||||
<!-- Arch, Fedora, Debian, etc. -->
|
||||
|
||||
## dms version
|
||||
|
||||
<!-- Output of dms version command -->
|
||||
|
||||
## Description
|
||||
|
||||
<!-- Brief description of the support needed -->
|
||||
|
||||
138
.github/workflows/release.yml
vendored
138
.github/workflows/release.yml
vendored
@@ -57,7 +57,30 @@ jobs:
|
||||
CHANGELOG=$(git log --oneline --pretty=format:"- %s (%h)" "${PREVIOUS_TAG}..${TAG}")
|
||||
fi
|
||||
|
||||
cat > CHANGELOG.md << EOF
|
||||
cat > RELEASE_BODY.md << 'EOF'
|
||||
## Assets
|
||||
|
||||
### Complete Packages
|
||||
- **`dms-full-amd64.tar.gz`** - Complete package for x86_64 systems (CLI binaries + QML source + installation guide)
|
||||
- **`dms-full-arm64.tar.gz`** - Complete package for ARM64 systems (CLI binaries + QML source + installation guide)
|
||||
|
||||
### Individual Components
|
||||
- **`dms-cli-amd64.gz`** - DMS CLI binary for x86_64 systems
|
||||
- **`dms-cli-arm64.gz`** - DMS CLI binary for ARM64 systems
|
||||
- **`dms-distropkg-amd64.gz`** - DMS CLI binary built with distro_package tag for AMD64 systems
|
||||
- **`dms-distropkg-arm64.gz`** - DMS CLI binary built with distro_package tag for ARM64 systems
|
||||
- **`dms-qml.tar.gz`** - QML source code only
|
||||
|
||||
### Checksums
|
||||
- **`*.sha256`** - SHA256 checksums for verifying download integrity
|
||||
|
||||
**Installation:** Extract the `dms-full-*.tar.gz` package for your architecture and follow the `INSTALL.md` instructions inside.
|
||||
|
||||
---
|
||||
|
||||
EOF
|
||||
|
||||
cat >> RELEASE_BODY.md << EOF
|
||||
## What's Changed
|
||||
|
||||
$CHANGELOG
|
||||
@@ -66,7 +89,7 @@ jobs:
|
||||
EOF
|
||||
|
||||
echo "changelog<<EOF" >> $GITHUB_OUTPUT
|
||||
cat CHANGELOG.md >> $GITHUB_OUTPUT
|
||||
cat RELEASE_BODY.md >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create/Update DankMaterialShell Release
|
||||
@@ -80,18 +103,121 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Download DMS release assets
|
||||
- name: Download and prepare release assets
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euxo pipefail
|
||||
# gh is preinstalled on ubuntu-24.04; auth via GH_TOKEN env
|
||||
|
||||
mkdir -p _release_assets
|
||||
|
||||
# Download DMS CLI binaries from the danklinux repo
|
||||
gh release download "${TAG}" -R "${DMS_REPO}" --dir ./_dms_assets
|
||||
|
||||
- name: Attach DMS assets to DankMaterialShell release
|
||||
# Rename CLI binaries to dms-cli-* format and copy distropkg binaries
|
||||
for file in _dms_assets/dms-*.gz*; do
|
||||
if [ -f "$file" ]; then
|
||||
basename=$(basename "$file")
|
||||
if [[ "$basename" == dms-distropkg-* ]]; then
|
||||
cp "$file" "_release_assets/$basename"
|
||||
else
|
||||
newname=$(echo "$basename" | sed 's/^dms-/dms-cli-/')
|
||||
cp "$file" "_release_assets/$newname"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Create QML source package (exclude .git, .github, build artifacts)
|
||||
tar --exclude='.git' \
|
||||
--exclude='.github' \
|
||||
--exclude='_dms_assets' \
|
||||
--exclude='_release_assets' \
|
||||
--exclude='*.tar.gz' \
|
||||
-czf _release_assets/dms-qml.tar.gz .
|
||||
|
||||
# Generate checksum for QML package
|
||||
(cd _release_assets && sha256sum dms-qml.tar.gz > dms-qml.tar.gz.sha256)
|
||||
|
||||
# Create full packages for each architecture
|
||||
for arch in amd64 arm64; do
|
||||
mkdir -p _temp_full/dms
|
||||
mkdir -p _temp_full/bin
|
||||
|
||||
# Extract QML source to temp directory
|
||||
tar -xzf _release_assets/dms-qml.tar.gz -C _temp_full/dms
|
||||
|
||||
# Copy CLI binary if it exists
|
||||
if [ -f "_dms_assets/dms-${arch}.gz" ]; then
|
||||
gunzip -c "_dms_assets/dms-${arch}.gz" > _temp_full/bin/dms
|
||||
chmod +x _temp_full/bin/dms
|
||||
fi
|
||||
|
||||
# Copy distropkg binary if it exists
|
||||
if [ -f "_dms_assets/dms-distropkg-${arch}.gz" ]; then
|
||||
gunzip -c "_dms_assets/dms-distropkg-${arch}.gz" > _temp_full/bin/dms-distropkg
|
||||
chmod +x _temp_full/bin/dms-distropkg
|
||||
fi
|
||||
|
||||
# Create INSTALL.md
|
||||
cat > _temp_full/INSTALL.md << 'EOF'
|
||||
# DankMaterialShell Installation
|
||||
|
||||
## Requirements
|
||||
|
||||
- Wayland compositor (niri or Hyprland recommended)
|
||||
- Quickshell framework
|
||||
- Qt6
|
||||
|
||||
## Installation Steps
|
||||
|
||||
1. **Install quickshell assets:**
|
||||
```bash
|
||||
mkdir -p ~/.config/quickshell
|
||||
cp -r dms ~/.config/quickshell/
|
||||
```
|
||||
|
||||
2. **Install the DMS CLI binaries:**
|
||||
```bash
|
||||
sudo install -m 755 bin/dms /usr/local/bin/dms
|
||||
# or install to a local directory:
|
||||
mkdir -p ~/.local/bin
|
||||
install -m 755 bin/dms ~/.local/bin/dms
|
||||
```
|
||||
|
||||
3. **Start the shell:**
|
||||
```bash
|
||||
dms run
|
||||
# or directly with quickshell (will lack some dbus integrations & plugin management):
|
||||
quickshell -p ~/.config/quickshell/dms
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
- Settings are stored in `~/.config/DankMaterialShell/settings.json`
|
||||
- Plugins go in `~/.config/DankMaterialShell/plugins/`
|
||||
- See the documentation in the `dms/` directory for more details
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- Run with verbose output: `quickshell -v -p ~/.config/quickshell/dms`
|
||||
- Check logs in `~/.local/state/DankMaterialShell/`
|
||||
- Ensure all dependencies are installed
|
||||
EOF
|
||||
|
||||
# Create the full package
|
||||
(cd _temp_full && tar -czf "../_release_assets/dms-full-${arch}.tar.gz" .)
|
||||
|
||||
# Generate checksum
|
||||
(cd _release_assets && sha256sum "dms-full-${arch}.tar.gz" > "dms-full-${arch}.tar.gz.sha256")
|
||||
|
||||
# Cleanup
|
||||
rm -rf _temp_full
|
||||
done
|
||||
|
||||
- name: Attach all assets to release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ env.TAG }}
|
||||
files: _dms_assets/**
|
||||
files: _release_assets/**
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -72,10 +72,6 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getAppUsageRanking() {
|
||||
return appUsageRanking
|
||||
}
|
||||
|
||||
function getRankedApps() {
|
||||
var apps = []
|
||||
for (var appId in appUsageRanking) {
|
||||
|
||||
62
Common/DankSocket.qml
Normal file
62
Common/DankSocket.qml
Normal file
@@ -0,0 +1,62 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property alias path: socket.path
|
||||
property alias parser: socket.parser
|
||||
property bool connected: false
|
||||
|
||||
property int reconnectBaseMs: 400
|
||||
property int reconnectMaxMs: 15000
|
||||
|
||||
property int _reconnectAttempt: 0
|
||||
|
||||
signal connectionStateChanged()
|
||||
|
||||
onConnectedChanged: {
|
||||
socket.connected = connected
|
||||
}
|
||||
|
||||
Socket {
|
||||
id: socket
|
||||
|
||||
onConnectionStateChanged: {
|
||||
root.connectionStateChanged()
|
||||
if (connected) {
|
||||
root._reconnectAttempt = 0
|
||||
return
|
||||
}
|
||||
if (root.connected) {
|
||||
root._scheduleReconnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: reconnectTimer
|
||||
interval: 0
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
socket.connected = false
|
||||
Qt.callLater(() => socket.connected = true)
|
||||
}
|
||||
}
|
||||
|
||||
function send(data) {
|
||||
const json = typeof data === "string" ? data : JSON.stringify(data)
|
||||
const message = json.endsWith("\n") ? json : json + "\n"
|
||||
socket.write(message)
|
||||
socket.flush()
|
||||
}
|
||||
|
||||
function _scheduleReconnect() {
|
||||
const pow = Math.min(_reconnectAttempt, 10)
|
||||
const base = Math.min(reconnectBaseMs * Math.pow(2, pow), reconnectMaxMs)
|
||||
const jitter = Math.floor(Math.random() * Math.floor(base / 4))
|
||||
reconnectTimer.interval = base + jitter
|
||||
reconnectTimer.restart()
|
||||
_reconnectAttempt++
|
||||
}
|
||||
}
|
||||
113
Common/I18n.qml
Normal file
113
Common/I18n.qml
Normal file
@@ -0,0 +1,113 @@
|
||||
import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string _rawLocale: Qt.locale().name
|
||||
readonly property string _lang: _rawLocale.split(/[_-]/)[0]
|
||||
readonly property var _candidates: {
|
||||
const fullUnderscore = _rawLocale;
|
||||
const fullHyphen = _rawLocale.replace("_", "-");
|
||||
return [fullUnderscore, fullHyphen, _lang].filter(c => c && c !== "en");
|
||||
}
|
||||
|
||||
|
||||
readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports")
|
||||
|
||||
property string currentLocale: "en"
|
||||
property var translations: ({})
|
||||
property bool translationsLoaded: false
|
||||
|
||||
property url _selectedPath: ""
|
||||
|
||||
FolderListModel {
|
||||
id: dir
|
||||
folder: root.translationsFolder
|
||||
nameFilters: ["*.json"]
|
||||
showDirs: false
|
||||
showDotAndDotDot: false
|
||||
|
||||
onStatusChanged: if (status === FolderListModel.Ready) root._pickTranslation()
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: translationLoader
|
||||
path: root._selectedPath
|
||||
|
||||
onLoaded: {
|
||||
try {
|
||||
root.translations = JSON.parse(text())
|
||||
root.translationsLoaded = true
|
||||
console.log(`I18n: Loaded translations for '${root.currentLocale}' ` +
|
||||
`(${Object.keys(root.translations).length} contexts)`)
|
||||
} catch (e) {
|
||||
console.warn(`I18n: Error parsing '${root.currentLocale}':`, e,
|
||||
"- falling back to English")
|
||||
root._fallbackToEnglish()
|
||||
}
|
||||
}
|
||||
|
||||
onLoadFailed: (error) => {
|
||||
console.warn(`I18n: Failed to load '${root.currentLocale}' (${error}), ` +
|
||||
"falling back to English")
|
||||
root._fallbackToEnglish()
|
||||
}
|
||||
}
|
||||
|
||||
function _pickTranslation() {
|
||||
const present = new Set()
|
||||
for (let i = 0; i < dir.count; i++) {
|
||||
const name = dir.get(i, "fileName") // e.g. "zh_CN.json"
|
||||
if (name && name.endsWith(".json")) {
|
||||
present.add(name.slice(0, -5))
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < _candidates.length; i++) {
|
||||
const cand = _candidates[i]
|
||||
if (present.has(cand)) {
|
||||
_useLocale(cand, dir.folder + "/" + cand + ".json")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_fallbackToEnglish()
|
||||
}
|
||||
|
||||
function _useLocale(localeTag, fileUrl) {
|
||||
currentLocale = localeTag
|
||||
_selectedPath = fileUrl
|
||||
translationsLoaded = false
|
||||
translations = ({})
|
||||
console.log(`I18n: Using locale '${localeTag}' from ${fileUrl}`)
|
||||
}
|
||||
|
||||
function _fallbackToEnglish() {
|
||||
currentLocale = "en"
|
||||
_selectedPath = ""
|
||||
translationsLoaded = false
|
||||
translations = ({})
|
||||
console.warn("I18n: Falling back to built-in English strings")
|
||||
}
|
||||
|
||||
function tr(term, context) {
|
||||
if (!translationsLoaded || !translations) return term
|
||||
const ctx = context || term
|
||||
if (translations[ctx] && translations[ctx][term]) return translations[ctx][term]
|
||||
for (const c in translations) {
|
||||
if (translations[c] && translations[c][term]) return translations[c][term]
|
||||
}
|
||||
return term
|
||||
}
|
||||
|
||||
function trContext(context, term) {
|
||||
if (!translationsLoaded || !translations) return term
|
||||
if (translations[context] && translations[context][term]) return translations[context][term]
|
||||
return term
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,10 @@ Singleton {
|
||||
return stringify(path).replace("file://", "")
|
||||
}
|
||||
|
||||
function toFileUrl(path: string): string {
|
||||
return path.startsWith("file://") ? path : "file://" + path
|
||||
}
|
||||
|
||||
function mkdir(path: url): void {
|
||||
Quickshell.execDetached(["mkdir", "-p", strip(path)])
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ Singleton {
|
||||
property int batteryHibernateTimeout: 0 // Never
|
||||
|
||||
property bool lockBeforeSuspend: false
|
||||
property bool loginctlLockIntegration: true
|
||||
property var recentColors: []
|
||||
property bool showThirdPartyPlugins: false
|
||||
|
||||
@@ -152,6 +153,7 @@ Singleton {
|
||||
batterySuspendTimeout = settings.batterySuspendTimeout !== undefined ? settings.batterySuspendTimeout : 0
|
||||
batteryHibernateTimeout = settings.batteryHibernateTimeout !== undefined ? settings.batteryHibernateTimeout : 0
|
||||
lockBeforeSuspend = settings.lockBeforeSuspend !== undefined ? settings.lockBeforeSuspend : false
|
||||
loginctlLockIntegration = settings.loginctlLockIntegration !== undefined ? settings.loginctlLockIntegration : true
|
||||
recentColors = settings.recentColors !== undefined ? settings.recentColors : []
|
||||
showThirdPartyPlugins = settings.showThirdPartyPlugins !== undefined ? settings.showThirdPartyPlugins : false
|
||||
|
||||
@@ -215,6 +217,7 @@ Singleton {
|
||||
"batterySuspendTimeout": batterySuspendTimeout,
|
||||
"batteryHibernateTimeout": batteryHibernateTimeout,
|
||||
"lockBeforeSuspend": lockBeforeSuspend,
|
||||
"loginctlLockIntegration": loginctlLockIntegration,
|
||||
"recentColors": recentColors,
|
||||
"showThirdPartyPlugins": showThirdPartyPlugins
|
||||
}, null, 2))
|
||||
@@ -643,6 +646,11 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setLoginctlLockIntegration(enabled) {
|
||||
loginctlLockIntegration = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setShowThirdPartyPlugins(enabled) {
|
||||
showThirdPartyPlugins = enabled
|
||||
saveSettings()
|
||||
@@ -662,8 +670,8 @@ Singleton {
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSettings) {
|
||||
hasTriedDefaultSettings = true
|
||||
if (!isGreeterMode && !hasTriedDefaultSession) {
|
||||
hasTriedDefaultSession = true
|
||||
defaultSessionCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
@@ -692,7 +700,7 @@ Singleton {
|
||||
id: defaultSessionCheckProcess
|
||||
|
||||
command: ["sh", "-c", "CONFIG_DIR=\"" + _stateDir
|
||||
+ "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-session.json\" ] && [ ! -f \"$CONFIG_DIR/session.json\" ]; then cp \"$CONFIG_DIR/default-session.json\" \"$CONFIG_DIR/session.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
+ "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-session.json\" ] && [ ! -f \"$CONFIG_DIR/session.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-session.json\" \"$CONFIG_DIR/session.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
@@ -838,4 +846,4 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ Singleton {
|
||||
property string currentThemeName: "blue"
|
||||
property string customThemeFile: ""
|
||||
property string matugenScheme: "scheme-tonal-spot"
|
||||
property bool runUserMatugenTemplates: true
|
||||
property real dankBarTransparency: 1.0
|
||||
property real dankBarWidgetTransparency: 1.0
|
||||
property real popupTransparency: 1.0
|
||||
@@ -155,6 +156,14 @@ Singleton {
|
||||
property bool dankBarNoBackground: false
|
||||
property bool dankBarGothCornersEnabled: false
|
||||
property bool dankBarBorderEnabled: false
|
||||
property string dankBarBorderColor: "surfaceText"
|
||||
property real dankBarBorderOpacity: 1.0
|
||||
property real dankBarBorderThickness: 1
|
||||
|
||||
onDankBarBorderColorChanged: saveSettings()
|
||||
onDankBarBorderOpacityChanged: saveSettings()
|
||||
onDankBarBorderThicknessChanged: saveSettings()
|
||||
|
||||
property int dankBarPosition: SettingsData.Position.Top
|
||||
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
|
||||
property bool lockScreenShowPowerActions: true
|
||||
@@ -275,6 +284,7 @@ Singleton {
|
||||
}
|
||||
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
|
||||
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"
|
||||
runUserMatugenTemplates = settings.runUserMatugenTemplates !== undefined ? settings.runUserMatugenTemplates : true
|
||||
dankBarTransparency = settings.dankBarTransparency !== undefined ? (settings.dankBarTransparency > 1 ? settings.dankBarTransparency / 100 : settings.dankBarTransparency) : (settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 1.0)
|
||||
dankBarWidgetTransparency = settings.dankBarWidgetTransparency !== undefined ? (settings.dankBarWidgetTransparency > 1 ? settings.dankBarWidgetTransparency / 100 : settings.dankBarWidgetTransparency) : (settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 1.0)
|
||||
popupTransparency = settings.popupTransparency !== undefined ? (settings.popupTransparency > 1 ? settings.popupTransparency / 100 : settings.popupTransparency) : 1.0
|
||||
@@ -407,6 +417,9 @@ Singleton {
|
||||
dankBarNoBackground = settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : (settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false)
|
||||
dankBarGothCornersEnabled = settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : (settings.topBarGothCornersEnabled !== undefined ? settings.topBarGothCornersEnabled : false)
|
||||
dankBarBorderEnabled = settings.dankBarBorderEnabled !== undefined ? settings.dankBarBorderEnabled : false
|
||||
dankBarBorderColor = settings.dankBarBorderColor !== undefined ? settings.dankBarBorderColor : "surfaceText"
|
||||
dankBarBorderOpacity = settings.dankBarBorderOpacity !== undefined ? settings.dankBarBorderOpacity : 1.0
|
||||
dankBarBorderThickness = settings.dankBarBorderThickness !== undefined ? settings.dankBarBorderThickness : 1
|
||||
dankBarPosition = settings.dankBarPosition !== undefined ? settings.dankBarPosition : (settings.dankBarAtBottom !== undefined ? (settings.dankBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : (settings.topBarAtBottom !== undefined ? (settings.topBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : SettingsData.Position.Top))
|
||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
||||
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
|
||||
@@ -441,6 +454,7 @@ Singleton {
|
||||
"currentThemeName": currentThemeName,
|
||||
"customThemeFile": customThemeFile,
|
||||
"matugenScheme": matugenScheme,
|
||||
"runUserMatugenTemplates": runUserMatugenTemplates,
|
||||
"dankBarTransparency": dankBarTransparency,
|
||||
"dankBarWidgetTransparency": dankBarWidgetTransparency,
|
||||
"popupTransparency": popupTransparency,
|
||||
@@ -533,6 +547,9 @@ Singleton {
|
||||
"dankBarNoBackground": dankBarNoBackground,
|
||||
"dankBarGothCornersEnabled": dankBarGothCornersEnabled,
|
||||
"dankBarBorderEnabled": dankBarBorderEnabled,
|
||||
"dankBarBorderColor": dankBarBorderColor,
|
||||
"dankBarBorderOpacity": dankBarBorderOpacity,
|
||||
"dankBarBorderThickness": dankBarBorderThickness,
|
||||
"dankBarPosition": dankBarPosition,
|
||||
"lockScreenShowPowerActions": lockScreenShowPowerActions,
|
||||
"hideBrightnessSlider": hideBrightnessSlider,
|
||||
@@ -697,6 +714,18 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function setRunUserMatugenTemplates(enabled) {
|
||||
if (runUserMatugenTemplates === enabled)
|
||||
return
|
||||
|
||||
runUserMatugenTemplates = enabled
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setDankBarTransparency(transparency) {
|
||||
dankBarTransparency = transparency
|
||||
saveSettings()
|
||||
@@ -969,7 +998,7 @@ Singleton {
|
||||
updateQtIconTheme(themeName)
|
||||
saveSettings()
|
||||
if (typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic)
|
||||
Theme.generateSystemThemes()
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
|
||||
function updateGtkIconTheme(themeName) {
|
||||
@@ -1184,9 +1213,9 @@ Singleton {
|
||||
|
||||
function sendTestNotification(index) {
|
||||
const notifications = [
|
||||
["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "dialog-information"],
|
||||
["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "emblem-default"],
|
||||
["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "emblem-favorite"]
|
||||
["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "preferences-system"],
|
||||
["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "applications-graphics"],
|
||||
["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "face-smile"]
|
||||
]
|
||||
|
||||
if (index < 0 || index >= notifications.length) {
|
||||
@@ -1555,7 +1584,7 @@ Singleton {
|
||||
id: defaultSettingsCheckProcess
|
||||
|
||||
command: ["sh", "-c", "CONFIG_DIR=\"" + _configDir
|
||||
+ "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
+ "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
|
||||
@@ -74,7 +74,6 @@ Singleton {
|
||||
property bool qtThemingEnabled: typeof SettingsData !== "undefined" ? (SettingsData.qt5ctAvailable || SettingsData.qt6ctAvailable) : false
|
||||
property var workerRunning: false
|
||||
property var matugenColors: ({})
|
||||
property int colorUpdateTrigger: 0
|
||||
property var customThemeData: null
|
||||
|
||||
readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.CacheLocation).toString()) + "/dankshell"
|
||||
@@ -84,7 +83,6 @@ Singleton {
|
||||
matugenCheck.running = true
|
||||
if (typeof SessionData !== "undefined") {
|
||||
SessionData.isLightModeChanged.connect(root.onLightModeChanged)
|
||||
isLightMode = SessionData.isLightMode
|
||||
}
|
||||
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) {
|
||||
@@ -100,7 +98,6 @@ Singleton {
|
||||
}
|
||||
|
||||
function getMatugenColor(path, fallback) {
|
||||
colorUpdateTrigger
|
||||
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"
|
||||
let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode]
|
||||
for (const part of path.split(".")) {
|
||||
@@ -578,10 +575,6 @@ Singleton {
|
||||
|
||||
|
||||
function onLightModeChanged() {
|
||||
if (matugenColors && Object.keys(matugenColors).length > 0) {
|
||||
colorUpdateTrigger++
|
||||
}
|
||||
|
||||
if (currentTheme === "custom" && customThemeFileView.path) {
|
||||
customThemeFileView.reload()
|
||||
}
|
||||
@@ -603,7 +596,8 @@ Singleton {
|
||||
"mode": isLight ? "light" : "dark",
|
||||
"iconTheme": iconTheme || "System Default",
|
||||
"matugenType": matugenType || "scheme-tonal-spot",
|
||||
"surfaceBase": (typeof SettingsData !== "undefined" && SettingsData.surfaceBase) ? SettingsData.surfaceBase : "sc"
|
||||
"surfaceBase": (typeof SettingsData !== "undefined" && SettingsData.surfaceBase) ? SettingsData.surfaceBase : "sc",
|
||||
"runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true
|
||||
}
|
||||
|
||||
const json = JSON.stringify(desired)
|
||||
@@ -692,7 +686,17 @@ Singleton {
|
||||
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a); }
|
||||
|
||||
function snap(value, dpr) {
|
||||
return Math.round(value * dpr) / dpr
|
||||
const s = dpr || 1
|
||||
return Math.round(value * s) / s
|
||||
}
|
||||
|
||||
function px(value, dpr) {
|
||||
const s = dpr || 1
|
||||
return Math.round(value * s) / s
|
||||
}
|
||||
|
||||
function hairline(dpr) {
|
||||
return 1 / (dpr || 1)
|
||||
}
|
||||
|
||||
function invertHex(hex) {
|
||||
@@ -717,6 +721,8 @@ Singleton {
|
||||
if (typeof SettingsData === "undefined") return ""
|
||||
const colorOverride = SettingsData.launcherLogoColorOverride
|
||||
if (!colorOverride || colorOverride === "") return ""
|
||||
if (colorOverride === "primary") return primary
|
||||
if (colorOverride === "surface") return surfaceText
|
||||
return colorOverride
|
||||
}
|
||||
|
||||
@@ -726,15 +732,18 @@ Singleton {
|
||||
const colorOverride = SettingsData.launcherLogoColorOverride
|
||||
if (!colorOverride || colorOverride === "") return ""
|
||||
|
||||
if (colorOverride === "primary") return primary
|
||||
if (colorOverride === "surface") return surfaceText
|
||||
|
||||
if (!SettingsData.launcherLogoColorInvertOnMode) {
|
||||
return colorOverride
|
||||
}
|
||||
|
||||
if (typeof SessionData !== "undefined" && SessionData.isLightMode) {
|
||||
return invertHex(baseLogoColor)
|
||||
if (isLightMode) {
|
||||
return invertHex(colorOverride)
|
||||
}
|
||||
|
||||
return baseLogoColor
|
||||
return colorOverride
|
||||
}
|
||||
|
||||
|
||||
@@ -900,7 +909,6 @@ Singleton {
|
||||
const colorsText = dynamicColorsFileView.text()
|
||||
if (colorsText) {
|
||||
root.matugenColors = JSON.parse(colorsText)
|
||||
root.colorUpdateTrigger++
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.clearWallpaperError()
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import Quickshell.Services.Greetd
|
||||
import qs.Common
|
||||
import qs.Modules.Greetd
|
||||
|
||||
ShellRoot {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
WlSessionLock {
|
||||
|
||||
299
DMSShell.qml
299
DMSShell.qml
@@ -1,6 +1,3 @@
|
||||
//@ pragma Env QSG_RENDER_LOOP=threaded
|
||||
//@ pragma UseQApplication
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
@@ -29,24 +26,13 @@ import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
|
||||
|
||||
ShellRoot {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool servicesReady: false
|
||||
|
||||
Component.onCompleted: {
|
||||
PortalService.init()
|
||||
DisplayService.nightModeEnabled
|
||||
WallpaperCyclingService.cyclingActive
|
||||
PluginService.pluginDirectory
|
||||
Qt.callLater(() => {
|
||||
servicesReady = true
|
||||
})
|
||||
}
|
||||
|
||||
Instantiator {
|
||||
id: daemonPluginInstantiator
|
||||
model: servicesReady ? Object.keys(PluginService.pluginDaemonComponents) : []
|
||||
asynchronous: true
|
||||
model: Object.keys(PluginService.pluginDaemonComponents)
|
||||
|
||||
delegate: Loader {
|
||||
id: daemonLoader
|
||||
@@ -68,10 +54,26 @@ ShellRoot {
|
||||
|
||||
WallpaperBackground {}
|
||||
|
||||
Lock {
|
||||
id: lock
|
||||
LazyLoader {
|
||||
id: lockLoader
|
||||
active: false
|
||||
|
||||
anchors.fill: parent
|
||||
Lock {
|
||||
id: lock
|
||||
anchors.fill: parent
|
||||
|
||||
Component.onCompleted: {
|
||||
IdleService.lockComponent = lock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: lockInitTimer
|
||||
interval: 100
|
||||
running: true
|
||||
repeat: false
|
||||
onTriggered: lockLoader.active = true
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -193,7 +195,7 @@ ShellRoot {
|
||||
powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef
|
||||
|
||||
onLockRequested: {
|
||||
lock.activate()
|
||||
lockLoader.item.activate()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -407,7 +409,7 @@ ShellRoot {
|
||||
delegate: DankSlideout {
|
||||
id: notepadSlideout
|
||||
modelData: item
|
||||
title: qsTr("Notepad")
|
||||
title: I18n.tr("Notepad")
|
||||
slideoutWidth: 480
|
||||
expandable: true
|
||||
expandedWidthValue: 960
|
||||
@@ -471,253 +473,12 @@ ShellRoot {
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open() {
|
||||
powerMenuModalLoader.active = true
|
||||
if (powerMenuModalLoader.item)
|
||||
powerMenuModalLoader.item.openCentered()
|
||||
|
||||
return "POWERMENU_OPEN_SUCCESS"
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (powerMenuModalLoader.item)
|
||||
powerMenuModalLoader.item.close()
|
||||
|
||||
return "POWERMENU_CLOSE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
powerMenuModalLoader.active = true
|
||||
if (powerMenuModalLoader.item) {
|
||||
if (powerMenuModalLoader.item.shouldBeVisible) {
|
||||
powerMenuModalLoader.item.close()
|
||||
} else {
|
||||
powerMenuModalLoader.item.openCentered()
|
||||
}
|
||||
}
|
||||
|
||||
return "POWERMENU_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
target: "powermenu"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(): string {
|
||||
processListModalLoader.active = true
|
||||
if (processListModalLoader.item)
|
||||
processListModalLoader.item.show()
|
||||
|
||||
return "PROCESSLIST_OPEN_SUCCESS"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (processListModalLoader.item)
|
||||
processListModalLoader.item.hide()
|
||||
|
||||
return "PROCESSLIST_CLOSE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
processListModalLoader.active = true
|
||||
if (processListModalLoader.item)
|
||||
processListModalLoader.item.toggle()
|
||||
|
||||
return "PROCESSLIST_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
target: "processlist"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(): string {
|
||||
controlCenterLoader.active = true
|
||||
if (controlCenterLoader.item) {
|
||||
controlCenterLoader.item.open()
|
||||
return "CONTROL_CENTER_OPEN_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (controlCenterLoader.item) {
|
||||
controlCenterLoader.item.close()
|
||||
return "CONTROL_CENTER_CLOSE_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
controlCenterLoader.active = true
|
||||
if (controlCenterLoader.item) {
|
||||
controlCenterLoader.item.toggle()
|
||||
return "CONTROL_CENTER_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "control-center"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(tab: string): string {
|
||||
dankDashPopoutLoader.active = true
|
||||
if (dankDashPopoutLoader.item) {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "weather":
|
||||
dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
break
|
||||
default:
|
||||
dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
dankDashPopoutLoader.item.dashVisible = true
|
||||
return "DASH_OPEN_SUCCESS"
|
||||
}
|
||||
return "DASH_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (dankDashPopoutLoader.item) {
|
||||
dankDashPopoutLoader.item.dashVisible = false
|
||||
return "DASH_CLOSE_SUCCESS"
|
||||
}
|
||||
return "DASH_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(tab: string): string {
|
||||
dankDashPopoutLoader.active = true
|
||||
if (dankDashPopoutLoader.item) {
|
||||
if (dankDashPopoutLoader.item.dashVisible) {
|
||||
dankDashPopoutLoader.item.dashVisible = false
|
||||
} else {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "weather":
|
||||
dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
break
|
||||
default:
|
||||
dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
dankDashPopoutLoader.item.dashVisible = true
|
||||
}
|
||||
return "DASH_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "DASH_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "dash"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function getFocusedScreenName() {
|
||||
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
|
||||
return Hyprland.focusedWorkspace.monitor.name
|
||||
}
|
||||
if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||
return NiriService.currentOutput
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function getActiveNotepadInstance() {
|
||||
if (notepadSlideoutVariants.instances.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (notepadSlideoutVariants.instances.length === 1) {
|
||||
return notepadSlideoutVariants.instances[0]
|
||||
}
|
||||
|
||||
var focusedScreen = getFocusedScreenName()
|
||||
if (focusedScreen && notepadSlideoutVariants.instances.length > 0) {
|
||||
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = notepadSlideoutVariants.instances[i]
|
||||
if (slideout.modelData && slideout.modelData.name === focusedScreen) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = notepadSlideoutVariants.instances[i]
|
||||
if (slideout.isVisible) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
|
||||
return notepadSlideoutVariants.instances[0]
|
||||
}
|
||||
|
||||
function open(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.show()
|
||||
return "NOTEPAD_OPEN_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.hide()
|
||||
return "NOTEPAD_CLOSE_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.toggle()
|
||||
return "NOTEPAD_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "notepad"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function toggle(): string {
|
||||
SessionService.toggleIdleInhibit()
|
||||
return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled"
|
||||
}
|
||||
|
||||
function enable(): string {
|
||||
SessionService.enableIdleInhibit()
|
||||
return "Idle inhibit enabled"
|
||||
}
|
||||
|
||||
function disable(): string {
|
||||
SessionService.disableIdleInhibit()
|
||||
return "Idle inhibit disabled"
|
||||
}
|
||||
|
||||
function status(): string {
|
||||
return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled"
|
||||
}
|
||||
|
||||
function reason(newReason: string): string {
|
||||
if (!newReason) {
|
||||
return `Current reason: ${SessionService.inhibitReason}`
|
||||
}
|
||||
|
||||
SessionService.setInhibitReason(newReason)
|
||||
return `Inhibit reason set to: ${newReason}`
|
||||
}
|
||||
|
||||
target: "inhibit"
|
||||
DMSShellIPC {
|
||||
powerMenuModalLoader: powerMenuModalLoader
|
||||
processListModalLoader: processListModalLoader
|
||||
controlCenterLoader: controlCenterLoader
|
||||
dankDashPopoutLoader: dankDashPopoutLoader
|
||||
notepadSlideoutVariants: notepadSlideoutVariants
|
||||
}
|
||||
|
||||
Variants {
|
||||
|
||||
265
DMSShellIPC.qml
Normal file
265
DMSShellIPC.qml
Normal file
@@ -0,0 +1,265 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var powerMenuModalLoader
|
||||
required property var processListModalLoader
|
||||
required property var controlCenterLoader
|
||||
required property var dankDashPopoutLoader
|
||||
required property var notepadSlideoutVariants
|
||||
|
||||
IpcHandler {
|
||||
function open() {
|
||||
root.powerMenuModalLoader.active = true
|
||||
if (root.powerMenuModalLoader.item)
|
||||
root.powerMenuModalLoader.item.openCentered()
|
||||
|
||||
return "POWERMENU_OPEN_SUCCESS"
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (root.powerMenuModalLoader.item)
|
||||
root.powerMenuModalLoader.item.close()
|
||||
|
||||
return "POWERMENU_CLOSE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
root.powerMenuModalLoader.active = true
|
||||
if (root.powerMenuModalLoader.item) {
|
||||
if (root.powerMenuModalLoader.item.shouldBeVisible) {
|
||||
root.powerMenuModalLoader.item.close()
|
||||
} else {
|
||||
root.powerMenuModalLoader.item.openCentered()
|
||||
}
|
||||
}
|
||||
|
||||
return "POWERMENU_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
target: "powermenu"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(): string {
|
||||
root.processListModalLoader.active = true
|
||||
if (root.processListModalLoader.item)
|
||||
root.processListModalLoader.item.show()
|
||||
|
||||
return "PROCESSLIST_OPEN_SUCCESS"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (root.processListModalLoader.item)
|
||||
root.processListModalLoader.item.hide()
|
||||
|
||||
return "PROCESSLIST_CLOSE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
root.processListModalLoader.active = true
|
||||
if (root.processListModalLoader.item)
|
||||
root.processListModalLoader.item.toggle()
|
||||
|
||||
return "PROCESSLIST_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
target: "processlist"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(): string {
|
||||
root.controlCenterLoader.active = true
|
||||
if (root.controlCenterLoader.item) {
|
||||
root.controlCenterLoader.item.open()
|
||||
return "CONTROL_CENTER_OPEN_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (root.controlCenterLoader.item) {
|
||||
root.controlCenterLoader.item.close()
|
||||
return "CONTROL_CENTER_CLOSE_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
root.controlCenterLoader.active = true
|
||||
if (root.controlCenterLoader.item) {
|
||||
root.controlCenterLoader.item.toggle()
|
||||
return "CONTROL_CENTER_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "control-center"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(tab: string): string {
|
||||
root.dankDashPopoutLoader.active = true
|
||||
if (root.dankDashPopoutLoader.item) {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "weather":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
break
|
||||
default:
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
root.dankDashPopoutLoader.item.dashVisible = true
|
||||
return "DASH_OPEN_SUCCESS"
|
||||
}
|
||||
return "DASH_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (root.dankDashPopoutLoader.item) {
|
||||
root.dankDashPopoutLoader.item.dashVisible = false
|
||||
return "DASH_CLOSE_SUCCESS"
|
||||
}
|
||||
return "DASH_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(tab: string): string {
|
||||
root.dankDashPopoutLoader.active = true
|
||||
if (root.dankDashPopoutLoader.item) {
|
||||
if (root.dankDashPopoutLoader.item.dashVisible) {
|
||||
root.dankDashPopoutLoader.item.dashVisible = false
|
||||
} else {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "weather":
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
break
|
||||
default:
|
||||
root.dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
root.dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
root.dankDashPopoutLoader.item.dashVisible = true
|
||||
}
|
||||
return "DASH_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "DASH_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "dash"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function getFocusedScreenName() {
|
||||
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
|
||||
return Hyprland.focusedWorkspace.monitor.name
|
||||
}
|
||||
if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||
return NiriService.currentOutput
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function getActiveNotepadInstance() {
|
||||
if (root.notepadSlideoutVariants.instances.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (root.notepadSlideoutVariants.instances.length === 1) {
|
||||
return root.notepadSlideoutVariants.instances[0]
|
||||
}
|
||||
|
||||
var focusedScreen = getFocusedScreenName()
|
||||
if (focusedScreen && root.notepadSlideoutVariants.instances.length > 0) {
|
||||
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = root.notepadSlideoutVariants.instances[i]
|
||||
if (slideout.modelData && slideout.modelData.name === focusedScreen) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < root.notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = root.notepadSlideoutVariants.instances[i]
|
||||
if (slideout.isVisible) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
|
||||
return root.notepadSlideoutVariants.instances[0]
|
||||
}
|
||||
|
||||
function open(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.show()
|
||||
return "NOTEPAD_OPEN_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.hide()
|
||||
return "NOTEPAD_CLOSE_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.toggle()
|
||||
return "NOTEPAD_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "notepad"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function toggle(): string {
|
||||
SessionService.toggleIdleInhibit()
|
||||
return SessionService.idleInhibited ? "Idle inhibit enabled" : "Idle inhibit disabled"
|
||||
}
|
||||
|
||||
function enable(): string {
|
||||
SessionService.enableIdleInhibit()
|
||||
return "Idle inhibit enabled"
|
||||
}
|
||||
|
||||
function disable(): string {
|
||||
SessionService.disableIdleInhibit()
|
||||
return "Idle inhibit disabled"
|
||||
}
|
||||
|
||||
function status(): string {
|
||||
return SessionService.idleInhibited ? "Idle inhibit is enabled" : "Idle inhibit is disabled"
|
||||
}
|
||||
|
||||
function reason(newReason: string): string {
|
||||
if (!newReason) {
|
||||
return `Current reason: ${SessionService.inhibitReason}`
|
||||
}
|
||||
|
||||
SessionService.setInhibitReason(newReason)
|
||||
return `Inhibit reason set to: ${newReason}`
|
||||
}
|
||||
|
||||
target: "inhibit"
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ Item {
|
||||
showKeyboardHints: modal.showKeyboardHints
|
||||
onKeyboardHintsToggled: modal.showKeyboardHints = !modal.showKeyboardHints
|
||||
onClearAllClicked: {
|
||||
clearConfirmDialog.show("Clear All History?", "This will permanently delete all clipboard history.", function () {
|
||||
clearConfirmDialog.show(I18n.tr("Clear All History?"), I18n.tr("This will permanently delete all clipboard history."), function () {
|
||||
modal.clearAll()
|
||||
modal.hide()
|
||||
}, function () {})
|
||||
@@ -46,7 +46,7 @@ Item {
|
||||
leftIconName: "search"
|
||||
showClearButton: true
|
||||
focus: true
|
||||
ignoreLeftRightKeys: true
|
||||
ignoreTabKeys: true
|
||||
keyForwardTargets: [modal.modalFocusScope]
|
||||
onTextChanged: {
|
||||
modal.searchText = text
|
||||
@@ -116,7 +116,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No clipboard entries found")
|
||||
text: I18n.tr("No clipboard entries found")
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
|
||||
@@ -80,11 +80,11 @@ Rectangle {
|
||||
text: {
|
||||
switch (entryType) {
|
||||
case "image":
|
||||
return "Image • " + entryPreview
|
||||
return I18n.tr("Image") + " • " + entryPreview
|
||||
case "long_text":
|
||||
return "Long Text"
|
||||
return I18n.tr("Long Text")
|
||||
default:
|
||||
return "Text"
|
||||
return I18n.tr("Text")
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
|
||||
@@ -28,7 +28,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `Clipboard History (${totalCount})`
|
||||
text: I18n.tr("Clipboard History") + ` (${totalCount})`
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -91,7 +91,7 @@ DankModal {
|
||||
function copyEntry(entry) {
|
||||
const entryId = entry.split('\t')[0]
|
||||
Quickshell.execDetached(["sh", "-c", `cliphist decode ${entryId} | wl-copy`])
|
||||
ToastService.showInfo("Copied to clipboard")
|
||||
ToastService.showInfo(I18n.tr("Copied to clipboard"))
|
||||
hide()
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ DankModal {
|
||||
|
||||
ConfirmModal {
|
||||
id: clearConfirmDialog
|
||||
confirmButtonText: "Clear All"
|
||||
confirmButtonText: I18n.tr("Clear All")
|
||||
confirmButtonColor: Theme.primary
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
|
||||
@@ -6,6 +6,8 @@ import qs.Modals.Clipboard
|
||||
Rectangle {
|
||||
id: keyboardHints
|
||||
|
||||
readonly property string hintsText: I18n.tr("Shift+Del: Clear All • Esc: Close")
|
||||
|
||||
height: ClipboardConstants.keyboardHintsHeight
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
|
||||
@@ -26,7 +28,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Shift+Del: Clear All • Esc: Close")
|
||||
text: keyboardHints.hintsText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -68,9 +68,11 @@ DankModal {
|
||||
}
|
||||
}
|
||||
onOpened: {
|
||||
modalFocusScope.forceActiveFocus()
|
||||
modalFocusScope.focus = true
|
||||
shouldHaveFocus = true
|
||||
Qt.callLater(function () {
|
||||
modalFocusScope.forceActiveFocus()
|
||||
modalFocusScope.focus = true
|
||||
shouldHaveFocus = true
|
||||
})
|
||||
}
|
||||
modalFocusScope.Keys.onPressed: function (event) {
|
||||
switch (event.key) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
@@ -15,6 +16,17 @@ PanelWindow {
|
||||
property real height: 300
|
||||
readonly property real screenWidth: screen ? screen.width : 1920
|
||||
readonly property real screenHeight: screen ? screen.height : 1080
|
||||
readonly property real dpr: {
|
||||
if (CompositorService.isNiri && screen) {
|
||||
const niriScale = NiriService.displayScales[screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
}
|
||||
if (CompositorService.isHyprland && screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale
|
||||
}
|
||||
return (screen?.devicePixelRatio) || 1
|
||||
}
|
||||
property bool showBackground: true
|
||||
property real backgroundOpacity: 0.5
|
||||
property string positioning: "center"
|
||||
@@ -134,22 +146,26 @@ PanelWindow {
|
||||
Rectangle {
|
||||
id: contentContainer
|
||||
|
||||
width: root.width
|
||||
height: root.height
|
||||
anchors.centerIn: positioning === "center" ? parent : undefined
|
||||
width: Theme.px(root.width, dpr)
|
||||
height: Theme.px(root.height, dpr)
|
||||
anchors.centerIn: undefined
|
||||
x: {
|
||||
if (positioning === "top-right") {
|
||||
return Math.max(Theme.spacingL, root.screenWidth - width - Theme.spacingL)
|
||||
if (positioning === "center") {
|
||||
return Theme.snap((root.screenWidth - width) / 2, dpr)
|
||||
} else if (positioning === "top-right") {
|
||||
return Theme.px(Math.max(Theme.spacingL, root.screenWidth - width - Theme.spacingL), dpr)
|
||||
} else if (positioning === "custom") {
|
||||
return root.customPosition.x
|
||||
return Theme.snap(root.customPosition.x, dpr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
y: {
|
||||
if (positioning === "top-right") {
|
||||
return Theme.barHeight + Theme.spacingXS
|
||||
if (positioning === "center") {
|
||||
return Theme.snap((root.screenHeight - height) / 2, dpr)
|
||||
} else if (positioning === "top-right") {
|
||||
return Theme.px(Theme.barHeight + Theme.spacingXS, dpr)
|
||||
} else if (positioning === "custom") {
|
||||
return root.customPosition.y
|
||||
return Theme.snap(root.customPosition.y, dpr)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
@@ -159,13 +175,24 @@ PanelWindow {
|
||||
border.width: root.borderWidth
|
||||
clip: false
|
||||
layer.enabled: true
|
||||
opacity: root.shouldBeVisible ? 1 : 0
|
||||
transform: root.animationType === "slide" ? slideTransform : null
|
||||
|
||||
Translate {
|
||||
id: slideTransform
|
||||
|
||||
x: root.shouldBeVisible ? 0 : 15
|
||||
y: root.shouldBeVisible ? 0 : -30
|
||||
readonly property real rawX: root.shouldBeVisible ? 0 : 15
|
||||
readonly property real rawY: root.shouldBeVisible ? 0 : -30
|
||||
|
||||
x: Theme.snap(rawX, root.dpr)
|
||||
y: Theme.snap(rawY, root.dpr)
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: animationDuration
|
||||
easing.type: animationEasing
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
@@ -189,24 +216,6 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
shadowHorizontalOffset: 0
|
||||
shadowVerticalOffset: 8
|
||||
shadowBlur: 1
|
||||
shadowColor: Theme.shadowStrong
|
||||
shadowOpacity: 0.3
|
||||
source: contentContainer
|
||||
opacity: root.shouldBeVisible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: animationDuration
|
||||
easing.type: animationEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
|
||||
@@ -188,7 +188,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Select a color from the palette or use custom sliders")
|
||||
text: I18n.tr("Select a color from the palette or use custom sliders")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
@@ -346,7 +346,7 @@ PanelWindow {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Material Colors")
|
||||
text: I18n.tr("Material Colors")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -394,7 +394,7 @@ PanelWindow {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Recent Colors")
|
||||
text: I18n.tr("Recent Colors")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -444,7 +444,7 @@ PanelWindow {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Opacity")
|
||||
text: I18n.tr("Opacity")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -480,7 +480,7 @@ PanelWindow {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Hex:")
|
||||
text: I18n.tr("Hex:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceTextMedium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -518,7 +518,7 @@ PanelWindow {
|
||||
DankButton {
|
||||
width: 80
|
||||
buttonHeight: 36
|
||||
text: qsTr("Apply")
|
||||
text: I18n.tr("Apply")
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.background
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -545,7 +545,7 @@ PanelWindow {
|
||||
DankButton {
|
||||
width: 70
|
||||
buttonHeight: 36
|
||||
text: qsTr("Cancel")
|
||||
text: I18n.tr("Cancel")
|
||||
backgroundColor: "transparent"
|
||||
textColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -564,7 +564,7 @@ PanelWindow {
|
||||
DankButton {
|
||||
width: 70
|
||||
buttonHeight: 36
|
||||
text: qsTr("Copy")
|
||||
text: I18n.tr("Copy")
|
||||
backgroundColor: Theme.primary
|
||||
textColor: Theme.background
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -621,7 +621,6 @@ DankModal {
|
||||
required property bool fileIsDir
|
||||
required property string filePath
|
||||
required property string fileName
|
||||
required property url fileURL
|
||||
required property int index
|
||||
|
||||
width: weMode ? 245 : 140
|
||||
@@ -781,7 +780,7 @@ DankModal {
|
||||
width: parent.width - saveButton.width - Theme.spacingM
|
||||
height: 40
|
||||
text: defaultFileName
|
||||
placeholderText: qsTr("Enter filename...")
|
||||
placeholderText: I18n.tr("Enter filename...")
|
||||
ignoreLeftRightKeys: false
|
||||
focus: saveMode
|
||||
topPadding: Theme.spacingS
|
||||
@@ -814,7 +813,7 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Save")
|
||||
text: I18n.tr("Save")
|
||||
color: fileNameInput.text.trim() !== "" ? Theme.primaryText : Theme.surfaceVariantText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
}
|
||||
@@ -918,7 +917,7 @@ DankModal {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("File Already Exists")
|
||||
text: I18n.tr("File Already Exists")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -926,7 +925,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("A file with this name already exists. Do you want to overwrite it?")
|
||||
text: I18n.tr("A file with this name already exists. Do you want to overwrite it?")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceTextMedium
|
||||
width: parent.width
|
||||
@@ -948,7 +947,7 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Cancel")
|
||||
text: I18n.tr("Cancel")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -974,7 +973,7 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Overwrite")
|
||||
text: I18n.tr("Overwrite")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -134,7 +134,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("File Information")
|
||||
text: I18n.tr("File Information")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -197,7 +197,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "F1/I: Toggle • F10: Help"
|
||||
text: I18n.tr("F1/I: Toggle • F10: Help")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
@@ -23,7 +23,7 @@ Rectangle {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: "Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select"
|
||||
text: I18n.tr("Tab/Shift+Tab: Nav • ←→↑↓: Grid Nav • Enter/Space: Select")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
width: parent.width
|
||||
@@ -32,7 +32,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close"
|
||||
text: I18n.tr("Alt+←/Backspace: Back • F1/I: File Info • F10: Help • Esc: Close")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
width: parent.width
|
||||
|
||||
@@ -56,7 +56,7 @@ DankModal {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Network Information")
|
||||
text: I18n.tr("Network Information")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -126,7 +126,7 @@ DankModal {
|
||||
id: closeText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Close")
|
||||
text: I18n.tr("Close")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -54,6 +54,9 @@ DankModal {
|
||||
height: 700
|
||||
visible: false
|
||||
onBackgroundClicked: hide()
|
||||
onOpened: () => {
|
||||
Qt.callLater(() => modalFocusScope.forceActiveFocus());
|
||||
}
|
||||
onShouldBeVisibleChanged: (shouldBeVisible) => {
|
||||
if (!shouldBeVisible) {
|
||||
notificationModalOpen = false
|
||||
|
||||
@@ -32,24 +32,24 @@ DankModal {
|
||||
close();
|
||||
const actions = {
|
||||
"logout": {
|
||||
"title": qsTr("Log Out"),
|
||||
"message": qsTr("Are you sure you want to log out?")
|
||||
"title": I18n.tr("Log Out"),
|
||||
"message": I18n.tr("Are you sure you want to log out?")
|
||||
},
|
||||
"suspend": {
|
||||
"title": qsTr("Suspend"),
|
||||
"message": qsTr("Are you sure you want to suspend the system?")
|
||||
"title": I18n.tr("Suspend"),
|
||||
"message": I18n.tr("Are you sure you want to suspend the system?")
|
||||
},
|
||||
"hibernate": {
|
||||
"title": qsTr("Hibernate"),
|
||||
"message": qsTr("Are you sure you want to hibernate the system?")
|
||||
"title": I18n.tr("Hibernate"),
|
||||
"message": I18n.tr("Are you sure you want to hibernate the system?")
|
||||
},
|
||||
"reboot": {
|
||||
"title": qsTr("Reboot"),
|
||||
"message": qsTr("Are you sure you want to reboot the system?")
|
||||
"title": I18n.tr("Reboot"),
|
||||
"message": I18n.tr("Are you sure you want to reboot the system?")
|
||||
},
|
||||
"poweroff": {
|
||||
"title": qsTr("Power Off"),
|
||||
"message": qsTr("Are you sure you want to power off the system?")
|
||||
"title": I18n.tr("Power Off"),
|
||||
"message": I18n.tr("Are you sure you want to power off the system?")
|
||||
}
|
||||
}
|
||||
const selected = actions[action]
|
||||
@@ -78,7 +78,7 @@ DankModal {
|
||||
}
|
||||
onOpened: () => {
|
||||
selectedIndex = 0;
|
||||
modalFocusScope.forceActiveFocus();
|
||||
Qt.callLater(() => modalFocusScope.forceActiveFocus());
|
||||
}
|
||||
modalFocusScope.Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
@@ -144,7 +144,7 @@ DankModal {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Power Options")
|
||||
text: I18n.tr("Power Options")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -201,7 +201,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Log Out")
|
||||
text: I18n.tr("Log Out")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -254,7 +254,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Suspend")
|
||||
text: I18n.tr("Suspend")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -308,7 +308,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Hibernate")
|
||||
text: I18n.tr("Hibernate")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -362,7 +362,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Reboot")
|
||||
text: I18n.tr("Reboot")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -416,7 +416,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Power Off")
|
||||
text: I18n.tr("Power Off")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -123,7 +123,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("System Monitor Unavailable")
|
||||
text: I18n.tr("System Monitor Unavailable")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Bold
|
||||
color: Theme.error
|
||||
@@ -131,7 +131,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature."
|
||||
text: I18n.tr("The 'dgop' tool is required for system monitoring.\nPlease install dgop to use this feature.")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -154,7 +154,7 @@ DankModal {
|
||||
height: 40
|
||||
|
||||
StyledText {
|
||||
text: qsTr("System Monitor")
|
||||
text: I18n.tr("System Monitor")
|
||||
font.pixelSize: Theme.fontSizeLarge + 4
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
|
||||
@@ -19,12 +19,87 @@ Item {
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Battery not detected - only AC power settings available")
|
||||
text: I18n.tr("Battery not detected - only AC power settings available")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
visible: !BatteryService.batteryAvailable
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: lockScreenSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: lockScreenSection
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "lock"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Lock Screen")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show Power Actions")
|
||||
description: "Show power, restart, and logout buttons on the lock screen"
|
||||
checked: SettingsData.lockScreenShowPowerActions
|
||||
onToggled: checked => SettingsData.setLockScreenShowPowerActions(checked)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("loginctl not available - lock integration requires DMS socket connection")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning
|
||||
visible: !SessionService.loginctlAvailable
|
||||
width: parent.width
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Enable loginctl lock integration")
|
||||
description: "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen."
|
||||
checked: SessionService.loginctlAvailable && SessionData.loginctlLockIntegration
|
||||
enabled: SessionService.loginctlAvailable
|
||||
onToggled: checked => {
|
||||
if (SessionService.loginctlAvailable) {
|
||||
SessionData.setLoginctlLockIntegration(checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Lock before suspend")
|
||||
description: "Automatically lock the screen when the system prepares to suspend"
|
||||
checked: SessionData.lockBeforeSuspend
|
||||
visible: SessionService.loginctlAvailable && SessionData.loginctlLockIntegration
|
||||
onToggled: checked => SessionData.setLockBeforeSuspend(checked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: timeoutSection.implicitHeight + Theme.spacingL * 2
|
||||
@@ -51,7 +126,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Idle Settings")
|
||||
text: I18n.tr("Idle Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -79,7 +154,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
text: qsTr("Automatically lock after")
|
||||
text: I18n.tr("Automatically lock after")
|
||||
options: timeoutOptions
|
||||
|
||||
Connections {
|
||||
@@ -115,7 +190,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
text: qsTr("Turn off monitors after")
|
||||
text: I18n.tr("Turn off monitors after")
|
||||
options: timeoutOptions
|
||||
|
||||
Connections {
|
||||
@@ -151,7 +226,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
text: qsTr("Suspend system after")
|
||||
text: I18n.tr("Suspend system after")
|
||||
options: timeoutOptions
|
||||
|
||||
Connections {
|
||||
@@ -187,7 +262,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
text: qsTr("Hibernate system after")
|
||||
text: I18n.tr("Hibernate system after")
|
||||
options: timeoutOptions
|
||||
visible: SessionService.hibernateSupported
|
||||
|
||||
@@ -219,16 +294,8 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Lock before suspend")
|
||||
description: "Automatically lock the screen when the system prepares to suspend"
|
||||
checked: SessionData.lockBeforeSuspend
|
||||
onToggled: checked => SessionData.setLockBeforeSuspend(checked)
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Idle monitoring not supported - requires newer Quickshell version")
|
||||
text: I18n.tr("Idle monitoring not supported - requires newer Quickshell version")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.error
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -35,27 +35,14 @@ FocusScope {
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: timeLoader
|
||||
id: timeWeatherLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 1
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: TimeTab {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: weatherLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 2
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: WeatherTab {
|
||||
sourceComponent: TimeWeatherTab {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -64,7 +51,7 @@ FocusScope {
|
||||
id: topBarLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 3
|
||||
active: root.currentIndex === 2
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -78,7 +65,7 @@ FocusScope {
|
||||
id: widgetsLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 4
|
||||
active: root.currentIndex === 3
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -91,7 +78,7 @@ FocusScope {
|
||||
id: dockLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 5
|
||||
active: root.currentIndex === 4
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -107,7 +94,7 @@ FocusScope {
|
||||
id: displaysLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 6
|
||||
active: root.currentIndex === 5
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -120,7 +107,7 @@ FocusScope {
|
||||
id: launcherLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 7
|
||||
active: root.currentIndex === 6
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -133,7 +120,7 @@ FocusScope {
|
||||
id: themeColorsLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 8
|
||||
active: root.currentIndex === 7
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -146,7 +133,7 @@ FocusScope {
|
||||
id: powerLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 9
|
||||
active: root.currentIndex === 8
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -159,7 +146,7 @@ FocusScope {
|
||||
id: pluginsLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 10
|
||||
active: root.currentIndex === 9
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
@@ -173,7 +160,7 @@ FocusScope {
|
||||
id: aboutLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 11
|
||||
active: root.currentIndex === 10
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Settings")
|
||||
text: I18n.tr("Settings")
|
||||
font.pixelSize: Theme.fontSizeXLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -9,40 +9,37 @@ Rectangle {
|
||||
property int currentIndex: 0
|
||||
property var parentModal: null
|
||||
readonly property var sidebarItems: [{
|
||||
"text": "Personalization",
|
||||
"text": I18n.tr("Personalization"),
|
||||
"icon": "person"
|
||||
}, {
|
||||
"text": "Time & Date",
|
||||
"text": I18n.tr("Time & Weather"),
|
||||
"icon": "schedule"
|
||||
}, {
|
||||
"text": "Weather",
|
||||
"icon": "cloud"
|
||||
}, {
|
||||
"text": "Dank Bar",
|
||||
"text": I18n.tr("Dank Bar"),
|
||||
"icon": "toolbar"
|
||||
}, {
|
||||
"text": "Widgets",
|
||||
"text": I18n.tr("Widgets"),
|
||||
"icon": "widgets"
|
||||
}, {
|
||||
"text": "Dock",
|
||||
"text": I18n.tr("Dock"),
|
||||
"icon": "dock_to_bottom"
|
||||
}, {
|
||||
"text": "Displays",
|
||||
"text": I18n.tr("Displays"),
|
||||
"icon": "monitor"
|
||||
}, {
|
||||
"text": "Launcher",
|
||||
"text": I18n.tr("Launcher"),
|
||||
"icon": "apps"
|
||||
}, {
|
||||
"text": "Theme & Colors",
|
||||
"text": I18n.tr("Theme & Colors"),
|
||||
"icon": "palette"
|
||||
}, {
|
||||
"text": "Power",
|
||||
"icon": "power_settings_new"
|
||||
"text": I18n.tr("Idle & Lock Screen"),
|
||||
"icon": "lock"
|
||||
}, {
|
||||
"text": "Plugins",
|
||||
"text": I18n.tr("Plugins"),
|
||||
"icon": "extension"
|
||||
}, {
|
||||
"text": "About",
|
||||
"text": I18n.tr("About"),
|
||||
"icon": "info"
|
||||
}]
|
||||
|
||||
|
||||
@@ -81,10 +81,6 @@ Item {
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
appLauncher.launchSelected()
|
||||
event.accepted = true
|
||||
} else if (!searchField.activeFocus && event.text && event.text.length > 0 && event.text.match(/[a-zA-Z0-9\\s]/)) {
|
||||
searchField.forceActiveFocus()
|
||||
searchField.insertText(event.text)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +127,8 @@ Item {
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
enabled: parentModal ? parentModal.spotlightOpen : true
|
||||
placeholderText: ""
|
||||
ignoreLeftRightKeys: true
|
||||
ignoreLeftRightKeys: appLauncher.viewMode !== "list"
|
||||
ignoreTabKeys: true
|
||||
keyForwardTargets: [spotlightKeyHandler]
|
||||
text: appLauncher.searchQuery
|
||||
onTextEdited: () => {
|
||||
|
||||
@@ -24,7 +24,7 @@ Popup {
|
||||
contextMenu.close()
|
||||
}
|
||||
|
||||
width: Math.max(180, Math.min(300, menuColumn.implicitWidth + Theme.spacingS * 2))
|
||||
width: Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)
|
||||
height: menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
padding: 0
|
||||
closePolicy: Popup.CloseOnPressOutside
|
||||
@@ -77,12 +77,14 @@ Popup {
|
||||
spacing: 1
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
implicitWidth: pinRow.implicitWidth + Theme.spacingS * 2
|
||||
width: implicitWidth
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: pinMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
id: pinRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -105,10 +107,10 @@ Popup {
|
||||
StyledText {
|
||||
text: {
|
||||
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
|
||||
return "Pin to Dock"
|
||||
return I18n.tr("Pin to Dock")
|
||||
|
||||
const appId = contextMenu.currentApp.desktopEntry.id || contextMenu.currentApp.desktopEntry.execString || ""
|
||||
return SessionData.isPinnedApp(appId) ? "Unpin from Dock" : "Pin to Dock"
|
||||
return SessionData.isPinnedApp(appId) ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock")
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
@@ -155,16 +157,16 @@ Popup {
|
||||
model: contextMenu.currentApp && contextMenu.currentApp.desktopEntry && contextMenu.currentApp.desktopEntry.actions ? contextMenu.currentApp.desktopEntry.actions : []
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
implicitWidth: actionRow.implicitWidth + Theme.spacingS * 2
|
||||
width: implicitWidth
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: actionMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
id: actionRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
@@ -189,8 +191,6 @@ Popup {
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
elide: Text.ElideRight
|
||||
width: parent.width - (modelData.icon && modelData.icon !== "" ? (Theme.iconSize - 2 + Theme.spacingS) : 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,12 +228,14 @@ Popup {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
implicitWidth: launchRow.implicitWidth + Theme.spacingS * 2
|
||||
width: implicitWidth
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: launchMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
id: launchRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -248,7 +250,7 @@ Popup {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch")
|
||||
text: I18n.tr("Launch")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -288,12 +290,14 @@ Popup {
|
||||
|
||||
Rectangle {
|
||||
visible: SessionService.hasPrimeRun
|
||||
width: parent.width
|
||||
implicitWidth: primeRunRow.implicitWidth + Theme.spacingS * 2
|
||||
width: implicitWidth
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: primeRunMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
id: primeRunRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -308,7 +312,7 @@ Popup {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch on dGPU")
|
||||
text: I18n.tr("Launch on dGPU")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
|
||||
@@ -36,7 +36,7 @@ DankModal {
|
||||
if (contentLoader.item.appLauncher) {
|
||||
contentLoader.item.appLauncher.searchQuery = ""
|
||||
contentLoader.item.appLauncher.selectedIndex = 0
|
||||
contentLoader.item.appLauncher.setCategory("All")
|
||||
contentLoader.item.appLauncher.setCategory(I18n.tr("All"))
|
||||
}
|
||||
if (contentLoader.item.resetScroll) {
|
||||
contentLoader.item.resetScroll()
|
||||
|
||||
@@ -19,7 +19,7 @@ Rectangle {
|
||||
height: parent.height - y
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
clip: false
|
||||
clip: true
|
||||
|
||||
DankListView {
|
||||
id: resultsList
|
||||
|
||||
@@ -9,33 +9,53 @@ DankModal {
|
||||
|
||||
property string wifiPasswordSSID: ""
|
||||
property string wifiPasswordInput: ""
|
||||
property string wifiUsernameInput: ""
|
||||
property bool requiresEnterprise: false
|
||||
|
||||
function show(ssid) {
|
||||
wifiPasswordSSID = ssid
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
|
||||
const network = NetworkService.wifiNetworks.find(n => n.ssid === ssid)
|
||||
requiresEnterprise = network?.enterprise || false
|
||||
|
||||
open()
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.passwordInput)
|
||||
contentLoader.item.passwordInput.forceActiveFocus()
|
||||
if (contentLoader.item) {
|
||||
if (requiresEnterprise && contentLoader.item.usernameInput) {
|
||||
contentLoader.item.usernameInput.forceActiveFocus()
|
||||
} else if (contentLoader.item.passwordInput) {
|
||||
contentLoader.item.passwordInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
shouldBeVisible: false
|
||||
width: 420
|
||||
height: 230
|
||||
height: requiresEnterprise ? 310 : 230
|
||||
onShouldBeVisibleChanged: () => {
|
||||
if (!shouldBeVisible)
|
||||
wifiPasswordInput = ""
|
||||
if (!shouldBeVisible) {
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
}
|
||||
}
|
||||
onOpened: {
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.passwordInput)
|
||||
contentLoader.item.passwordInput.forceActiveFocus()
|
||||
if (contentLoader.item) {
|
||||
if (requiresEnterprise && contentLoader.item.usernameInput) {
|
||||
contentLoader.item.usernameInput.forceActiveFocus()
|
||||
} else if (contentLoader.item.passwordInput) {
|
||||
contentLoader.item.passwordInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
onBackgroundClicked: () => {
|
||||
close()
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -55,6 +75,7 @@ DankModal {
|
||||
FocusScope {
|
||||
id: wifiContent
|
||||
|
||||
property alias usernameInput: usernameInput
|
||||
property alias passwordInput: passwordInput
|
||||
|
||||
anchors.fill: parent
|
||||
@@ -62,6 +83,7 @@ DankModal {
|
||||
Keys.onEscapePressed: event => {
|
||||
close()
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
@@ -78,14 +100,14 @@ DankModal {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Connect to Wi-Fi")
|
||||
text: I18n.tr("Connect to Wi-Fi")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `Enter password for "${wifiPasswordSSID}"`
|
||||
text: requiresEnterprise ? `Enter credentials for "${wifiPasswordSSID}"` : `Enter password for "${wifiPasswordSSID}"`
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceTextMedium
|
||||
width: parent.width
|
||||
@@ -100,10 +122,48 @@ DankModal {
|
||||
onClicked: () => {
|
||||
close()
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceHover
|
||||
border.color: usernameInput.activeFocus ? Theme.primary : Theme.outlineStrong
|
||||
border.width: usernameInput.activeFocus ? 2 : 1
|
||||
visible: requiresEnterprise
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: () => {
|
||||
usernameInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: usernameInput
|
||||
|
||||
anchors.fill: parent
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
textColor: Theme.surfaceText
|
||||
text: wifiUsernameInput
|
||||
placeholderText: "Username"
|
||||
backgroundColor: "transparent"
|
||||
enabled: root.shouldBeVisible
|
||||
onTextEdited: () => {
|
||||
wifiUsernameInput = text
|
||||
}
|
||||
onAccepted: () => {
|
||||
if (passwordInput) {
|
||||
passwordInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
@@ -127,21 +187,24 @@ DankModal {
|
||||
textColor: Theme.surfaceText
|
||||
text: wifiPasswordInput
|
||||
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
|
||||
placeholderText: ""
|
||||
placeholderText: requiresEnterprise ? "Password" : ""
|
||||
backgroundColor: "transparent"
|
||||
focus: true
|
||||
focus: !requiresEnterprise
|
||||
enabled: root.shouldBeVisible
|
||||
onTextEdited: () => {
|
||||
wifiPasswordInput = text
|
||||
}
|
||||
onAccepted: () => {
|
||||
NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text)
|
||||
const username = requiresEnterprise ? usernameInput.text : ""
|
||||
NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text, username)
|
||||
close()
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
passwordInput.text = ""
|
||||
if (requiresEnterprise) usernameInput.text = ""
|
||||
}
|
||||
Component.onCompleted: () => {
|
||||
if (root.shouldBeVisible)
|
||||
if (root.shouldBeVisible && !requiresEnterprise)
|
||||
focusDelayTimer.start()
|
||||
}
|
||||
|
||||
@@ -151,8 +214,13 @@ DankModal {
|
||||
interval: 100
|
||||
repeat: false
|
||||
onTriggered: () => {
|
||||
if (root.shouldBeVisible)
|
||||
passwordInput.forceActiveFocus()
|
||||
if (root.shouldBeVisible) {
|
||||
if (requiresEnterprise && usernameInput) {
|
||||
usernameInput.forceActiveFocus()
|
||||
} else {
|
||||
passwordInput.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +269,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Show password")
|
||||
text: I18n.tr("Show password")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -229,7 +297,7 @@ DankModal {
|
||||
id: cancelText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Cancel")
|
||||
text: I18n.tr("Cancel")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -244,6 +312,7 @@ DankModal {
|
||||
onClicked: () => {
|
||||
close()
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -253,14 +322,14 @@ DankModal {
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||
enabled: passwordInput.text.length > 0
|
||||
enabled: requiresEnterprise ? (usernameInput.text.length > 0 && passwordInput.text.length > 0) : passwordInput.text.length > 0
|
||||
opacity: enabled ? 1 : 0.5
|
||||
|
||||
StyledText {
|
||||
id: connectText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Connect")
|
||||
text: I18n.tr("Connect")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
font.weight: Font.Medium
|
||||
@@ -274,10 +343,13 @@ DankModal {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: parent.enabled
|
||||
onClicked: () => {
|
||||
NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text)
|
||||
const username = requiresEnterprise ? usernameInput.text : ""
|
||||
NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text, username)
|
||||
close()
|
||||
wifiPasswordInput = ""
|
||||
wifiUsernameInput = ""
|
||||
passwordInput.text = ""
|
||||
if (requiresEnterprise) usernameInput.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ DankPopout {
|
||||
if (shouldBeVisible) {
|
||||
appLauncher.searchQuery = ""
|
||||
appLauncher.selectedIndex = 0
|
||||
appLauncher.setCategory("All")
|
||||
appLauncher.setCategory(I18n.tr("All"))
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.searchField) {
|
||||
contentLoader.item.searchField.text = ""
|
||||
@@ -112,6 +112,8 @@ DankPopout {
|
||||
mappings[Qt.Key_Up] = () => appLauncher.selectPrevious()
|
||||
mappings[Qt.Key_Return] = () => appLauncher.launchSelected()
|
||||
mappings[Qt.Key_Enter] = () => appLauncher.launchSelected()
|
||||
mappings[Qt.Key_Tab] = () => appLauncher.viewMode === "grid" ? appLauncher.selectNextInRow() : appLauncher.selectNext()
|
||||
mappings[Qt.Key_Backtab] = () => appLauncher.viewMode === "grid" ? appLauncher.selectPreviousInRow() : appLauncher.selectPrevious()
|
||||
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
mappings[Qt.Key_Right] = () => appLauncher.selectNextInRow()
|
||||
@@ -166,11 +168,6 @@ DankPopout {
|
||||
}
|
||||
}
|
||||
|
||||
if (!searchField.activeFocus && event.text && /[a-zA-Z0-9\s]/.test(event.text)) {
|
||||
searchField.forceActiveFocus()
|
||||
searchField.insertText(event.text)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -180,25 +177,23 @@ DankPopout {
|
||||
y: Theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 40
|
||||
leftPadding: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Applications")
|
||||
text: I18n.tr("Applications")
|
||||
font.pixelSize: Theme.fontSizeLarge + 4
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 200
|
||||
height: 1
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: appLauncher.model.count + " apps"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -223,7 +218,8 @@ DankPopout {
|
||||
showClearButton: true
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
enabled: appDrawerPopout.shouldBeVisible
|
||||
ignoreLeftRightKeys: true
|
||||
ignoreLeftRightKeys: appLauncher.viewMode !== "list"
|
||||
ignoreTabKeys: true
|
||||
keyForwardTargets: [keyHandler]
|
||||
onTextEdited: {
|
||||
appLauncher.searchQuery = text
|
||||
@@ -248,7 +244,7 @@ DankPopout {
|
||||
return
|
||||
}
|
||||
|
||||
const navigationKeys = [Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right]
|
||||
const navigationKeys = [Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right, Qt.Key_Tab, Qt.Key_Backtab]
|
||||
const isNavigationKey = navigationKeys.includes(event.key)
|
||||
const isEmptyEnter = isEnterKey && !hasText
|
||||
|
||||
@@ -684,7 +680,7 @@ DankPopout {
|
||||
contextMenu.close()
|
||||
}
|
||||
|
||||
width: 180
|
||||
width: Math.max(180, menuColumn.implicitWidth + Theme.spacingS * 2)
|
||||
height: menuColumn.implicitHeight + Theme.spacingS * 2
|
||||
padding: 0
|
||||
closePolicy: Popup.CloseOnPressOutside
|
||||
@@ -757,7 +753,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: contextMenu.isPinned ? "Unpin from Dock" : "Pin to Dock"
|
||||
text: contextMenu.isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -804,12 +800,13 @@ DankPopout {
|
||||
model: contextMenu.currentApp && contextMenu.currentApp.desktopEntry && contextMenu.currentApp.desktopEntry.actions ? contextMenu.currentApp.desktopEntry.actions : []
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
width: Math.max(parent.width, actionRow.implicitWidth + Theme.spacingS * 2)
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: actionMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
id: actionRow
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -891,7 +888,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch")
|
||||
text: I18n.tr("Launch")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -951,7 +948,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch on dGPU")
|
||||
text: I18n.tr("Launch on dGPU")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
|
||||
@@ -9,7 +9,7 @@ Item {
|
||||
id: root
|
||||
|
||||
property string searchQuery: ""
|
||||
property string selectedCategory: "All"
|
||||
property string selectedCategory: I18n.tr("All")
|
||||
property string viewMode: "list" // "list" or "grid"
|
||||
property int selectedIndex: 0
|
||||
property int maxResults: 50
|
||||
@@ -20,8 +20,8 @@ Item {
|
||||
property bool suppressUpdatesWhileLaunching: false
|
||||
readonly property var categories: {
|
||||
const allCategories = AppSearchService.getAllCategories().filter(cat => cat !== "Education" && cat !== "Science")
|
||||
const result = ["All"]
|
||||
return result.concat(allCategories.filter(cat => cat !== "All"))
|
||||
const result = [I18n.tr("All")]
|
||||
return result.concat(allCategories.filter(cat => cat !== I18n.tr("All")))
|
||||
}
|
||||
readonly property var categoryIcons: categories.map(category => AppSearchService.getCategoryIcon(category))
|
||||
property var appUsageRanking: AppUsageHistoryData.appUsageRanking || {}
|
||||
@@ -42,10 +42,11 @@ Item {
|
||||
keyboardNavigationActive = false
|
||||
|
||||
let apps = []
|
||||
const allCategory = I18n.tr("All")
|
||||
if (searchQuery.length === 0) {
|
||||
apps = selectedCategory === "All" ? AppSearchService.getAppsInCategory("All") : AppSearchService.getAppsInCategory(selectedCategory).slice(0, maxResults)
|
||||
apps = selectedCategory === allCategory ? AppSearchService.getAppsInCategory(allCategory) : AppSearchService.getAppsInCategory(selectedCategory).slice(0, maxResults)
|
||||
} else {
|
||||
if (selectedCategory === "All") {
|
||||
if (selectedCategory === allCategory) {
|
||||
apps = AppSearchService.searchApplications(searchQuery)
|
||||
} else {
|
||||
const categoryApps = AppSearchService.getAppsInCategory(selectedCategory)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var categories: []
|
||||
property string selectedCategory: "All"
|
||||
property string selectedCategory: I18n.tr("All")
|
||||
property bool compact: false
|
||||
|
||||
signal categorySelected(string category)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -8,6 +9,10 @@ import qs.Modules.Plugins
|
||||
PluginComponent {
|
||||
id: root
|
||||
|
||||
Ref {
|
||||
service: VpnService
|
||||
}
|
||||
|
||||
ccWidgetIcon: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
|
||||
ccWidgetPrimaryText: "VPN"
|
||||
ccWidgetSecondaryText: {
|
||||
@@ -82,7 +87,7 @@ PluginComponent {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Disconnect")
|
||||
text: I18n.tr("Disconnect")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -133,14 +138,14 @@ PluginComponent {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No VPN profiles found")
|
||||
text: I18n.tr("No VPN profiles found")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Add a VPN in NetworkManager")
|
||||
text: I18n.tr("Add a VPN in NetworkManager")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -48,7 +48,10 @@ Item {
|
||||
const builtinId = root.expandedSection
|
||||
let builtinInstance = null
|
||||
|
||||
if (builtinId === "builtin_vpn" && widgetModel?.vpnBuiltinInstance) {
|
||||
if (builtinId === "builtin_vpn") {
|
||||
if (widgetModel?.vpnLoader) {
|
||||
widgetModel.vpnLoader.active = true
|
||||
}
|
||||
builtinInstance = widgetModel.vpnBuiltinInstance
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,22 @@ Column {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: errorPillComponent
|
||||
ErrorPill {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
width: parent.width
|
||||
height: 60
|
||||
primaryMessage: {
|
||||
if (!DMSService.dmsAvailable) {
|
||||
return I18n.tr("DMS_SOCKET not available")
|
||||
}
|
||||
return I18n.tr("NM not supported")
|
||||
}
|
||||
secondaryMessage: I18n.tr("update dms for NM integration.")
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: compoundPillComponent
|
||||
CompoundPill {
|
||||
@@ -723,12 +739,16 @@ Column {
|
||||
width: parent.width
|
||||
height: 60
|
||||
|
||||
property var builtinInstance: {
|
||||
property var builtinInstance: null
|
||||
|
||||
Component.onCompleted: {
|
||||
const id = widgetData.id || ""
|
||||
if (id === "builtin_vpn") {
|
||||
return root.model?.vpnBuiltinInstance
|
||||
if (root.model?.vpnLoader) {
|
||||
root.model.vpnLoader.active = true
|
||||
}
|
||||
builtinInstance = Qt.binding(() => root.model?.vpnBuiltinInstance)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
sourceComponent: {
|
||||
|
||||
@@ -55,7 +55,7 @@ Row {
|
||||
}
|
||||
|
||||
Typography {
|
||||
text: qsTr("Add Widget")
|
||||
text: I18n.tr("Add Widget")
|
||||
style: Typography.Style.Subtitle
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -155,7 +155,7 @@ Row {
|
||||
}
|
||||
|
||||
Typography {
|
||||
text: qsTr("Add Widget")
|
||||
text: I18n.tr("Add Widget")
|
||||
style: Typography.Style.Button
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -189,7 +189,7 @@ Row {
|
||||
}
|
||||
|
||||
Typography {
|
||||
text: qsTr("Defaults")
|
||||
text: I18n.tr("Defaults")
|
||||
style: Typography.Style.Button
|
||||
color: Theme.warning
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -223,7 +223,7 @@ Row {
|
||||
}
|
||||
|
||||
Typography {
|
||||
text: qsTr("Reset")
|
||||
text: I18n.tr("Reset")
|
||||
style: Typography.Style.Button
|
||||
color: Theme.error
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -73,13 +73,17 @@ DankPopout {
|
||||
onShouldBeVisibleChanged: {
|
||||
if (shouldBeVisible) {
|
||||
Qt.callLater(() => {
|
||||
NetworkService.autoRefreshEnabled = NetworkService.wifiEnabled
|
||||
if (NetworkService.activeService) {
|
||||
NetworkService.activeService.autoRefreshEnabled = NetworkService.wifiEnabled
|
||||
}
|
||||
if (UserInfoService)
|
||||
UserInfoService.getUptime()
|
||||
})
|
||||
} else {
|
||||
Qt.callLater(() => {
|
||||
NetworkService.autoRefreshEnabled = false
|
||||
if (NetworkService.activeService) {
|
||||
NetworkService.activeService.autoRefreshEnabled = false
|
||||
}
|
||||
if (BluetoothService.adapter && BluetoothService.adapter.discovering)
|
||||
BluetoothService.adapter.discovering = false
|
||||
editMode = false
|
||||
|
||||
@@ -30,7 +30,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: qsTr("Input Devices")
|
||||
text: I18n.tr("Input Devices")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -30,7 +30,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: qsTr("Audio Devices")
|
||||
text: I18n.tr("Audio Devices")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -133,7 +133,7 @@ Rectangle {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Health")
|
||||
text: I18n.tr("Health")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -168,7 +168,7 @@ Rectangle {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Capacity")
|
||||
text: I18n.tr("Capacity")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -237,7 +237,7 @@ Rectangle {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Power Profile Degradation")
|
||||
text: I18n.tr("Power Profile Degradation")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.error
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -170,7 +170,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Audio Codec Selection")
|
||||
text: I18n.tr("Audio Codec Selection")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: qsTr("Bluetooth Settings")
|
||||
text: I18n.tr("Bluetooth Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -422,7 +422,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("No Bluetooth adapter found")
|
||||
text: I18n.tr("No Bluetooth adapter found")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -473,7 +473,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Audio Codec")
|
||||
text: I18n.tr("Audio Codec")
|
||||
height: bluetoothContextMenu.currentDevice && BluetoothService.isAudioDevice(bluetoothContextMenu.currentDevice) && bluetoothContextMenu.currentDevice.connected ? 32 : 0
|
||||
visible: bluetoothContextMenu.currentDevice && BluetoothService.isAudioDevice(bluetoothContextMenu.currentDevice) && bluetoothContextMenu.currentDevice.connected
|
||||
|
||||
@@ -498,7 +498,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Forget Device")
|
||||
text: I18n.tr("Forget Device")
|
||||
height: 32
|
||||
|
||||
contentItem: StyledText {
|
||||
|
||||
@@ -20,12 +20,9 @@ Rectangle {
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
NetworkService.addRef()
|
||||
if (NetworkService.wifiEnabled) {
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
@@ -44,7 +41,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: qsTr("Network Settings")
|
||||
text: I18n.tr("Network Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -59,15 +56,30 @@ Rectangle {
|
||||
DankButtonGroup {
|
||||
id: preferenceControls
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.ethernetConnected && NetworkService.wifiConnected
|
||||
visible: NetworkService.ethernetConnected
|
||||
|
||||
property int currentPreferenceIndex: NetworkService.userPreference === "ethernet" ? 0 : 1
|
||||
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
|
||||
}
|
||||
|
||||
model: ["Ethernet", "WiFi"]
|
||||
currentIndex: currentPreferenceIndex
|
||||
selectionMode: "single"
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected) return
|
||||
console.log("NetworkDetail: Setting preference to", index === 0 ? "ethernet" : "wifi")
|
||||
NetworkService.setNetworkPreference(index === 0 ? "ethernet" : "wifi")
|
||||
}
|
||||
}
|
||||
@@ -82,17 +94,17 @@ Rectangle {
|
||||
anchors.topMargin: Theme.spacingM
|
||||
visible: NetworkService.wifiToggling
|
||||
height: visible ? 80 : 0
|
||||
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingM
|
||||
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
name: "sync"
|
||||
size: 32
|
||||
color: Theme.primary
|
||||
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: NetworkService.wifiToggling
|
||||
loops: Animation.Infinite
|
||||
@@ -101,7 +113,7 @@ Rectangle {
|
||||
duration: 1000
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi..."
|
||||
@@ -136,7 +148,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: qsTr("WiFi is off")
|
||||
text: I18n.tr("WiFi is off")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -154,7 +166,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Enable WiFi")
|
||||
text: I18n.tr("Enable WiFi")
|
||||
color: Theme.primary
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
@@ -192,16 +204,16 @@ Rectangle {
|
||||
Item {
|
||||
width: parent.width
|
||||
height: 200
|
||||
visible: NetworkService.wifiInterface && NetworkService.wifiNetworks?.length < 1 && !NetworkService.wifiToggling
|
||||
|
||||
visible: NetworkService.wifiInterface && NetworkService.wifiNetworks?.length < 1 && !NetworkService.wifiToggling && NetworkService.isScanning
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "refresh"
|
||||
size: 48
|
||||
color: Qt.rgba(Theme.surfaceText.r || 0.8, Theme.surfaceText.g || 0.8, Theme.surfaceText.b || 0.8, 0.3)
|
||||
|
||||
|
||||
RotationAnimation on rotation {
|
||||
running: true
|
||||
running: NetworkService.isScanning
|
||||
loops: Animation.Infinite
|
||||
from: 0
|
||||
to: 360
|
||||
@@ -211,14 +223,18 @@ Rectangle {
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
let networks = [...NetworkService.wifiNetworks]
|
||||
networks.sort((a, b) => {
|
||||
if (a.ssid === NetworkService.currentWifiSSID) return -1
|
||||
if (b.ssid === NetworkService.currentWifiSSID) return 1
|
||||
model: sortedNetworks
|
||||
|
||||
property var sortedNetworks: {
|
||||
const ssid = NetworkService.currentWifiSSID
|
||||
const networks = NetworkService.wifiNetworks
|
||||
let sorted = [...networks]
|
||||
sorted.sort((a, b) => {
|
||||
if (a.ssid === ssid) return -1
|
||||
if (b.ssid === ssid) return 1
|
||||
return b.signal - a.signal
|
||||
})
|
||||
return networks
|
||||
return sorted
|
||||
}
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
@@ -261,10 +277,10 @@ Rectangle {
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
|
||||
StyledText {
|
||||
text: modelData.ssid === NetworkService.currentWifiSSID ? "Connected" : (modelData.secured ? "Secured" : "Open")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
@@ -380,7 +396,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Network Info")
|
||||
text: I18n.tr("Network Info")
|
||||
height: 32
|
||||
|
||||
contentItem: StyledText {
|
||||
@@ -403,7 +419,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Forget Network")
|
||||
text: I18n.tr("Forget Network")
|
||||
height: networkContextMenu.currentSaved || networkContextMenu.currentConnected ? 32 : 0
|
||||
visible: networkContextMenu.currentSaved || networkContextMenu.currentConnected
|
||||
|
||||
|
||||
@@ -7,7 +7,30 @@ import "../utils/widgets.js" as WidgetUtils
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
property var vpnBuiltinInstance: VpnWidget {}
|
||||
property var vpnBuiltinInstance: null
|
||||
|
||||
property var vpnLoader: Loader {
|
||||
active: false
|
||||
sourceComponent: Component {
|
||||
VpnWidget {}
|
||||
}
|
||||
|
||||
onItemChanged: {
|
||||
root.vpnBuiltinInstance = item
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onControlCenterWidgetsChanged() {
|
||||
const widgets = SettingsData.controlCenterWidgets || []
|
||||
const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn")
|
||||
if (!hasVpnWidget && vpnLoader.active) {
|
||||
console.log("VpnWidget: No VPN widget in control center, deactivating loader")
|
||||
vpnLoader.active = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var coreWidgetDefinitions: [{
|
||||
"id": "nightMode",
|
||||
|
||||
@@ -10,6 +10,12 @@ import qs.Widgets
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
readonly property string powerOptionsText: I18n.tr("Power Options")
|
||||
readonly property string logOutText: I18n.tr("Log Out")
|
||||
readonly property string suspendText: I18n.tr("Suspend")
|
||||
readonly property string rebootText: I18n.tr("Reboot")
|
||||
readonly property string powerOffText: I18n.tr("Power Off")
|
||||
|
||||
property bool powerMenuVisible: false
|
||||
signal powerActionRequested(string action, string title, string message)
|
||||
|
||||
@@ -65,7 +71,7 @@ PanelWindow {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Power Options")
|
||||
text: root.powerOptionsText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -118,7 +124,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Log Out")
|
||||
text: root.logOutText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -168,7 +174,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Suspend")
|
||||
text: root.suspendText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -218,7 +224,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Reboot")
|
||||
text: root.rebootText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -268,7 +274,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Power Off")
|
||||
text: root.powerOffText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
51
Modules/ControlCenter/Widgets/ErrorPill.qml
Normal file
51
Modules/ControlCenter/Widgets/ErrorPill.qml
Normal file
@@ -0,0 +1,51 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
StyledRect {
|
||||
id: root
|
||||
|
||||
property string primaryMessage: ""
|
||||
property string secondaryMessage: ""
|
||||
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.1)
|
||||
border.color: Theme.warning
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: "warning"
|
||||
size: 16
|
||||
color: Theme.warning
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 2
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - 16 - parent.spacing
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: root.primaryMessage
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning
|
||||
font.weight: Font.Medium
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: root.secondaryMessage
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning
|
||||
visible: text.length > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
|
||||
CompoundPill {
|
||||
id: root
|
||||
|
||||
isActive: {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return false
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return true
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi") {
|
||||
return true
|
||||
}
|
||||
return NetworkService.wifiEnabled
|
||||
}
|
||||
|
||||
iconName: {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return "sync"
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return "settings_ethernet"
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi") {
|
||||
return NetworkService.wifiSignalIcon
|
||||
}
|
||||
if (NetworkService.wifiEnabled) {
|
||||
return "wifi_off"
|
||||
}
|
||||
return "wifi_off"
|
||||
}
|
||||
|
||||
primaryText: {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi..."
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return "Ethernet"
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi" && NetworkService.currentWifiSSID) {
|
||||
return NetworkService.currentWifiSSID
|
||||
}
|
||||
if (NetworkService.wifiEnabled) {
|
||||
return "Not connected"
|
||||
}
|
||||
return "WiFi off"
|
||||
}
|
||||
|
||||
secondaryText: {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return "Please wait..."
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return "Connected"
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi") {
|
||||
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected"
|
||||
}
|
||||
if (NetworkService.wifiEnabled) {
|
||||
return "Select network"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
onToggled: {
|
||||
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
|
||||
NetworkService.toggleWifiRadio()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ Item {
|
||||
|
||||
readonly property real correctWidth: root.width
|
||||
readonly property real correctHeight: root.height
|
||||
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
|
||||
canvasSize: Qt.size(Math.ceil(correctWidth), Math.ceil(correctHeight))
|
||||
|
||||
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
|
||||
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
|
||||
@@ -40,7 +40,6 @@ Item {
|
||||
Connections {
|
||||
target: barWindow
|
||||
function on_BgColorChanged() { barShape.requestPaint() }
|
||||
function on_DprChanged() { barShape.requestPaint() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -50,19 +49,16 @@ Item {
|
||||
|
||||
onPaint: {
|
||||
const ctx = getContext("2d")
|
||||
const scale = barWindow._dpr
|
||||
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
|
||||
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
|
||||
const R = barWindow.px(wing)
|
||||
const RT = barWindow.px(rt)
|
||||
const W = barWindow.isVertical ? correctHeight : correctWidth
|
||||
const H_raw = barWindow.isVertical ? correctWidth : correctHeight
|
||||
const R = wing
|
||||
const RT = rt
|
||||
const H = H_raw - (R > 0 ? R : 0)
|
||||
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
|
||||
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
|
||||
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
|
||||
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
|
||||
|
||||
ctx.scale(scale, scale)
|
||||
|
||||
function drawTopPath() {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(RT, 0)
|
||||
@@ -89,7 +85,7 @@ Item {
|
||||
}
|
||||
|
||||
ctx.reset()
|
||||
ctx.clearRect(0, 0, W, H_raw)
|
||||
ctx.clearRect(0, 0, Math.ceil(W), Math.ceil(H_raw))
|
||||
|
||||
ctx.save()
|
||||
if (isBottom) {
|
||||
@@ -120,7 +116,7 @@ Item {
|
||||
|
||||
readonly property real correctWidth: root.width
|
||||
readonly property real correctHeight: root.height
|
||||
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
|
||||
canvasSize: Qt.size(Math.ceil(correctWidth), Math.ceil(correctHeight))
|
||||
|
||||
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
|
||||
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
|
||||
@@ -137,7 +133,6 @@ Item {
|
||||
Connections {
|
||||
target: barWindow
|
||||
function on_BgColorChanged() { barTint.requestPaint() }
|
||||
function on_DprChanged() { barTint.requestPaint() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -147,19 +142,16 @@ Item {
|
||||
|
||||
onPaint: {
|
||||
const ctx = getContext("2d")
|
||||
const scale = barWindow._dpr
|
||||
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
|
||||
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
|
||||
const R = barWindow.px(wing)
|
||||
const RT = barWindow.px(rt)
|
||||
const W = barWindow.isVertical ? correctHeight : correctWidth
|
||||
const H_raw = barWindow.isVertical ? correctWidth : correctHeight
|
||||
const R = wing
|
||||
const RT = rt
|
||||
const H = H_raw - (R > 0 ? R : 0)
|
||||
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
|
||||
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
|
||||
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
|
||||
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
|
||||
|
||||
ctx.scale(scale, scale)
|
||||
|
||||
function drawTopPath() {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(RT, 0)
|
||||
@@ -186,7 +178,7 @@ Item {
|
||||
}
|
||||
|
||||
ctx.reset()
|
||||
ctx.clearRect(0, 0, W, H_raw)
|
||||
ctx.clearRect(0, 0, Math.ceil(W), Math.ceil(H_raw))
|
||||
|
||||
ctx.save()
|
||||
if (isBottom) {
|
||||
@@ -211,14 +203,14 @@ Item {
|
||||
Canvas {
|
||||
id: barBorder
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
antialiasing: false
|
||||
visible: SettingsData.dankBarBorderEnabled
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
|
||||
readonly property real correctWidth: root.width
|
||||
readonly property real correctHeight: root.height
|
||||
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
|
||||
canvasSize: Qt.size(Math.ceil(correctWidth), Math.ceil(correctHeight))
|
||||
|
||||
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
|
||||
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
|
||||
@@ -232,32 +224,28 @@ Item {
|
||||
onVisibleChanged: if (visible) requestPaint()
|
||||
Component.onCompleted: requestPaint()
|
||||
|
||||
Connections {
|
||||
target: barWindow
|
||||
function on_DprChanged() { barBorder.requestPaint() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Theme
|
||||
function onSecondaryChanged() { barBorder.requestPaint() }
|
||||
function onIsLightModeChanged() { barBorder.requestPaint() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onDankBarBorderColorChanged() { barBorder.requestPaint() }
|
||||
function onDankBarBorderOpacityChanged() { barBorder.requestPaint() }
|
||||
function onDankBarBorderThicknessChanged() { barBorder.requestPaint() }
|
||||
function onDankBarSpacingChanged() { barBorder.requestPaint() }
|
||||
function onDankBarSquareCornersChanged() { barBorder.requestPaint() }
|
||||
function onCornerRadiusChanged() { barBorder.requestPaint() }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
if (!borderEnabled) return
|
||||
|
||||
const ctx = getContext("2d")
|
||||
const scale = barWindow._dpr
|
||||
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
|
||||
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
|
||||
const R = barWindow.px(wing)
|
||||
const RT = barWindow.px(rt)
|
||||
const W = barWindow.isVertical ? correctHeight : correctWidth
|
||||
const H_raw = barWindow.isVertical ? correctWidth : correctHeight
|
||||
const R = wing
|
||||
const RT = rt
|
||||
const H = H_raw - (R > 0 ? R : 0)
|
||||
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
|
||||
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
|
||||
@@ -267,8 +255,6 @@ Item {
|
||||
const spacing = SettingsData.dankBarSpacing
|
||||
const hasEdgeGap = spacing > 0 || RT > 0
|
||||
|
||||
ctx.scale(scale, scale)
|
||||
|
||||
function drawTopBorder() {
|
||||
ctx.beginPath()
|
||||
|
||||
@@ -302,7 +288,7 @@ Item {
|
||||
}
|
||||
|
||||
ctx.reset()
|
||||
ctx.clearRect(0, 0, W, H_raw)
|
||||
ctx.clearRect(0, 0, Math.ceil(W), Math.ceil(H_raw))
|
||||
|
||||
ctx.save()
|
||||
if (isBottom) {
|
||||
@@ -319,9 +305,17 @@ Item {
|
||||
drawTopBorder()
|
||||
ctx.restore()
|
||||
|
||||
ctx.lineWidth = 1
|
||||
ctx.strokeStyle = Theme.secondary
|
||||
const key = SettingsData.dankBarBorderColor || "surfaceText"
|
||||
const base = (key === "surfaceText") ? Theme.surfaceText
|
||||
: (key === "primary") ? Theme.primary
|
||||
: Theme.secondary
|
||||
const color = Theme.withAlpha(base, SettingsData.dankBarBorderOpacity ?? 1.0)
|
||||
const thickness = Math.max(1, SettingsData.dankBarBorderThickness ?? 1)
|
||||
|
||||
ctx.globalCompositeOperation = "source-over"
|
||||
ctx.lineWidth = thickness
|
||||
ctx.strokeStyle = color
|
||||
ctx.stroke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Shapes
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Mpris
|
||||
import Quickshell.Services.Notifications
|
||||
@@ -61,8 +62,17 @@ Item {
|
||||
property real wingtipsRadius: Theme.cornerRadius
|
||||
readonly property real _wingR: Math.max(0, wingtipsRadius)
|
||||
readonly property color _bgColor: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency)
|
||||
readonly property real _dpr: (barWindow.screen && barWindow.screen.devicePixelRatio) ? barWindow.screen.devicePixelRatio : 1
|
||||
function px(v) { return Math.round(v * _dpr) / _dpr }
|
||||
readonly property real _dpr: {
|
||||
if (CompositorService.isNiri && barWindow.screen) {
|
||||
const niriScale = NiriService.displayScales[barWindow.screen.name]
|
||||
if (niriScale !== undefined) return niriScale
|
||||
}
|
||||
if (CompositorService.isHyprland && barWindow.screen) {
|
||||
const hyprlandMonitor = Hyprland.monitors.values.find(m => m.name === barWindow.screen.name)
|
||||
if (hyprlandMonitor?.scale !== undefined) return hyprlandMonitor.scale
|
||||
}
|
||||
return (barWindow.screen?.devicePixelRatio) || 1
|
||||
}
|
||||
|
||||
property string screenName: modelData.name
|
||||
readonly property int notificationCount: NotificationService.notifications.length
|
||||
@@ -70,8 +80,8 @@ Item {
|
||||
readonly property real widgetThickness: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
|
||||
screen: modelData
|
||||
implicitHeight: !isVertical ? px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0)) : 0
|
||||
implicitWidth: isVertical ? px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0)) : 0
|
||||
implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0
|
||||
implicitWidth: isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0
|
||||
color: "transparent"
|
||||
|
||||
property var nativeInhibitor: null
|
||||
@@ -96,8 +106,17 @@ Item {
|
||||
updateGpuTempConfig()
|
||||
Qt.callLater(() => Qt.callLater(forceWidgetRefresh))
|
||||
|
||||
if (SessionService.nativeInhibitorAvailable) {
|
||||
createNativeInhibitor()
|
||||
inhibitorInitTimer.start()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: inhibitorInitTimer
|
||||
interval: 300
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (SessionService.nativeInhibitorAvailable) {
|
||||
createNativeInhibitor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +244,7 @@ Item {
|
||||
Item {
|
||||
id: inputMask
|
||||
|
||||
readonly property int barThickness: px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing)
|
||||
readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr)
|
||||
|
||||
readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview
|
||||
readonly property bool effectiveVisible: SettingsData.dankBarVisible || inOverviewWithShow
|
||||
@@ -358,8 +377,8 @@ Item {
|
||||
id: topBarMouseArea
|
||||
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
|
||||
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0
|
||||
height: !barWindow.isVertical ? px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
|
||||
width: barWindow.isVertical ? px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
|
||||
height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined
|
||||
width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined
|
||||
anchors {
|
||||
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined)
|
||||
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined)
|
||||
@@ -378,8 +397,8 @@ Item {
|
||||
|
||||
transform: Translate {
|
||||
id: topBarSlide
|
||||
x: barWindow.isVertical ? px(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth)) : 0
|
||||
y: !barWindow.isVertical ? px(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight)) : 0
|
||||
x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0
|
||||
y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
@@ -399,10 +418,10 @@ Item {
|
||||
Item {
|
||||
id: barUnitInset
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: !barWindow.isVertical ? px(SettingsData.dankBarSpacing) : (axis.edge === "left" ? px(SettingsData.dankBarSpacing) : 0)
|
||||
anchors.rightMargin: !barWindow.isVertical ? px(SettingsData.dankBarSpacing) : (axis.edge === "right" ? px(SettingsData.dankBarSpacing) : 0)
|
||||
anchors.topMargin: barWindow.isVertical ? px(SettingsData.dankBarSpacing) : (axis.outerVisualEdge() === "bottom" ? 0 : px(SettingsData.dankBarSpacing))
|
||||
anchors.bottomMargin: barWindow.isVertical ? px(SettingsData.dankBarSpacing) : (axis.outerVisualEdge() === "bottom" ? px(SettingsData.dankBarSpacing) : 0)
|
||||
anchors.leftMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "left" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
|
||||
anchors.rightMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "right" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
|
||||
anchors.topMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? 0 : Theme.px(SettingsData.dankBarSpacing, barWindow._dpr))
|
||||
anchors.bottomMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0)
|
||||
|
||||
BarCanvas {
|
||||
id: barBackground
|
||||
|
||||
@@ -311,7 +311,7 @@ DankPopout {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Health")
|
||||
text: I18n.tr("Health")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -346,7 +346,7 @@ DankPopout {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Capacity")
|
||||
text: I18n.tr("Capacity")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -415,7 +415,7 @@ DankPopout {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Power Profile Degradation")
|
||||
text: I18n.tr("Power Profile Degradation")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.error
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -13,6 +13,10 @@ import qs.Widgets
|
||||
DankPopout {
|
||||
id: root
|
||||
|
||||
Ref {
|
||||
service: VpnService
|
||||
}
|
||||
|
||||
property var triggerScreen: null
|
||||
|
||||
function setTriggerPosition(x, y, width, section, screen) {
|
||||
@@ -96,7 +100,7 @@ DankPopout {
|
||||
height: 32
|
||||
|
||||
StyledText {
|
||||
text: qsTr("VPN Connections")
|
||||
text: I18n.tr("VPN Connections")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -206,7 +210,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Disconnect")
|
||||
text: I18n.tr("Disconnect")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -262,14 +266,14 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No VPN profiles found")
|
||||
text: I18n.tr("No VPN profiles found")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Add a VPN in NetworkManager")
|
||||
text: I18n.tr("Add a VPN in NetworkManager")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -61,7 +61,7 @@ Rectangle {
|
||||
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: root.showNetworkIcon
|
||||
visible: root.showNetworkIcon && NetworkService.networkAvailable
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -160,7 +160,7 @@ Rectangle {
|
||||
return NetworkService.networkStatus !== "disconnected" ? Theme.primary : Theme.outlineButton;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: root.showNetworkIcon
|
||||
visible: root.showNetworkIcon && NetworkService.networkAvailable
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ Item {
|
||||
}
|
||||
layer.enabled: Theme.effectiveLogoColor !== ""
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.effectiveLogoColor
|
||||
brightness: SettingsData.launcherLogoBrightness
|
||||
@@ -108,6 +109,7 @@ Item {
|
||||
source: SettingsData.launcherLogoCustomPath ? "file://" + SettingsData.launcherLogoCustomPath.replace("file://", "") : ""
|
||||
layer.enabled: Theme.effectiveLogoColor !== ""
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.effectiveLogoColor
|
||||
brightness: SettingsData.launcherLogoBrightness
|
||||
|
||||
@@ -611,7 +611,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Close")
|
||||
text: I18n.tr("Close")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
|
||||
@@ -66,7 +66,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://")) {
|
||||
@@ -445,7 +448,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Back")
|
||||
text: I18n.tr("Back")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -7,6 +7,10 @@ import qs.Widgets
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
Ref {
|
||||
service: VpnService
|
||||
}
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property int widgetThickness: 28
|
||||
|
||||
@@ -131,15 +131,15 @@ DankPopout {
|
||||
|
||||
model: {
|
||||
let tabs = [
|
||||
{ icon: "dashboard", text: qsTr("Overview") },
|
||||
{ icon: "music_note", text: qsTr("Media") }
|
||||
{ icon: "dashboard", text: I18n.tr("Overview") },
|
||||
{ icon: "music_note", text: I18n.tr("Media") }
|
||||
]
|
||||
|
||||
if (SettingsData.weatherEnabled) {
|
||||
tabs.push({ icon: "wb_sunny", text: qsTr("Weather") })
|
||||
tabs.push({ icon: "wb_sunny", text: I18n.tr("Weather") })
|
||||
}
|
||||
|
||||
tabs.push({ icon: "settings", text: qsTr("Settings"), isAction: true })
|
||||
tabs.push({ icon: "settings", text: I18n.tr("Settings"), isAction: true })
|
||||
return tabs
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No Active Players")
|
||||
text: I18n.tr("No Active Players")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -406,7 +406,7 @@ Item {
|
||||
anchors.margins: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Audio Output Devices (") + audioDevicesDropdown.availableDevices.length + ")"
|
||||
text: I18n.tr("Audio Output Devices (") + audioDevicesDropdown.availableDevices.length + ")"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -491,7 +491,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color { ColorAnimation { duration: Anims.durShort } }
|
||||
Behavior on border.color { ColorAnimation { duration: Anims.durShort } }
|
||||
}
|
||||
}
|
||||
@@ -564,7 +563,7 @@ Item {
|
||||
anchors.margins: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Media Players (") + (allPlayers?.length || 0) + ")"
|
||||
text: I18n.tr("Media Players (") + (allPlayers?.length || 0) + ")"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -675,14 +674,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standard
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: Anims.durShort
|
||||
@@ -858,14 +849,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,14 +1007,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standard
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ Card {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No Media")
|
||||
text: I18n.tr("No Media")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -33,7 +33,7 @@ Card {
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Refresh")
|
||||
text: I18n.tr("Refresh")
|
||||
flat: true
|
||||
visible: !WeatherService.weather.loading
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -24,7 +24,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No Weather Data Available")
|
||||
text: I18n.tr("No Weather Data Available")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -257,7 +257,7 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Feels Like")
|
||||
text: I18n.tr("Feels Like")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -304,7 +304,7 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Humidity")
|
||||
text: I18n.tr("Humidity")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -351,7 +351,7 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Wind")
|
||||
text: I18n.tr("Wind")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -398,7 +398,7 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Pressure")
|
||||
text: I18n.tr("Pressure")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -445,7 +445,7 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Rain Chance")
|
||||
text: I18n.tr("Rain Chance")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -492,14 +492,14 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Visibility")
|
||||
text: I18n.tr("Visibility")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Good")
|
||||
text: I18n.tr("Good")
|
||||
font.pixelSize: Theme.fontSizeSmall + 1
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -522,7 +522,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("7-Day Forecast")
|
||||
text: I18n.tr("7-Day Forecast")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -60,14 +60,6 @@ Variants {
|
||||
|
||||
|
||||
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
||||
property bool windowIsFullscreen: {
|
||||
if (!ToplevelManager.activeToplevel) {
|
||||
return false
|
||||
}
|
||||
const activeWindow = ToplevelManager.activeToplevel
|
||||
const fullscreenApps = ["vlc", "mpv", "kodi", "steam", "lutris", "wine", "dosbox"]
|
||||
return fullscreenApps.some(app => activeWindow.appId && activeWindow.appId.toLowerCase().includes(app))
|
||||
}
|
||||
property bool revealSticky: false
|
||||
|
||||
Timer {
|
||||
@@ -81,7 +73,7 @@ Variants {
|
||||
if (CompositorService.isNiri && NiriService.inOverview && SettingsData.dockOpenOnOverview) {
|
||||
return true
|
||||
}
|
||||
return (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky) && !windowIsFullscreen
|
||||
return !autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky
|
||||
}
|
||||
|
||||
onContextMenuOpenChanged: {
|
||||
|
||||
@@ -322,7 +322,21 @@ Item {
|
||||
}
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
if (appData && appData.appId) {
|
||||
if (appData && appData.type === "window") {
|
||||
const sortedToplevels = CompositorService.sortedToplevels
|
||||
for (var i = 0; i < sortedToplevels.length; i++) {
|
||||
const toplevel = sortedToplevels[i]
|
||||
const checkId = toplevel.title + "|" + (toplevel.appId || "") + "|" + i
|
||||
if (checkId === appData.uniqueId) {
|
||||
toplevel.close()
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if (appData && appData.type === "grouped") {
|
||||
if (contextMenu) {
|
||||
contextMenu.showForButton(root, appData, 40, false, cachedDesktopEntry)
|
||||
}
|
||||
} else if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
@@ -333,7 +347,7 @@ Item {
|
||||
"comment": desktopEntry.comment || ""
|
||||
})
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry)
|
||||
SessionService.launchDesktopEntry(desktopEntry)
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (contextMenu && appData) {
|
||||
|
||||
@@ -232,7 +232,7 @@ PanelWindow {
|
||||
anchors.right: closeButton.left
|
||||
anchors.rightMargin: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: (modelData && modelData.title) ? modelData.title: qsTr("(Unnamed)")
|
||||
text: (modelData && modelData.title) ? modelData.title: I18n.tr("(Unnamed)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -376,7 +376,7 @@ PanelWindow {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: root.appData && root.appData.isPinned ? "Unpin from Dock" : "Pin to Dock"
|
||||
text: root.appData && root.appData.isPinned ? I18n.tr("Unpin from Dock") : I18n.tr("Pin to Dock")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -423,7 +423,7 @@ PanelWindow {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Launch on dGPU")
|
||||
text: I18n.tr("Launch on dGPU")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
|
||||
@@ -11,6 +11,7 @@ import Quickshell.Services.Mpris
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Lock
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -33,30 +34,10 @@ Item {
|
||||
|
||||
signal launchRequested
|
||||
|
||||
property bool powerDialogVisible: false
|
||||
property string powerDialogTitle: ""
|
||||
property string powerDialogMessage: ""
|
||||
property string powerDialogConfirmText: ""
|
||||
property color powerDialogConfirmColor: Theme.primary
|
||||
property var powerDialogOnConfirm: function () {}
|
||||
|
||||
function pickRandomFact() {
|
||||
randomFact = Facts.getRandomFact()
|
||||
}
|
||||
|
||||
function showPowerDialog(title, message, confirmText, confirmColor, onConfirm) {
|
||||
powerDialogTitle = title
|
||||
powerDialogMessage = message
|
||||
powerDialogConfirmText = confirmText
|
||||
powerDialogConfirmColor = confirmColor
|
||||
powerDialogOnConfirm = onConfirm
|
||||
powerDialogVisible = true
|
||||
}
|
||||
|
||||
function hidePowerDialog() {
|
||||
powerDialogVisible = false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
pickRandomFact()
|
||||
WeatherService.addRef()
|
||||
@@ -322,6 +303,8 @@ Item {
|
||||
TextInput {
|
||||
id: inputField
|
||||
|
||||
property bool syncingFromState: false
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: lockIcon.width + Theme.spacingM * 2
|
||||
anchors.rightMargin: {
|
||||
@@ -329,6 +312,9 @@ Item {
|
||||
if (GreeterState.showPasswordInput && revealButton.visible) {
|
||||
margin += revealButton.width
|
||||
}
|
||||
if (virtualKeyboardButton.visible) {
|
||||
margin += virtualKeyboardButton.width
|
||||
}
|
||||
if (enterButton.visible) {
|
||||
margin += enterButton.width + 2
|
||||
}
|
||||
@@ -338,6 +324,7 @@ Item {
|
||||
focus: true
|
||||
echoMode: GreeterState.showPasswordInput ? (parent.showPassword ? TextInput.Normal : TextInput.Password) : TextInput.Normal
|
||||
onTextChanged: {
|
||||
if (syncingFromState) return
|
||||
if (GreeterState.showPasswordInput) {
|
||||
GreeterState.passwordBuffer = text
|
||||
} else {
|
||||
@@ -355,28 +342,38 @@ Item {
|
||||
GreeterState.showPasswordInput = true
|
||||
PortalService.getGreeterUserProfileImage(GreeterState.username)
|
||||
GreeterState.passwordBuffer = ""
|
||||
inputField.text = ""
|
||||
syncingFromState = true
|
||||
text = ""
|
||||
syncingFromState = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
syncingFromState = true
|
||||
text = GreeterState.showPasswordInput ? GreeterState.passwordBuffer : GreeterState.usernameInput
|
||||
if (isPrimaryScreen)
|
||||
syncingFromState = false
|
||||
if (isPrimaryScreen && !powerMenu.isVisible)
|
||||
forceActiveFocus()
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if (visible && isPrimaryScreen)
|
||||
if (visible && isPrimaryScreen && !powerMenu.isVisible)
|
||||
forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardController {
|
||||
id: keyboard_controller
|
||||
target: inputField
|
||||
rootObject: root
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: placeholder
|
||||
|
||||
anchors.left: lockIcon.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (enterButton.visible ? enterButton.left : parent.right))
|
||||
anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))
|
||||
anchors.rightMargin: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: {
|
||||
@@ -413,7 +410,7 @@ Item {
|
||||
StyledText {
|
||||
anchors.left: lockIcon.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (enterButton.visible ? enterButton.left : parent.right))
|
||||
anchors.right: (GreeterState.showPasswordInput && revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)))
|
||||
anchors.rightMargin: 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: {
|
||||
@@ -441,8 +438,8 @@ Item {
|
||||
DankActionButton {
|
||||
id: revealButton
|
||||
|
||||
anchors.right: enterButton.visible ? enterButton.left : parent.right
|
||||
anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS
|
||||
anchors.right: virtualKeyboardButton.visible ? virtualKeyboardButton.left : (enterButton.visible ? enterButton.left : parent.right)
|
||||
anchors.rightMargin: 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: parent.showPassword ? "visibility_off" : "visibility"
|
||||
buttonSize: 32
|
||||
@@ -450,6 +447,24 @@ Item {
|
||||
enabled: visible
|
||||
onClicked: parent.showPassword = !parent.showPassword
|
||||
}
|
||||
DankActionButton {
|
||||
id: virtualKeyboardButton
|
||||
|
||||
anchors.right: enterButton.visible ? enterButton.left : parent.right
|
||||
anchors.rightMargin: enterButton.visible ? 0 : Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
iconName: "keyboard"
|
||||
buttonSize: 32
|
||||
visible: Greetd.state === GreetdState.Inactive && !GreeterState.unlocking
|
||||
enabled: visible
|
||||
onClicked: {
|
||||
if (keyboard_controller.isKeyboardActive) {
|
||||
keyboard_controller.hide()
|
||||
} else {
|
||||
keyboard_controller.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: enterButton
|
||||
@@ -549,7 +564,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Switch User")
|
||||
text: I18n.tr("Switch User")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -1038,33 +1053,15 @@ Item {
|
||||
visible: root.randomFact !== ""
|
||||
}
|
||||
|
||||
Row {
|
||||
DankActionButton {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Theme.spacingXL
|
||||
spacing: Theme.spacingL
|
||||
visible: GreetdSettings.lockScreenShowPowerActions
|
||||
|
||||
DankActionButton {
|
||||
iconName: "power_settings_new"
|
||||
iconColor: Theme.error
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
showPowerDialog("Power Off", "Power off this computer?", "Power Off", Theme.error, function () {
|
||||
SessionService.poweroff()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "refresh"
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
showPowerDialog("Restart", "Restart this computer?", "Restart", Theme.primary, function () {
|
||||
SessionService.reboot()
|
||||
})
|
||||
}
|
||||
}
|
||||
iconName: "power_settings_new"
|
||||
iconColor: Theme.error
|
||||
buttonSize: 40
|
||||
onClicked: powerMenu.show()
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -1256,7 +1253,7 @@ Item {
|
||||
if (sessionCmd) {
|
||||
GreetdMemory.setLastSessionId(GreeterState.sessionPaths[GreeterState.currentSessionIndex])
|
||||
GreetdMemory.setLastSuccessfulUser(GreeterState.username)
|
||||
Greetd.launch(sessionCmd.split(" "), ["XDG_SESSION_TYPE=wayland"], true)
|
||||
Greetd.launch(sessionCmd.split(" "), ["XDG_SESSION_TYPE=wayland"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1279,90 +1276,12 @@ Item {
|
||||
onTriggered: GreeterState.pamState = ""
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.8)
|
||||
visible: powerDialogVisible
|
||||
z: 1000
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 320
|
||||
height: 180
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
name: "power_settings_new"
|
||||
size: 32
|
||||
color: powerDialogConfirmColor
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: powerDialogMessage
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariant
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Cancel")
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: hidePowerDialog()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: powerDialogConfirmColor
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: powerDialogConfirmText
|
||||
color: Theme.primaryText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
hidePowerDialog()
|
||||
powerDialogOnConfirm()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LockPowerMenu {
|
||||
id: powerMenu
|
||||
showLogout: false
|
||||
onClosed: {
|
||||
if (isPrimaryScreen && inputField && inputField.forceActiveFocus) {
|
||||
Qt.callLater(() => inputField.forceActiveFocus())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,40 +12,89 @@ A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the
|
||||
|
||||
## Installation
|
||||
|
||||
### Arch Linux
|
||||
|
||||
Arch linux users can install [greetd-dms-greeter-git](https://aur.archlinux.org/packages/greetd-dms-greeter-git) from the AUR.
|
||||
|
||||
```bash
|
||||
paru -S greetd-dms-greeter-git
|
||||
# Or with yay
|
||||
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:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
### Automatic
|
||||
|
||||
The easiest thing is to run `dms greeter install` or `dms` for interactive installation.
|
||||
|
||||
### Manual
|
||||
|
||||
1. Install `greetd` (in most distro's standard repositories)
|
||||
2. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd`
|
||||
- niri if you want to run the greeter under niri, hypr if you want to run the greeter under Hyprland
|
||||
3. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/usr/local/bin/start-dms-greetd.sh`
|
||||
4. Edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` and replace `_DMS_PATH_` with the absolute path to dms, e.g. `/home/joecool/.config/quickshell/dms`
|
||||
5. Edit or create `/etc/greetd/config.toml`
|
||||
1. Install `greetd` (in most distro's standard repositories) and `quickshell`
|
||||
2. 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`:
|
||||
```bash
|
||||
sudo cp assets/dms-greeter /usr/local/bin/dms-greeter
|
||||
sudo chmod +x /usr/local/bin/dms-greeter
|
||||
```
|
||||
4. 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]
|
||||
# The VT to run the greeter on. Can be "next", "current" or a number
|
||||
# designating the VT.
|
||||
vt = 1
|
||||
|
||||
# The default session, also known as the greeter.
|
||||
[default_session]
|
||||
|
||||
# `agreety` is the bundled agetty/login-lookalike. You can replace `/bin/sh`
|
||||
# with whatever you want started, such as `sway`.
|
||||
|
||||
# The user to run the command as. The privileges this user must have depends
|
||||
# on the greeter. A graphical greeter may for example require the user to be
|
||||
# in the `video` group.
|
||||
user = "greeter"
|
||||
|
||||
command = "/usr/local/bin/start-dms-greetd.sh"
|
||||
# Change compositor to sway or hyprland if preferred
|
||||
command = "/usr/local/bin/dms-greeter --command niri"
|
||||
```
|
||||
|
||||
Enable the greeter with `sudo systemctl enable greetd`
|
||||
|
||||
#### Legacy installation (deprecated)
|
||||
|
||||
If you prefer the old method with separate shell scripts and config files:
|
||||
1. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd`
|
||||
2. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/usr/local/bin/start-dms-greetd.sh`
|
||||
3. Edit the config file and replace `_DMS_PATH_` with your DMS installation path
|
||||
4. Configure greetd to use `/usr/local/bin/start-dms-greetd.sh`
|
||||
|
||||
### NixOS
|
||||
|
||||
To install the greeter on NixOS add the repo to your flake inputs as described in the readme. Then somewhere in your NixOS config add this to imports:
|
||||
@@ -66,7 +115,30 @@ programs.dankMaterialShell.greeter = {
|
||||
|
||||
## Usage
|
||||
|
||||
To run dms in greeter mode you just need to set `DMS_RUN_GREETER=1` in the environment.
|
||||
### Using dms-greeter wrapper (recommended)
|
||||
|
||||
The `dms-greeter` wrapper simplifies running the greeter with any compositor:
|
||||
|
||||
```bash
|
||||
dms-greeter --command niri
|
||||
dms-greeter --command hyprland
|
||||
dms-greeter --command sway
|
||||
dms-greeter --command niri -C /path/to/custom-niri.kdl
|
||||
```
|
||||
|
||||
Configure greetd to use it in `/etc/greetd/config.toml`:
|
||||
```toml
|
||||
[terminal]
|
||||
vt = 1
|
||||
|
||||
[default_session]
|
||||
user = "greeter"
|
||||
command = "/usr/local/bin/dms-greeter --command niri"
|
||||
```
|
||||
|
||||
### Manual usage
|
||||
|
||||
To run dms in greeter mode you can also manually set environment variables:
|
||||
|
||||
```bash
|
||||
DMS_RUN_GREETER=1 qs -p /path/to/dms
|
||||
@@ -86,15 +158,17 @@ Wallpapers and themes and weather and clock formats and things are a TODO on the
|
||||
|
||||
You can synchronize those configurations with a specific user if you want greeter settings to always mirror the shell.
|
||||
|
||||
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.
|
||||
|
||||
```bash
|
||||
# For core settings (theme, clock formats, etc)
|
||||
sudo ln -sf ~/.config/DankMaterialShell/settings.json /etc/greetd/.dms/settings.json
|
||||
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 /etc/greetd/.dms/session.json
|
||||
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 /etc/greetd/.dms/dms-colors.json
|
||||
sudo ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /var/cache/dms-greeter/dms-colors.json
|
||||
```
|
||||
|
||||
You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable, the default is `/etc/greetd/.dms`
|
||||
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`.
|
||||
|
||||
It should be writable by the greeter user.
|
||||
The cache directory should be owned by `greeter:greeter` with `770` permissions.
|
||||
174
Modules/Greetd/assets/dms-greeter
Executable file
174
Modules/Greetd/assets/dms-greeter
Executable file
@@ -0,0 +1,174 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
COMPOSITOR=""
|
||||
COMPOSITOR_CONFIG=""
|
||||
DMS_PATH="dms-greeter"
|
||||
CACHE_DIR="/var/cache/dms-greeter"
|
||||
|
||||
show_help() {
|
||||
cat << EOF
|
||||
dms-greeter - DankMaterialShell greeter launcher
|
||||
|
||||
Usage: dms-greeter --command COMPOSITOR [OPTIONS]
|
||||
|
||||
Required:
|
||||
--command COMPOSITOR Compositor to use (niri, hyprland, or sway)
|
||||
|
||||
Options:
|
||||
-C, --config PATH Custom compositor config file
|
||||
-p, --path PATH DMS path (config name or absolute path)
|
||||
(default: dms-greeter)
|
||||
--cache-dir PATH Cache directory for greeter data
|
||||
(default: /var/cache/dms-greeter)
|
||||
-h, --help Show this help message
|
||||
|
||||
Examples:
|
||||
dms-greeter --command niri
|
||||
dms-greeter --command hyprland -C /etc/greetd/custom-hypr.conf
|
||||
dms-greeter --command sway -p /home/user/.config/quickshell/custom-dms
|
||||
dms-greeter --command niri --cache-dir /tmp/dmsgreeter
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--command)
|
||||
COMPOSITOR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-C|--config)
|
||||
COMPOSITOR_CONFIG="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p|--path)
|
||||
DMS_PATH="$2"
|
||||
shift 2
|
||||
;;
|
||||
--cache-dir)
|
||||
CACHE_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$COMPOSITOR" ]]; then
|
||||
echo "Error: --command COMPOSITOR is required" >&2
|
||||
show_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||
export EGL_PLATFORM=gbm
|
||||
export DMS_RUN_GREETER=1
|
||||
export DMS_GREET_CFG_DIR="$CACHE_DIR"
|
||||
|
||||
mkdir -p "$CACHE_DIR"
|
||||
|
||||
QS_CMD="qs"
|
||||
if [[ "$DMS_PATH" == /* ]]; then
|
||||
QS_CMD="qs -p $DMS_PATH"
|
||||
else
|
||||
QS_CMD="qs -c $DMS_PATH"
|
||||
fi
|
||||
|
||||
case "$COMPOSITOR" in
|
||||
niri)
|
||||
if [[ -z "$COMPOSITOR_CONFIG" ]]; then
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
cat > "$TEMP_CONFIG" << NIRI_EOF
|
||||
hotkey-overlay {
|
||||
skip-at-startup
|
||||
}
|
||||
|
||||
environment {
|
||||
DMS_RUN_GREETER "1"
|
||||
}
|
||||
|
||||
spawn-at-startup "sh" "-c" "$QS_CMD; niri msg action quit --skip-confirmation"
|
||||
|
||||
debug {
|
||||
keep-max-bpc-unchanged
|
||||
}
|
||||
|
||||
gestures {
|
||||
hot-corners {
|
||||
off
|
||||
}
|
||||
}
|
||||
|
||||
layout {
|
||||
background-color "#000000"
|
||||
}
|
||||
NIRI_EOF
|
||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||
else
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG"
|
||||
cat >> "$TEMP_CONFIG" << NIRI_EOF
|
||||
|
||||
spawn-at-startup "sh" "-c" "$QS_CMD; niri msg action quit --skip-confirmation"
|
||||
NIRI_EOF
|
||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||
fi
|
||||
exec niri -c "$COMPOSITOR_CONFIG"
|
||||
;;
|
||||
|
||||
hyprland)
|
||||
if [[ -z "$COMPOSITOR_CONFIG" ]]; then
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
cat > "$TEMP_CONFIG" << HYPRLAND_EOF
|
||||
env = DMS_RUN_GREETER,1
|
||||
|
||||
exec = sh -c "$QS_CMD; hyprctl dispatch exit"
|
||||
HYPRLAND_EOF
|
||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||
else
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG"
|
||||
cat >> "$TEMP_CONFIG" << HYPRLAND_EOF
|
||||
|
||||
exec = sh -c "$QS_CMD; hyprctl dispatch exit"
|
||||
HYPRLAND_EOF
|
||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||
fi
|
||||
exec Hyprland -c "$COMPOSITOR_CONFIG"
|
||||
;;
|
||||
|
||||
sway)
|
||||
if [[ -z "$COMPOSITOR_CONFIG" ]]; then
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
cat > "$TEMP_CONFIG" << SWAY_EOF
|
||||
exec "$QS_CMD; swaymsg exit"
|
||||
SWAY_EOF
|
||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||
else
|
||||
TEMP_CONFIG=$(mktemp)
|
||||
cat "$COMPOSITOR_CONFIG" > "$TEMP_CONFIG"
|
||||
cat >> "$TEMP_CONFIG" << SWAY_EOF
|
||||
|
||||
exec "$QS_CMD; swaymsg exit"
|
||||
SWAY_EOF
|
||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||
fi
|
||||
exec sway -c "$COMPOSITOR_CONFIG"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Error: Unsupported compositor: $COMPOSITOR" >&2
|
||||
echo "Supported compositors: niri, hyprland, sway" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -7,145 +7,55 @@ import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
property string sid: Quickshell.env("XDG_SESSION_ID") || "self"
|
||||
property string sessionPath: ""
|
||||
|
||||
function activate() {
|
||||
loader.activeAsync = true
|
||||
}
|
||||
property string sharedPasswordBuffer: ""
|
||||
property bool shouldLock: false
|
||||
|
||||
Component.onCompleted: {
|
||||
getSessionPath.running = true
|
||||
IdleService.lockComponent = root
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
lockStateMonitor.running = false
|
||||
function activate() {
|
||||
shouldLock = true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
|
||||
function onSessionLocked() {
|
||||
shouldLock = true
|
||||
}
|
||||
|
||||
function onSessionUnlocked() {
|
||||
shouldLock = false
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: IdleService
|
||||
|
||||
function onLockRequested() {
|
||||
console.log("Lock: Received lock request from IdleService")
|
||||
activate()
|
||||
shouldLock = true
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: getSessionPath
|
||||
command: ["gdbus", "call", "--system", "--dest", "org.freedesktop.login1", "--object-path", "/org/freedesktop/login1", "--method", "org.freedesktop.login1.Manager.GetSession", sid]
|
||||
running: false
|
||||
WlSessionLock {
|
||||
id: sessionLock
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const match = text.match(/objectpath '([^']+)'/)
|
||||
if (match) {
|
||||
root.sessionPath = match[1]
|
||||
console.log("Found session path:", root.sessionPath)
|
||||
checkCurrentLockState.running = true
|
||||
lockStateMonitor.running = true
|
||||
} else {
|
||||
console.warn("Could not determine session path")
|
||||
}
|
||||
}
|
||||
}
|
||||
locked: root.shouldLock
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("Failed to get session path, exit code:", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: checkCurrentLockState
|
||||
command: root.sessionPath ? ["gdbus", "call", "--system", "--dest", "org.freedesktop.login1", "--object-path", root.sessionPath, "--method", "org.freedesktop.DBus.Properties.Get", "org.freedesktop.login1.Session", "LockedHint"] : []
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.includes("true")) {
|
||||
console.log("Session is locked on startup, activating lock screen")
|
||||
loader.activeAsync = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("Failed to check initial lock state, exit code:", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: lockStateMonitor
|
||||
command: root.sessionPath ? ["gdbus", "monitor", "--system", "--dest", "org.freedesktop.login1"] : []
|
||||
running: false
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
|
||||
onRead: line => {
|
||||
if (line.includes(root.sessionPath)) {
|
||||
if (line.includes("org.freedesktop.login1.Session.Lock")) {
|
||||
console.log("login1: Lock signal received -> show lock")
|
||||
loader.activeAsync = true
|
||||
return
|
||||
}
|
||||
if (line.includes("org.freedesktop.login1.Session.Unlock")) {
|
||||
console.log("login1: Unlock signal received -> hide lock")
|
||||
loader.active = false
|
||||
return
|
||||
}
|
||||
if (line.includes("LockedHint") && line.includes("true")) {
|
||||
console.log("login1: LockedHint=true -> show lock")
|
||||
loader.activeAsync = true
|
||||
return
|
||||
}
|
||||
if (line.includes("LockedHint") && line.includes("false")) {
|
||||
console.log("login1: LockedHint=false -> hide lock")
|
||||
loader.active = false
|
||||
return
|
||||
}
|
||||
}
|
||||
if (line.includes("PrepareForSleep") &&
|
||||
line.includes("true") &&
|
||||
SessionData.lockBeforeSuspend) {
|
||||
loader.activeAsync = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("gdbus monitor failed, exit code:", exitCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: loader
|
||||
|
||||
WlSessionLock {
|
||||
id: sessionLock
|
||||
|
||||
property bool unlocked: false
|
||||
property string sharedPasswordBuffer: ""
|
||||
|
||||
locked: true
|
||||
|
||||
onLockedChanged: {
|
||||
if (!locked) {
|
||||
loader.active = false
|
||||
}
|
||||
}
|
||||
WlSessionLockSurface {
|
||||
color: "transparent"
|
||||
|
||||
LockSurface {
|
||||
id: lockSurface
|
||||
anchors.fill: parent
|
||||
lock: sessionLock
|
||||
sharedPasswordBuffer: sessionLock.sharedPasswordBuffer
|
||||
sharedPasswordBuffer: root.sharedPasswordBuffer
|
||||
onUnlockRequested: {
|
||||
root.shouldLock = false
|
||||
}
|
||||
onPasswordChanged: newPassword => {
|
||||
sessionLock.sharedPasswordBuffer = newPassword
|
||||
root.sharedPasswordBuffer = newPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,17 +69,15 @@ Item {
|
||||
target: "lock"
|
||||
|
||||
function lock() {
|
||||
console.log("Lock screen requested via IPC")
|
||||
loader.activeAsync = true
|
||||
shouldLock = true
|
||||
}
|
||||
|
||||
function demo() {
|
||||
console.log("Lock screen DEMO mode requested via IPC")
|
||||
demoWindow.showDemo()
|
||||
}
|
||||
|
||||
function isLocked(): bool {
|
||||
return loader.active
|
||||
return sessionLock.locked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
457
Modules/Lock/LockPowerMenu.qml
Normal file
457
Modules/Lock/LockPowerMenu.qml
Normal file
@@ -0,0 +1,457 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool isVisible: false
|
||||
property bool showLogout: true
|
||||
property int selectedIndex: 0
|
||||
property int optionCount: {
|
||||
let count = 0
|
||||
if (showLogout) count++
|
||||
count++
|
||||
if (SessionService.hibernateSupported) count++
|
||||
count += 2
|
||||
return count
|
||||
}
|
||||
|
||||
signal closed()
|
||||
|
||||
function show() {
|
||||
isVisible = true
|
||||
selectedIndex = 0
|
||||
Qt.callLater(() => {
|
||||
if (powerMenuFocusScope && powerMenuFocusScope.forceActiveFocus) {
|
||||
powerMenuFocusScope.forceActiveFocus()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function hide() {
|
||||
isVisible = false
|
||||
closed()
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.5)
|
||||
visible: isVisible
|
||||
z: 1000
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.hide()
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
id: powerMenuFocusScope
|
||||
anchors.fill: parent
|
||||
focus: root.isVisible
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
Qt.callLater(() => forceActiveFocus())
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
root.hide()
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Backtab:
|
||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Tab:
|
||||
selectedIndex = (selectedIndex + 1) % optionCount
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
const actions = []
|
||||
if (showLogout) actions.push("logout")
|
||||
actions.push("suspend")
|
||||
if (SessionService.hibernateSupported) actions.push("hibernate")
|
||||
actions.push("reboot", "poweroff")
|
||||
if (selectedIndex < actions.length) {
|
||||
const action = actions[selectedIndex]
|
||||
hide()
|
||||
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
|
||||
}
|
||||
}
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_N:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % optionCount
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_P:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % optionCount
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 320
|
||||
implicitHeight: mainColumn.implicitHeight + Theme.spacingL * 2
|
||||
height: implicitHeight
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outlineMedium
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Power Options")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 150
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: Theme.surfaceText
|
||||
onClicked: root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
visible: showLogout
|
||||
color: {
|
||||
if (selectedIndex === 0) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
} else if (logoutArea.containsMouse) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
} else {
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
}
|
||||
border.color: selectedIndex === 0 ? Theme.primary : "transparent"
|
||||
border.width: selectedIndex === 0 ? 1 : 0
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "logout"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Log Out")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: logoutArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.hide()
|
||||
SessionService.logout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
const suspendIdx = showLogout ? 1 : 0
|
||||
if (selectedIndex === suspendIdx) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
} else if (suspendArea.containsMouse) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
} else {
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
}
|
||||
border.color: selectedIndex === (showLogout ? 1 : 0) ? Theme.primary : "transparent"
|
||||
border.width: selectedIndex === (showLogout ? 1 : 0) ? 1 : 0
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "bedtime"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Suspend")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: suspendArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.hide()
|
||||
SessionService.suspend()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
const hibernateIdx = showLogout ? 2 : 1
|
||||
if (selectedIndex === hibernateIdx) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
} else if (hibernateArea.containsMouse) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
} else {
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
}
|
||||
border.color: selectedIndex === (showLogout ? 2 : 1) ? Theme.primary : "transparent"
|
||||
border.width: selectedIndex === (showLogout ? 2 : 1) ? 1 : 0
|
||||
visible: SessionService.hibernateSupported
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "ac_unit"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Hibernate")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: hibernateArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.hide()
|
||||
SessionService.hibernate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
let rebootIdx = showLogout ? 3 : 2
|
||||
if (!SessionService.hibernateSupported) rebootIdx--
|
||||
if (selectedIndex === rebootIdx) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
} else if (rebootArea.containsMouse) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
} else {
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
}
|
||||
border.color: {
|
||||
let rebootIdx = showLogout ? 3 : 2
|
||||
if (!SessionService.hibernateSupported) rebootIdx--
|
||||
return selectedIndex === rebootIdx ? Theme.primary : "transparent"
|
||||
}
|
||||
border.width: {
|
||||
let rebootIdx = showLogout ? 3 : 2
|
||||
if (!SessionService.hibernateSupported) rebootIdx--
|
||||
return selectedIndex === rebootIdx ? 1 : 0
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "restart_alt"
|
||||
size: Theme.iconSize
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Reboot")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: rebootArea.containsMouse ? Theme.warning : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: rebootArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.hide()
|
||||
SessionService.reboot()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
let powerOffIdx = showLogout ? 4 : 3
|
||||
if (!SessionService.hibernateSupported) powerOffIdx--
|
||||
if (selectedIndex === powerOffIdx) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
} else if (powerOffArea.containsMouse) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
} else {
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||
}
|
||||
}
|
||||
border.color: {
|
||||
let powerOffIdx = showLogout ? 4 : 3
|
||||
if (!SessionService.hibernateSupported) powerOffIdx--
|
||||
return selectedIndex === powerOffIdx ? Theme.primary : "transparent"
|
||||
}
|
||||
border.width: {
|
||||
let powerOffIdx = showLogout ? 4 : 3
|
||||
if (!SessionService.hibernateSupported) powerOffIdx--
|
||||
return selectedIndex === powerOffIdx ? 1 : 0
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "power_settings_new"
|
||||
size: Theme.iconSize
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Power Off")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: powerOffArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: powerOffArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.hide()
|
||||
SessionService.poweroff()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
height: Theme.spacingS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,27 +26,6 @@ Item {
|
||||
|
||||
signal unlockRequested
|
||||
|
||||
// Internal power dialog state
|
||||
property bool powerDialogVisible: false
|
||||
property string powerDialogTitle: ""
|
||||
property string powerDialogMessage: ""
|
||||
property string powerDialogConfirmText: ""
|
||||
property color powerDialogConfirmColor: Theme.primary
|
||||
property var powerDialogOnConfirm: function () {}
|
||||
|
||||
function showPowerDialog(title, message, confirmText, confirmColor, onConfirm) {
|
||||
powerDialogTitle = title
|
||||
powerDialogMessage = message
|
||||
powerDialogConfirmText = confirmText
|
||||
powerDialogConfirmColor = confirmColor
|
||||
powerDialogOnConfirm = onConfirm
|
||||
powerDialogVisible = true
|
||||
}
|
||||
|
||||
function hidePowerDialog() {
|
||||
powerDialogVisible = false
|
||||
}
|
||||
|
||||
function pickRandomFact() {
|
||||
randomFact = Facts.getRandomFact()
|
||||
}
|
||||
@@ -63,6 +42,16 @@ Item {
|
||||
updateHyprlandLayout()
|
||||
hyprlandLayoutUpdateTimer.start()
|
||||
}
|
||||
|
||||
if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) {
|
||||
DMSService.sendRequest("loginctl.lockerReady", null, response => {
|
||||
if (response.error) {
|
||||
console.warn("LockScreenContent: Failed to signal locker ready:", response.error)
|
||||
} else {
|
||||
console.log("LockScreenContent: Locker ready signaled, inhibitor released")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
onDemoModeChanged: {
|
||||
if (demoMode) {
|
||||
@@ -336,7 +325,7 @@ Item {
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (!activeFocus && !demoMode && visible && passwordField) {
|
||||
if (!activeFocus && !demoMode && visible && passwordField && !powerMenu.isVisible) {
|
||||
Qt.callLater(() => {
|
||||
if (passwordField && passwordField.forceActiveFocus) {
|
||||
passwordField.forceActiveFocus()
|
||||
@@ -346,7 +335,7 @@ Item {
|
||||
}
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled && !demoMode && visible && passwordField) {
|
||||
if (enabled && !demoMode && visible && passwordField && !powerMenu.isVisible) {
|
||||
Qt.callLater(() => {
|
||||
if (passwordField && passwordField.forceActiveFocus) {
|
||||
passwordField.forceActiveFocus()
|
||||
@@ -609,7 +598,7 @@ Item {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Theme.spacingXL
|
||||
text: qsTr("DEMO MODE - Click anywhere to exit")
|
||||
text: I18n.tr("DEMO MODE - Click anywhere to exit")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: "white"
|
||||
opacity: 0.7
|
||||
@@ -1070,53 +1059,19 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
DankActionButton {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.margins: Theme.spacingXL
|
||||
spacing: Theme.spacingL
|
||||
visible: SettingsData.lockScreenShowPowerActions
|
||||
|
||||
DankActionButton {
|
||||
iconName: "power_settings_new"
|
||||
iconColor: Theme.error
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
if (demoMode) {
|
||||
console.log("Demo: Power")
|
||||
} else {
|
||||
showPowerDialog("Power Off", "Power off this computer?", "Power Off", Theme.error, function () {
|
||||
SessionService.poweroff()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "refresh"
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
if (demoMode) {
|
||||
console.log("Demo: Reboot")
|
||||
} else {
|
||||
showPowerDialog("Restart", "Restart this computer?", "Restart", Theme.primary, function () {
|
||||
SessionService.reboot()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "logout"
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
if (demoMode) {
|
||||
console.log("Demo: Logout")
|
||||
} else {
|
||||
showPowerDialog("Log Out", "End this session?", "Log Out", Theme.primary, function () {
|
||||
SessionService.logout()
|
||||
})
|
||||
}
|
||||
iconName: "power_settings_new"
|
||||
iconColor: Theme.error
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
if (demoMode) {
|
||||
console.log("Demo: Power Menu")
|
||||
} else {
|
||||
powerMenu.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1197,91 +1152,12 @@ Item {
|
||||
onClicked: root.unlockRequested()
|
||||
}
|
||||
|
||||
// Internal power dialog
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(0, 0, 0, 0.8)
|
||||
visible: powerDialogVisible
|
||||
z: 1000
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: 320
|
||||
height: 180
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
name: "power_settings_new"
|
||||
size: 32
|
||||
color: powerDialogConfirmColor
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: powerDialogMessage
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariant
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Cancel")
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: hidePowerDialog()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: powerDialogConfirmColor
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: powerDialogConfirmText
|
||||
color: Theme.primaryText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
hidePowerDialog()
|
||||
powerDialogOnConfirm()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LockPowerMenu {
|
||||
id: powerMenu
|
||||
showLogout: true
|
||||
onClosed: {
|
||||
if (!demoMode && passwordField && passwordField.forceActiveFocus) {
|
||||
Qt.callLater(() => passwordField.forceActiveFocus())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,33 +4,26 @@ import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
|
||||
WlSessionLockSurface {
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
required property WlSessionLock lock
|
||||
required property string sharedPasswordBuffer
|
||||
|
||||
signal passwordChanged(string newPassword)
|
||||
|
||||
readonly property bool locked: lock && !lock.locked
|
||||
|
||||
function unlock(): void {
|
||||
lock.locked = false
|
||||
}
|
||||
signal unlockRequested()
|
||||
|
||||
color: "transparent"
|
||||
|
||||
Loader {
|
||||
LockScreenContent {
|
||||
anchors.fill: parent
|
||||
sourceComponent: LockScreenContent {
|
||||
demoMode: false
|
||||
passwordBuffer: root.sharedPasswordBuffer
|
||||
screenName: root.screen?.name ?? ""
|
||||
onUnlockRequested: root.unlock()
|
||||
onPasswordBufferChanged: {
|
||||
if (root.sharedPasswordBuffer !== passwordBuffer) {
|
||||
root.passwordChanged(passwordBuffer)
|
||||
}
|
||||
demoMode: false
|
||||
passwordBuffer: root.sharedPasswordBuffer
|
||||
screenName: ""
|
||||
onUnlockRequested: root.unlockRequested()
|
||||
onPasswordBufferChanged: {
|
||||
if (root.sharedPasswordBuffer !== passwordBuffer) {
|
||||
root.passwordChanged(passwordBuffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +254,7 @@ Item {
|
||||
FileBrowserModal {
|
||||
id: saveBrowser
|
||||
|
||||
browserTitle: qsTr("Save Notepad File")
|
||||
browserTitle: I18n.tr("Save Notepad File")
|
||||
browserIcon: "save"
|
||||
browserType: "notepad_save"
|
||||
fileExtensions: ["*.txt", "*.md", "*.*"]
|
||||
@@ -318,7 +318,7 @@ Item {
|
||||
FileBrowserModal {
|
||||
id: loadBrowser
|
||||
|
||||
browserTitle: qsTr("Open Notepad File")
|
||||
browserTitle: I18n.tr("Open Notepad File")
|
||||
browserIcon: "folder_open"
|
||||
browserType: "notepad_load"
|
||||
fileExtensions: ["*.txt", "*.md", "*.*"]
|
||||
@@ -381,7 +381,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Unsaved Changes")
|
||||
text: I18n.tr("Unsaved Changes")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -389,12 +389,12 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: root.pendingAction === "new" ?
|
||||
qsTr("You have unsaved changes. Save before creating a new file?") :
|
||||
I18n.tr("You have unsaved changes. Save before creating a new file?") :
|
||||
root.pendingAction.startsWith("close_tab_") ?
|
||||
qsTr("You have unsaved changes. Save before closing this tab?") :
|
||||
I18n.tr("You have unsaved changes. Save before closing this tab?") :
|
||||
root.pendingAction === "load_file" || root.pendingAction === "open" ?
|
||||
qsTr("You have unsaved changes. Save before opening a file?") :
|
||||
qsTr("You have unsaved changes. Save before continuing?")
|
||||
I18n.tr("You have unsaved changes. Save before opening a file?") :
|
||||
I18n.tr("You have unsaved changes. Save before continuing?")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceTextMedium
|
||||
width: parent.width
|
||||
@@ -433,7 +433,7 @@ Item {
|
||||
StyledText {
|
||||
id: discardText
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Don't Save")
|
||||
text: I18n.tr("Don't Save")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -473,7 +473,7 @@ Item {
|
||||
StyledText {
|
||||
id: saveAsText
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Save")
|
||||
text: I18n.tr("Save")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -119,7 +119,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Notepad Font Settings")
|
||||
text: I18n.tr("Notepad Font Settings")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -136,7 +136,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.spacingM
|
||||
width: parent.width + Theme.spacingM
|
||||
text: qsTr("Use Monospace Font")
|
||||
text: I18n.tr("Use Monospace Font")
|
||||
description: "Toggle fonts"
|
||||
checked: SettingsData.notepadUseMonospace
|
||||
onToggled: checked => {
|
||||
@@ -148,7 +148,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.spacingM
|
||||
width: parent.width + Theme.spacingM
|
||||
text: qsTr("Show Line Numbers")
|
||||
text: I18n.tr("Show Line Numbers")
|
||||
description: "Display line numbers in editor"
|
||||
checked: SettingsData.notepadShowLineNumbers
|
||||
onToggled: checked => {
|
||||
@@ -191,14 +191,14 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Find in Text")
|
||||
text: I18n.tr("Find in Text")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Open search bar to find text")
|
||||
text: I18n.tr("Open search bar to find text")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -217,7 +217,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.spacingM
|
||||
width: parent.width + Theme.spacingM
|
||||
text: qsTr("Font Family")
|
||||
text: I18n.tr("Font Family")
|
||||
options: cachedFontFamilies
|
||||
currentValue: {
|
||||
if (!SettingsData.notepadFontFamily || SettingsData.notepadFontFamily === "")
|
||||
@@ -251,7 +251,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Font Size")
|
||||
text: I18n.tr("Font Size")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -330,7 +330,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.spacingM
|
||||
width: parent.width + Theme.spacingM
|
||||
text: qsTr("Custom Transparency")
|
||||
text: I18n.tr("Custom Transparency")
|
||||
description: "Override global transparency for Notepad"
|
||||
checked: SettingsData.notepadTransparencyOverride >= 0
|
||||
onToggled: checked => {
|
||||
|
||||
@@ -265,7 +265,7 @@ Column {
|
||||
StyledText {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: qsTr("Find in note...")
|
||||
text: I18n.tr("Find in note...")
|
||||
font: searchField.font
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
visible: searchField.text.length === 0 && !searchField.activeFocus
|
||||
@@ -275,7 +275,7 @@ Column {
|
||||
// Match count display
|
||||
StyledText {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
text: matchCount > 0 ? qsTr("%1/%2").arg(currentMatchIndex + 1).arg(matchCount) : searchQuery.length > 0 ? qsTr("No matches") : ""
|
||||
text: matchCount > 0 ? I18n.tr("%1/%2").arg(currentMatchIndex + 1).arg(matchCount) : searchQuery.length > 0 ? I18n.tr("No matches") : ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: matchCount > 0 ? Theme.primary : Theme.surfaceTextMedium
|
||||
visible: searchQuery.length > 0
|
||||
@@ -383,7 +383,7 @@ Column {
|
||||
|
||||
TextArea.flickable: TextArea {
|
||||
id: textArea
|
||||
placeholderText: qsTr("Start typing your notes here...")
|
||||
placeholderText: I18n.tr("Start typing your notes here...")
|
||||
placeholderTextColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
font.family: SettingsData.notepadUseMonospace ? SettingsData.monoFontFamily : (SettingsData.notepadFontFamily || SettingsData.fontFamily)
|
||||
font.pixelSize: SettingsData.notepadFontSize * SettingsData.fontScale
|
||||
@@ -508,7 +508,7 @@ Column {
|
||||
}
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Save")
|
||||
text: I18n.tr("Save")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
@@ -524,7 +524,7 @@ Column {
|
||||
}
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Open")
|
||||
text: I18n.tr("Open")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
@@ -540,7 +540,7 @@ Column {
|
||||
}
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("New")
|
||||
text: I18n.tr("New")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
@@ -562,13 +562,13 @@ Column {
|
||||
spacing: Theme.spacingL
|
||||
|
||||
StyledText {
|
||||
text: textArea.text.length > 0 ? qsTr("%1 characters").arg(textArea.text.length) : qsTr("Empty")
|
||||
text: textArea.text.length > 0 ? I18n.tr("%1 characters").arg(textArea.text.length) : I18n.tr("Empty")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Lines: %1").arg(textArea.lineCount)
|
||||
text: I18n.tr("Lines: %1").arg(textArea.lineCount)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
visible: textArea.text.length > 0
|
||||
@@ -578,17 +578,17 @@ Column {
|
||||
StyledText {
|
||||
text: {
|
||||
if (autoSaveTimer.running) {
|
||||
return qsTr("Auto-saving...")
|
||||
return I18n.tr("Auto-saving...")
|
||||
}
|
||||
|
||||
if (hasUnsavedChanges()) {
|
||||
if (currentTab && currentTab.isTemporary) {
|
||||
return qsTr("Unsaved note...")
|
||||
return I18n.tr("Unsaved note...")
|
||||
} else {
|
||||
return qsTr("Unsaved changes")
|
||||
return I18n.tr("Unsaved changes")
|
||||
}
|
||||
} else {
|
||||
return qsTr("Saved")
|
||||
return I18n.tr("Saved")
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
|
||||
@@ -133,10 +133,8 @@ Rectangle {
|
||||
}
|
||||
|
||||
hasImage: hasNotificationImage
|
||||
fallbackIcon: notificationGroup?.latestNotification?.appIcon || "notifications"
|
||||
fallbackIcon: ""
|
||||
fallbackText: {
|
||||
if (hasNotificationImage || (notificationGroup?.latestNotification?.appIcon && notificationGroup.latestNotification.appIcon !== ""))
|
||||
return ""
|
||||
const appName = notificationGroup?.appName || "?"
|
||||
return appName.charAt(0).toUpperCase()
|
||||
}
|
||||
@@ -390,21 +388,11 @@ Rectangle {
|
||||
return ""
|
||||
}
|
||||
|
||||
fallbackIcon: {
|
||||
if (modelData?.appIcon && !hasNotificationImage) {
|
||||
const appIcon = modelData.appIcon
|
||||
if (!appIcon.startsWith("file://") && !appIcon.startsWith("http://") && !appIcon.startsWith("https://"))
|
||||
return appIcon
|
||||
}
|
||||
return "notifications"
|
||||
}
|
||||
fallbackIcon: ""
|
||||
|
||||
fallbackText: {
|
||||
if (!hasNotificationImage && (!modelData?.appIcon || modelData.appIcon === "")) {
|
||||
const appName = modelData?.appName || "?"
|
||||
return appName.charAt(0).toUpperCase()
|
||||
}
|
||||
return ""
|
||||
const appName = modelData?.appName || "?"
|
||||
return appName.charAt(0).toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +537,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: clearText
|
||||
text: qsTr("Clear")
|
||||
text: I18n.tr("Clear")
|
||||
color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
@@ -642,7 +630,7 @@ Rectangle {
|
||||
|
||||
StyledText {
|
||||
id: clearText
|
||||
text: qsTr("Clear")
|
||||
text: I18n.tr("Clear")
|
||||
color: clearButton.isHovered ? Theme.primary : Theme.surfaceVariantText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -24,7 +24,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
text: qsTr("Nothing to see here")
|
||||
text: I18n.tr("Nothing to see here")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -19,7 +19,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Notifications")
|
||||
text: I18n.tr("Notifications")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -53,7 +53,7 @@ Item {
|
||||
StyledText {
|
||||
id: tooltipText
|
||||
|
||||
text: qsTr("Do Not Disturb")
|
||||
text: I18n.tr("Do Not Disturb")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -120,7 +120,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Clear All")
|
||||
text: I18n.tr("Clear All")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -32,7 +32,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close")
|
||||
text: I18n.tr("Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
width: parent.width
|
||||
|
||||
@@ -105,7 +105,7 @@ Rectangle {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Notification Settings")
|
||||
text: I18n.tr("Notification Settings")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
@@ -128,7 +128,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Do Not Disturb")
|
||||
text: I18n.tr("Do Not Disturb")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -150,14 +150,14 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Notification Timeouts")
|
||||
text: I18n.tr("Notification Timeouts")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Low Priority")
|
||||
text: I18n.tr("Low Priority")
|
||||
description: "Timeout for low priority notifications"
|
||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
|
||||
options: timeoutOptions.map(opt => opt.text)
|
||||
@@ -172,7 +172,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Normal Priority")
|
||||
text: I18n.tr("Normal Priority")
|
||||
description: "Timeout for normal priority notifications"
|
||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
|
||||
options: timeoutOptions.map(opt => opt.text)
|
||||
@@ -187,7 +187,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Critical Priority")
|
||||
text: I18n.tr("Critical Priority")
|
||||
description: "Timeout for critical priority notifications"
|
||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
|
||||
options: timeoutOptions.map(opt => opt.text)
|
||||
@@ -228,13 +228,13 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Notification Overlay")
|
||||
text: I18n.tr("Notification Overlay")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Display all priorities over fullscreen apps")
|
||||
text: I18n.tr("Display all priorities over fullscreen apps")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ PanelWindow {
|
||||
property bool exiting: false
|
||||
property bool _isDestroying: false
|
||||
property bool _finalized: false
|
||||
readonly property string clearText: I18n.tr("Clear")
|
||||
|
||||
signal entered
|
||||
signal exitFinished
|
||||
@@ -316,10 +317,8 @@ PanelWindow {
|
||||
}
|
||||
|
||||
hasImage: hasNotificationImage
|
||||
fallbackIcon: notificationData?.appIcon || "notifications"
|
||||
fallbackIcon: ""
|
||||
fallbackText: {
|
||||
if (hasNotificationImage || (notificationData?.appIcon && notificationData.appIcon !== ""))
|
||||
return ""
|
||||
const appName = notificationData?.appName || "?"
|
||||
return appName.charAt(0).toUpperCase()
|
||||
}
|
||||
@@ -478,16 +477,16 @@ PanelWindow {
|
||||
anchors.rightMargin: 16
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
width: Math.max(clearText.implicitWidth + 12, 50)
|
||||
width: Math.max(clearTextLabel.implicitWidth + 12, 50)
|
||||
height: 24
|
||||
radius: 4
|
||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||
z: 20
|
||||
|
||||
StyledText {
|
||||
id: clearText
|
||||
id: clearTextLabel
|
||||
|
||||
text: qsTr("Clear")
|
||||
text: win.clearText
|
||||
color: clearButton.isHovered ? Theme.primary : Theme.surfaceVariantText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -76,7 +76,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No items added yet")
|
||||
text: I18n.tr("No items added yet")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
visible: root.items.length === 0
|
||||
@@ -111,7 +111,7 @@ Column {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Remove")
|
||||
text: I18n.tr("Remove")
|
||||
color: Theme.errorText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -123,7 +123,7 @@ Column {
|
||||
id: addButton
|
||||
width: 50
|
||||
height: 36
|
||||
text: qsTr("Add")
|
||||
text: I18n.tr("Add")
|
||||
|
||||
onClicked: {
|
||||
let newItem = {}
|
||||
@@ -159,7 +159,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Current Items")
|
||||
text: I18n.tr("Current Items")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -227,7 +227,7 @@ Column {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Remove")
|
||||
text: I18n.tr("Remove")
|
||||
color: Theme.onError
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
@@ -247,7 +247,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No items added yet")
|
||||
text: I18n.tr("No items added yet")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
visible: root.items.length === 0
|
||||
|
||||
@@ -8,16 +8,24 @@ Item {
|
||||
|
||||
required property string pluginId
|
||||
property var pluginService: null
|
||||
default property alias content: settingsColumn.children
|
||||
default property list<QtObject> content
|
||||
|
||||
signal settingChanged()
|
||||
|
||||
property var variants: []
|
||||
property alias variantsModel: variantsListModel
|
||||
|
||||
implicitHeight: hasPermission ? settingsColumn.implicitHeight : errorText.implicitHeight
|
||||
height: implicitHeight
|
||||
|
||||
readonly property bool hasPermission: pluginService && pluginService.hasPermission ? pluginService.hasPermission(pluginId, "settings_write") : true
|
||||
readonly property bool hasPermission: {
|
||||
if (!pluginService || !pluginId) return true
|
||||
const allPlugins = pluginService.availablePlugins
|
||||
const plugin = allPlugins[pluginId]
|
||||
if (!plugin) return true
|
||||
const permissions = Array.isArray(plugin.permissions) ? plugin.permissions : []
|
||||
return permissions.indexOf("settings_write") !== -1
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
loadVariants()
|
||||
@@ -26,8 +34,8 @@ Item {
|
||||
onPluginServiceChanged: {
|
||||
if (pluginService) {
|
||||
loadVariants()
|
||||
for (let i = 0; i < settingsColumn.children.length; i++) {
|
||||
const child = settingsColumn.children[i]
|
||||
for (let i = 0; i < content.length; i++) {
|
||||
const child = content[i]
|
||||
if (child.loadValue) {
|
||||
child.loadValue()
|
||||
}
|
||||
@@ -35,6 +43,15 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
onContentChanged: {
|
||||
for (let i = 0; i < content.length; i++) {
|
||||
const item = content[i]
|
||||
if (item instanceof Item) {
|
||||
item.parent = settingsColumn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: pluginService
|
||||
function onPluginDataChanged(changedPluginId) {
|
||||
@@ -50,6 +67,22 @@ Item {
|
||||
return
|
||||
}
|
||||
variants = pluginService.getPluginVariants(pluginId)
|
||||
syncVariantsToModel()
|
||||
}
|
||||
|
||||
function syncVariantsToModel() {
|
||||
variantsListModel.clear()
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
variantsListModel.append(variants[i])
|
||||
}
|
||||
}
|
||||
|
||||
onVariantsChanged: {
|
||||
syncVariantsToModel()
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: variantsListModel
|
||||
}
|
||||
|
||||
function createVariant(variantName, variantConfig) {
|
||||
@@ -94,11 +127,47 @@ Item {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
function findFlickable(item) {
|
||||
var current = item?.parent
|
||||
while (current) {
|
||||
if (current.contentY !== undefined && current.contentHeight !== undefined) {
|
||||
return current
|
||||
}
|
||||
current = current.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function ensureItemVisible(item) {
|
||||
if (!item) return
|
||||
|
||||
var flickable = findFlickable(root)
|
||||
if (!flickable) return
|
||||
|
||||
var itemGlobalY = item.mapToItem(null, 0, 0).y
|
||||
var itemHeight = item.height
|
||||
var flickableGlobalY = flickable.mapToItem(null, 0, 0).y
|
||||
var viewportHeight = flickable.height
|
||||
|
||||
var itemRelativeY = itemGlobalY - flickableGlobalY
|
||||
var viewportTop = 0
|
||||
var viewportBottom = viewportHeight
|
||||
|
||||
if (itemRelativeY < viewportTop) {
|
||||
flickable.contentY = Math.max(0, flickable.contentY - (viewportTop - itemRelativeY) - Theme.spacingL)
|
||||
} else if (itemRelativeY + itemHeight > viewportBottom) {
|
||||
flickable.contentY = Math.min(
|
||||
flickable.contentHeight - viewportHeight,
|
||||
flickable.contentY + (itemRelativeY + itemHeight - viewportBottom) + Theme.spacingL
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: errorText
|
||||
visible: pluginService && !root.hasPermission
|
||||
anchors.fill: parent
|
||||
text: "This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json"
|
||||
text: I18n.tr("This plugin does not have 'settings_write' permission.\n\nAdd \"permissions\": [\"settings_read\", \"settings_write\"] to plugin.json")
|
||||
color: Theme.error
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
@@ -194,7 +194,7 @@ Column {
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Memory")
|
||||
text: I18n.tr("Memory")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
@@ -269,7 +269,7 @@ Column {
|
||||
spacing: 4
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Swap")
|
||||
text: I18n.tr("Swap")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
@@ -359,7 +359,7 @@ Column {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Network")
|
||||
text: I18n.tr("Network")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
@@ -425,7 +425,7 @@ Column {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Disk")
|
||||
text: I18n.tr("Disk")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
|
||||
@@ -85,7 +85,7 @@ Popup {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Copy PID")
|
||||
text: I18n.tr("Copy PID")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -118,7 +118,7 @@ Popup {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Copy Process Name")
|
||||
text: I18n.tr("Copy Process Name")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -168,7 +168,7 @@ Popup {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Kill Process")
|
||||
text: I18n.tr("Kill Process")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: parent.enabled ? (killArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
font.weight: Font.Normal
|
||||
@@ -204,7 +204,7 @@ Popup {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Force Kill Process")
|
||||
text: I18n.tr("Force Kill Process")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: parent.enabled ? (forceKillArea.containsMouse ? Theme.error : Theme.surfaceText) : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||
font.weight: Font.Normal
|
||||
|
||||
@@ -38,7 +38,7 @@ Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Process")
|
||||
text: I18n.tr("Process")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: DgopService.currentSort === "name" ? Font.Bold : Font.Medium
|
||||
|
||||
@@ -48,7 +48,7 @@ Row {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("CPU")
|
||||
text: I18n.tr("CPU")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: DgopService.sortBy === "cpu" ? Theme.primary : Theme.secondary
|
||||
@@ -163,7 +163,7 @@ Row {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Memory")
|
||||
text: I18n.tr("Memory")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: DgopService.sortBy === "memory" ? Theme.primary : Theme.secondary
|
||||
@@ -315,7 +315,7 @@ Row {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("GPU")
|
||||
text: I18n.tr("GPU")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.secondary
|
||||
@@ -388,7 +388,7 @@ Row {
|
||||
id: gpuContextMenu
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Enable GPU Temperature")
|
||||
text: I18n.tr("Enable GPU Temperature")
|
||||
checkable: true
|
||||
checked: {
|
||||
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|
||||
|
||||
@@ -69,7 +69,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `Up ${UserInfoService.uptime} • Boot: ${DgopService.bootTime}`
|
||||
text: `${UserInfoService.uptime} • Boot: ${DgopService.bootTime}`
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
@@ -127,7 +127,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("System")
|
||||
text: I18n.tr("System")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -411,7 +411,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Storage & Disks")
|
||||
text: I18n.tr("Storage & Disks")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -431,7 +431,7 @@ DankFlickable {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Device")
|
||||
text: I18n.tr("Device")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -442,7 +442,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Mount")
|
||||
text: I18n.tr("Mount")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -453,7 +453,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Size")
|
||||
text: I18n.tr("Size")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -464,7 +464,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Used")
|
||||
text: I18n.tr("Used")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -475,7 +475,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Available")
|
||||
text: I18n.tr("Available")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
@@ -486,7 +486,7 @@ DankFlickable {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Use%")
|
||||
text: I18n.tr("Use%")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.family: SettingsData.monoFontFamily
|
||||
font.weight: Font.Bold
|
||||
|
||||
@@ -248,7 +248,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("About")
|
||||
text: I18n.tr("About")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -258,7 +258,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: `dms is a highly customizable, modern desktop shell with a <a href="https://m3.material.io/" style="text-decoration:none; color:${Theme.primary};">material 3 inspired</a> design.
|
||||
<br /><br/>It is built on top of <a href="https://quickshell.org" style="text-decoration:none; color:${Theme.primary};">Quickshell</a>, a QT6 framework for building desktop shells.
|
||||
<br /><br/>It is built with <a href="https://quickshell.org" style="text-decoration:none; color:${Theme.primary};">Quickshell</a>, a QT6 framework for building desktop shells, and <a href="https://go.dev" style="text-decoration:none; color:${Theme.primary};">Go</a>, a statically typed, compiled programming language.
|
||||
`
|
||||
textFormat: Text.RichText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -307,7 +307,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Technical Details")
|
||||
text: I18n.tr("Technical Details")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -322,7 +322,7 @@ Item {
|
||||
rowSpacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Framework:")
|
||||
text: I18n.tr("Framework:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -345,20 +345,20 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Language:")
|
||||
text: I18n.tr("Language:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("QML (Qt Modeling Language)")
|
||||
text: I18n.tr("QML, JavaScript, Go")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Compositor:")
|
||||
text: I18n.tr("Compositor:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -410,7 +410,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Github:")
|
||||
text: I18n.tr("Github:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -437,7 +437,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("- Support Us With a Star ⭐")
|
||||
text: I18n.tr("- Support Us With a Star ⭐")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -445,7 +445,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("System Monitoring:")
|
||||
text: I18n.tr("System Monitoring:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -472,7 +472,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("- Stateless System Monitoring")
|
||||
text: I18n.tr("- Stateless System Monitoring")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -480,7 +480,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Dank Suite:")
|
||||
text: I18n.tr("Dank Suite:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
|
||||
@@ -22,170 +22,170 @@ Item {
|
||||
property var baseWidgetDefinitions: {
|
||||
var coreWidgets = [{
|
||||
"id": "launcherButton",
|
||||
"text": "App Launcher",
|
||||
"description": "Quick access to application launcher",
|
||||
"text": I18n.tr("App Launcher"),
|
||||
"description": I18n.tr("Quick access to application launcher"),
|
||||
"icon": "apps",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "workspaceSwitcher",
|
||||
"text": "Workspace Switcher",
|
||||
"description": "Shows current workspace and allows switching",
|
||||
"text": I18n.tr("Workspace Switcher"),
|
||||
"description": I18n.tr("Shows current workspace and allows switching"),
|
||||
"icon": "view_module",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "focusedWindow",
|
||||
"text": "Focused Window",
|
||||
"description": "Display currently focused application title",
|
||||
"text": I18n.tr("Focused Window"),
|
||||
"description": I18n.tr("Display currently focused application title"),
|
||||
"icon": "window",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "runningApps",
|
||||
"text": "Running Apps",
|
||||
"description": "Shows all running applications with focus indication",
|
||||
"text": I18n.tr("Running Apps"),
|
||||
"description": I18n.tr("Shows all running applications with focus indication"),
|
||||
"icon": "apps",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "clock",
|
||||
"text": "Clock",
|
||||
"description": "Current time and date display",
|
||||
"text": I18n.tr("Clock"),
|
||||
"description": I18n.tr("Current time and date display"),
|
||||
"icon": "schedule",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "weather",
|
||||
"text": "Weather Widget",
|
||||
"description": "Current weather conditions and temperature",
|
||||
"text": I18n.tr("Weather Widget"),
|
||||
"description": I18n.tr("Current weather conditions and temperature"),
|
||||
"icon": "wb_sunny",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "music",
|
||||
"text": "Media Controls",
|
||||
"description": "Control currently playing media",
|
||||
"text": I18n.tr("Media Controls"),
|
||||
"description": I18n.tr("Control currently playing media"),
|
||||
"icon": "music_note",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "clipboard",
|
||||
"text": "Clipboard Manager",
|
||||
"description": "Access clipboard history",
|
||||
"text": I18n.tr("Clipboard Manager"),
|
||||
"description": I18n.tr("Access clipboard history"),
|
||||
"icon": "content_paste",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "cpuUsage",
|
||||
"text": "CPU Usage",
|
||||
"description": "CPU usage indicator",
|
||||
"text": I18n.tr("CPU Usage"),
|
||||
"description": I18n.tr("CPU usage indicator"),
|
||||
"icon": "memory",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
|
||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined
|
||||
}, {
|
||||
"id": "memUsage",
|
||||
"text": "Memory Usage",
|
||||
"description": "Memory usage indicator",
|
||||
"text": I18n.tr("Memory Usage"),
|
||||
"description": I18n.tr("Memory usage indicator"),
|
||||
"icon": "developer_board",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
|
||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined
|
||||
}, {
|
||||
"id": "diskUsage",
|
||||
"text": "Disk Usage",
|
||||
"description": "Percentage",
|
||||
"text": I18n.tr("Disk Usage"),
|
||||
"description": I18n.tr("Percentage"),
|
||||
"icon": "storage",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
|
||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined
|
||||
}, {
|
||||
"id": "cpuTemp",
|
||||
"text": "CPU Temperature",
|
||||
"description": "CPU temperature display",
|
||||
"text": I18n.tr("CPU Temperature"),
|
||||
"description": I18n.tr("CPU temperature display"),
|
||||
"icon": "device_thermostat",
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined
|
||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined
|
||||
}, {
|
||||
"id": "gpuTemp",
|
||||
"text": "GPU Temperature",
|
||||
"description": "GPU temperature display",
|
||||
"text": I18n.tr("GPU Temperature"),
|
||||
"description": I18n.tr("GPU temperature display"),
|
||||
"icon": "auto_awesome_mosaic",
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : "This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics.",
|
||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : I18n.tr("This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics."),
|
||||
"enabled": DgopService.dgopAvailable
|
||||
}, {
|
||||
"id": "systemTray",
|
||||
"text": "System Tray",
|
||||
"description": "System notification area icons",
|
||||
"text": I18n.tr("System Tray"),
|
||||
"description": I18n.tr("System notification area icons"),
|
||||
"icon": "notifications",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "privacyIndicator",
|
||||
"text": "Privacy Indicator",
|
||||
"description": "Shows when microphone, camera, or screen sharing is active",
|
||||
"text": I18n.tr("Privacy Indicator"),
|
||||
"description": I18n.tr("Shows when microphone, camera, or screen sharing is active"),
|
||||
"icon": "privacy_tip",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "controlCenterButton",
|
||||
"text": "Control Center",
|
||||
"description": "Access to system controls and settings",
|
||||
"text": I18n.tr("Control Center"),
|
||||
"description": I18n.tr("Access to system controls and settings"),
|
||||
"icon": "settings",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "notificationButton",
|
||||
"text": "Notification Center",
|
||||
"description": "Access to notifications and do not disturb",
|
||||
"text": I18n.tr("Notification Center"),
|
||||
"description": I18n.tr("Access to notifications and do not disturb"),
|
||||
"icon": "notifications",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "battery",
|
||||
"text": "Battery",
|
||||
"description": "Battery level and power management",
|
||||
"text": I18n.tr("Battery"),
|
||||
"description": I18n.tr("Battery level and power management"),
|
||||
"icon": "battery_std",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "vpn",
|
||||
"text": "VPN",
|
||||
"description": "VPN status and quick connect",
|
||||
"text": I18n.tr("VPN"),
|
||||
"description": I18n.tr("VPN status and quick connect"),
|
||||
"icon": "vpn_lock",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "idleInhibitor",
|
||||
"text": "Idle Inhibitor",
|
||||
"description": "Prevent screen timeout",
|
||||
"text": I18n.tr("Idle Inhibitor"),
|
||||
"description": I18n.tr("Prevent screen timeout"),
|
||||
"icon": "motion_sensor_active",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "spacer",
|
||||
"text": "Spacer",
|
||||
"description": "Customizable empty space",
|
||||
"text": I18n.tr("Spacer"),
|
||||
"description": I18n.tr("Customizable empty space"),
|
||||
"icon": "more_horiz",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "separator",
|
||||
"text": "Separator",
|
||||
"description": "Visual divider between widgets",
|
||||
"text": I18n.tr("Separator"),
|
||||
"description": I18n.tr("Visual divider between widgets"),
|
||||
"icon": "remove",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"id": "network_speed_monitor",
|
||||
"text": "Network Speed Monitor",
|
||||
"description": "Network download and upload speed display",
|
||||
"text": I18n.tr("Network Speed Monitor"),
|
||||
"description": I18n.tr("Network download and upload speed display"),
|
||||
"icon": "network_check",
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
|
||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : undefined,
|
||||
"enabled": DgopService.dgopAvailable
|
||||
}, {
|
||||
"id": "keyboard_layout_name",
|
||||
"text": "Keyboard Layout Name",
|
||||
"description": "Displays the active keyboard layout and allows switching",
|
||||
"text": I18n.tr("Keyboard Layout Name"),
|
||||
"description": I18n.tr("Displays the active keyboard layout and allows switching"),
|
||||
"icon": "keyboard",
|
||||
}, {
|
||||
"id": "notepadButton",
|
||||
"text": "Notepad",
|
||||
"description": "Quick access to notepad",
|
||||
"text": I18n.tr("Notepad"),
|
||||
"description": I18n.tr("Quick access to notepad"),
|
||||
"icon": "assignment",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "colorPicker",
|
||||
"text": "Color Picker",
|
||||
"description": "Quick access to color picker",
|
||||
"text": I18n.tr("Color Picker"),
|
||||
"description": I18n.tr("Quick access to color picker"),
|
||||
"icon": "palette",
|
||||
"enabled": true
|
||||
}, {
|
||||
"id": "systemUpdate",
|
||||
"text": "System Update",
|
||||
"description": "Check for system updates",
|
||||
"text": I18n.tr("System Update"),
|
||||
"description": I18n.tr("Check for system updates"),
|
||||
"icon": "update",
|
||||
"enabled": SystemUpdateService.distributionSupported
|
||||
}]
|
||||
@@ -199,7 +199,7 @@ Item {
|
||||
"description": variant.description,
|
||||
"icon": variant.icon,
|
||||
"enabled": variant.loaded,
|
||||
"warning": !variant.loaded ? "Plugin is disabled - enable in Plugins settings to use" : undefined
|
||||
"warning": !variant.loaded ? I18n.tr("Plugin is disabled - enable in Plugins settings to use") : undefined
|
||||
})
|
||||
}
|
||||
|
||||
@@ -695,7 +695,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Position")
|
||||
text: I18n.tr("Position")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -765,14 +765,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Auto-hide")
|
||||
text: I18n.tr("Auto-hide")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Automatically hide the top bar to expand screen real estate")
|
||||
text: I18n.tr("Automatically hide the top bar to expand screen real estate")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -817,14 +817,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: "Manual Show/Hide"
|
||||
text: I18n.tr("Manual Show/Hide")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Toggle top bar visibility manually (can be controlled via IPC)")
|
||||
text: I18n.tr("Toggle top bar visibility manually (can be controlled via IPC)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -871,14 +871,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Show on Overview")
|
||||
text: I18n.tr("Show on Overview")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Always show the top bar when niri's overview is open"
|
||||
text: I18n.tr("Always show the top bar when niri's overview is open")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -930,7 +930,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Spacing")
|
||||
text: I18n.tr("Spacing")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -942,14 +942,51 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Edge Spacing (0 = edge-to-edge)"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Edge Spacing (0 = edge-to-edge)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - edgeSpacingText.implicitWidth - resetEdgeSpacingBtn.width - Theme.spacingS - Theme.spacingM
|
||||
height: 1
|
||||
|
||||
StyledText {
|
||||
id: edgeSpacingText
|
||||
visible: false
|
||||
text: I18n.tr("Edge Spacing (0 = edge-to-edge)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: resetEdgeSpacingBtn
|
||||
buttonSize: 20
|
||||
iconName: "refresh"
|
||||
iconSize: 12
|
||||
backgroundColor: Theme.surfaceContainerHigh
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.setDankBarSpacing(4)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Theme.spacingS
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: edgeSpacingSlider
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: SettingsData.dankBarSpacing
|
||||
@@ -963,6 +1000,13 @@ Item {
|
||||
SettingsData.setDankBarSpacing(
|
||||
newValue)
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: edgeSpacingSlider
|
||||
property: "value"
|
||||
value: SettingsData.dankBarSpacing
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,19 +1014,56 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Exclusive Zone Offset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Exclusive Zone Offset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - exclusiveZoneText.implicitWidth - resetExclusiveZoneBtn.width - Theme.spacingS - Theme.spacingM
|
||||
height: 1
|
||||
|
||||
StyledText {
|
||||
id: exclusiveZoneText
|
||||
visible: false
|
||||
text: I18n.tr("Exclusive Zone Offset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: resetExclusiveZoneBtn
|
||||
buttonSize: 20
|
||||
iconName: "refresh"
|
||||
iconSize: 12
|
||||
backgroundColor: Theme.surfaceContainerHigh
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.setDankBarBottomGap(0)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Theme.spacingS
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: exclusiveZoneSlider
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: SettingsData.dankBarBottomGap
|
||||
minimum: -100
|
||||
maximum: 100
|
||||
minimum: -50
|
||||
maximum: 50
|
||||
unit: ""
|
||||
showValue: true
|
||||
wheelEnabled: false
|
||||
@@ -991,6 +1072,13 @@ Item {
|
||||
SettingsData.setDankBarBottomGap(
|
||||
newValue)
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: exclusiveZoneSlider
|
||||
property: "value"
|
||||
value: SettingsData.dankBarBottomGap
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,14 +1086,51 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Size")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Size")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - sizeText.implicitWidth - resetSizeBtn.width - Theme.spacingS - Theme.spacingM
|
||||
height: 1
|
||||
|
||||
StyledText {
|
||||
id: sizeText
|
||||
visible: false
|
||||
text: I18n.tr("Size")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: resetSizeBtn
|
||||
buttonSize: 20
|
||||
iconName: "refresh"
|
||||
iconSize: 12
|
||||
backgroundColor: Theme.surfaceContainerHigh
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.setDankBarInnerPadding(4)
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Theme.spacingS
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: sizeSlider
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: SettingsData.dankBarInnerPadding
|
||||
@@ -1019,13 +1144,20 @@ Item {
|
||||
SettingsData.setDankBarInnerPadding(
|
||||
newValue)
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: sizeSlider
|
||||
property: "value"
|
||||
value: SettingsData.dankBarInnerPadding
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Square Corners")
|
||||
text: I18n.tr("Square Corners")
|
||||
description: "Removes rounded corners from bar container."
|
||||
checked: SettingsData.dankBarSquareCorners
|
||||
onToggled: checked => {
|
||||
@@ -1036,7 +1168,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("No Background")
|
||||
text: I18n.tr("No Background")
|
||||
description: "Remove widget backgrounds for a minimal look with tighter spacing."
|
||||
checked: SettingsData.dankBarNoBackground
|
||||
onToggled: checked => {
|
||||
@@ -1047,7 +1179,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Goth Corners")
|
||||
text: I18n.tr("Goth Corners")
|
||||
description: "Add curved swooping tips at the bottom of the bar."
|
||||
checked: SettingsData.dankBarGothCornersEnabled
|
||||
onToggled: checked => {
|
||||
@@ -1056,14 +1188,227 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
Column {
|
||||
width: parent.width
|
||||
text: qsTr("Border")
|
||||
description: "Add a 1px border to the bar. Smart edge detection only shows border on exposed sides."
|
||||
checked: SettingsData.dankBarBorderEnabled
|
||||
onToggled: checked => {
|
||||
SettingsData.setDankBarBorderEnabled(checked)
|
||||
}
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Border")
|
||||
description: "Add a 1px border to the bar. Smart edge detection only shows border on exposed sides."
|
||||
checked: SettingsData.dankBarBorderEnabled
|
||||
onToggled: checked => {
|
||||
SettingsData.setDankBarBorderEnabled(checked)
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
leftPadding: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
visible: SettingsData.dankBarBorderEnabled
|
||||
|
||||
Rectangle {
|
||||
width: parent.width - parent.leftPadding
|
||||
height: 1
|
||||
color: Theme.outline
|
||||
opacity: 0.2
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width - parent.leftPadding
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Column {
|
||||
width: parent.width - borderColorGroup.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Border Color")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Choose the border accent color")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
|
||||
DankButtonGroup {
|
||||
id: borderColorGroup
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
model: ["Surface", "Secondary", "Primary"]
|
||||
currentIndex: {
|
||||
const colorOption = SettingsData.dankBarBorderColor || "surfaceText"
|
||||
switch (colorOption) {
|
||||
case "surfaceText": return 0
|
||||
case "secondary": return 1
|
||||
case "primary": return 2
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (selected) {
|
||||
let newColor = "surfaceText"
|
||||
switch (index) {
|
||||
case 0: newColor = "surfaceText"; break
|
||||
case 1: newColor = "secondary"; break
|
||||
case 2: newColor = "primary"; break
|
||||
}
|
||||
if (SettingsData.dankBarBorderColor !== newColor) {
|
||||
SettingsData.dankBarBorderColor = newColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - parent.leftPadding
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Border Opacity")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - borderOpacityText.implicitWidth - resetBorderOpacityBtn.width - Theme.spacingS - Theme.spacingM
|
||||
height: 1
|
||||
|
||||
StyledText {
|
||||
id: borderOpacityText
|
||||
visible: false
|
||||
text: I18n.tr("Border Opacity")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: resetBorderOpacityBtn
|
||||
buttonSize: 20
|
||||
iconName: "refresh"
|
||||
iconSize: 12
|
||||
backgroundColor: Theme.surfaceContainerHigh
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.dankBarBorderOpacity = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Theme.spacingS
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: borderOpacitySlider
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: (SettingsData.dankBarBorderOpacity ?? 1.0) * 100
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
unit: "%"
|
||||
showValue: true
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.surfaceContainerHigh
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.dankBarBorderOpacity = newValue / 100
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: borderOpacitySlider
|
||||
property: "value"
|
||||
value: (SettingsData.dankBarBorderOpacity ?? 1.0) * 100
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - parent.leftPadding
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Border Thickness")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - borderThicknessText.implicitWidth - resetBorderThicknessBtn.width - Theme.spacingS - Theme.spacingM
|
||||
height: 1
|
||||
|
||||
StyledText {
|
||||
id: borderThicknessText
|
||||
visible: false
|
||||
text: I18n.tr("Border Thickness")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: resetBorderThicknessBtn
|
||||
buttonSize: 20
|
||||
iconName: "refresh"
|
||||
iconSize: 12
|
||||
backgroundColor: Theme.surfaceContainerHigh
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.dankBarBorderThickness = 1
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: Theme.spacingS
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
id: borderThicknessSlider
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: SettingsData.dankBarBorderThickness ?? 1
|
||||
minimum: 1
|
||||
maximum: 10
|
||||
unit: "px"
|
||||
showValue: true
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.surfaceContainerHigh
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.dankBarBorderThickness = newValue
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: borderThicknessSlider
|
||||
property: "value"
|
||||
value: SettingsData.dankBarBorderThickness ?? 1
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -1088,14 +1433,14 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("DankBar Font Scale")
|
||||
text: I18n.tr("DankBar Font Scale")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Scale DankBar font sizes independently")
|
||||
text: I18n.tr("Scale DankBar font sizes independently")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
@@ -1190,7 +1535,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
id: widgetTitle
|
||||
text: qsTr("Widget Management")
|
||||
text: I18n.tr("Widget Management")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1228,7 +1573,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Reset")
|
||||
text: I18n.tr("Reset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1270,7 +1615,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely."
|
||||
text: I18n.tr("Drag widgets to reorder within sections. Use the eye icon to hide/show widgets (maintains spacing), or X to remove them completely.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -1372,7 +1717,7 @@ Item {
|
||||
id: centerSection
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
title: qsTr("Center Section")
|
||||
title: I18n.tr("Center Section")
|
||||
titleIcon: "format_align_center"
|
||||
sectionId: "center"
|
||||
allWidgets: dankBarTab.baseWidgetDefinitions
|
||||
|
||||
@@ -76,6 +76,378 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: gammaSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: gammaSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "brightness_6"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Gamma Control")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: nightModeToggle
|
||||
|
||||
width: parent.width
|
||||
text: I18n.tr("Night Mode")
|
||||
description: "Apply warm color temperature to reduce eye strain. Use automation settings below to control when it activates."
|
||||
checked: DisplayService.nightModeEnabled
|
||||
onToggled: checked => {
|
||||
DisplayService.toggleNightMode()
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onNightModeEnabledChanged() {
|
||||
nightModeToggle.checked = DisplayService.nightModeEnabled
|
||||
}
|
||||
|
||||
target: DisplayService
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: 0
|
||||
leftPadding: Theme.spacingM
|
||||
rightPadding: Theme.spacingM
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width - parent.leftPadding - parent.rightPadding
|
||||
text: I18n.tr("Temperature")
|
||||
description: I18n.tr("Color temperature for night mode")
|
||||
currentValue: SessionData.nightModeTemperature + "K"
|
||||
options: {
|
||||
var temps = []
|
||||
for (var i = 2500; i <= 6000; i += 500) {
|
||||
temps.push(i + "K")
|
||||
}
|
||||
return temps
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var temp = parseInt(value.replace("K", ""))
|
||||
SessionData.setNightModeTemperature(temp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: automaticToggle
|
||||
width: parent.width
|
||||
text: I18n.tr("Automatic Control")
|
||||
description: "Only adjust gamma based on time or location rules."
|
||||
checked: SessionData.nightModeAutoEnabled
|
||||
onToggled: checked => {
|
||||
if (checked && !DisplayService.nightModeEnabled) {
|
||||
DisplayService.toggleNightMode()
|
||||
} else if (!checked && DisplayService.nightModeEnabled) {
|
||||
DisplayService.toggleNightMode()
|
||||
}
|
||||
SessionData.setNightModeAutoEnabled(checked)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoEnabledChanged() {
|
||||
automaticToggle.checked = SessionData.nightModeAutoEnabled
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: automaticSettings
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
visible: SessionData.nightModeAutoEnabled
|
||||
leftPadding: Theme.spacingM
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoEnabledChanged() {
|
||||
automaticSettings.visible = SessionData.nightModeAutoEnabled
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 200
|
||||
height: 45 + Theme.spacingM
|
||||
|
||||
DankTabBar {
|
||||
id: modeTabBarNight
|
||||
width: 200
|
||||
height: 45
|
||||
model: [{
|
||||
"text": "Time",
|
||||
"icon": "access_time"
|
||||
}, {
|
||||
"text": "Location",
|
||||
"icon": "place"
|
||||
}]
|
||||
|
||||
Component.onCompleted: {
|
||||
currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0
|
||||
Qt.callLater(updateIndicator)
|
||||
}
|
||||
|
||||
onTabClicked: index => {
|
||||
console.log("Tab clicked:", index, "Setting mode to:", index === 1 ? "location" : "time")
|
||||
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time")
|
||||
currentIndex = index
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoModeChanged() {
|
||||
modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0
|
||||
Qt.callLater(modeTabBarNight.updateIndicator)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
property bool isTimeMode: SessionData.nightModeAutoMode === "time"
|
||||
visible: isTimeMode
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
height: 20
|
||||
leftPadding: 45
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Hour")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: 50
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Minute")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: 50
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
anchors.bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
height: 32
|
||||
|
||||
StyledText {
|
||||
id: startLabel
|
||||
text: I18n.tr("Start")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
width: 50
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: 60
|
||||
height: 32
|
||||
text: ""
|
||||
currentValue: SessionData.nightModeStartHour.toString()
|
||||
options: {
|
||||
var hours = []
|
||||
for (var i = 0; i < 24; i++) {
|
||||
hours.push(i.toString())
|
||||
}
|
||||
return hours
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeStartHour(parseInt(value))
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: 60
|
||||
height: 32
|
||||
text: ""
|
||||
currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0')
|
||||
options: {
|
||||
var minutes = []
|
||||
for (var i = 0; i < 60; i += 5) {
|
||||
minutes.push(i.toString().padStart(2, '0'))
|
||||
}
|
||||
return minutes
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeStartMinute(parseInt(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
height: 32
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("End")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
width: startLabel.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: 60
|
||||
height: 32
|
||||
text: ""
|
||||
currentValue: SessionData.nightModeEndHour.toString()
|
||||
options: {
|
||||
var hours = []
|
||||
for (var i = 0; i < 24; i++) {
|
||||
hours.push(i.toString())
|
||||
}
|
||||
return hours
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeEndHour(parseInt(value))
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: 60
|
||||
height: 32
|
||||
text: ""
|
||||
currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0')
|
||||
options: {
|
||||
var minutes = []
|
||||
for (var i = 0; i < 60; i += 5) {
|
||||
minutes.push(i.toString().padStart(2, '0'))
|
||||
}
|
||||
return minutes
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeEndMinute(parseInt(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
property bool isLocationMode: SessionData.nightModeAutoMode === "location"
|
||||
visible: isLocationMode
|
||||
spacing: Theme.spacingM
|
||||
width: parent.width
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Auto-location")
|
||||
description: DisplayService.geoclueAvailable ? "Use automatic location detection (geoclue2)" : "Geoclue service not running - cannot auto-detect location"
|
||||
checked: SessionData.nightModeLocationProvider === "geoclue2"
|
||||
enabled: DisplayService.geoclueAvailable
|
||||
onToggled: checked => {
|
||||
if (checked && DisplayService.geoclueAvailable) {
|
||||
SessionData.setNightModeLocationProvider("geoclue2")
|
||||
SessionData.setLatitude(0.0)
|
||||
SessionData.setLongitude(0.0)
|
||||
} else {
|
||||
SessionData.setNightModeLocationProvider("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Manual Coordinates")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
visible: SessionData.nightModeLocationProvider !== "geoclue2"
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
visible: SessionData.nightModeLocationProvider !== "geoclue2"
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Latitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: 120
|
||||
height: 40
|
||||
text: SessionData.latitude.toString()
|
||||
placeholderText: "0.0"
|
||||
onTextChanged: {
|
||||
const lat = parseFloat(text) || 0.0
|
||||
if (lat >= -90 && lat <= 90) {
|
||||
SessionData.setLatitude(lat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Longitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: 120
|
||||
height: 40
|
||||
text: SessionData.longitude.toString()
|
||||
placeholderText: "0.0"
|
||||
onTextChanged: {
|
||||
const lon = parseFloat(text) || 0.0
|
||||
if (lon >= -180 && lon <= 180) {
|
||||
SessionData.setLongitude(lon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Uses sunrise/sunset times to automatically adjust night mode based on your location.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: screensInfoSection.implicitHeight + Theme.spacingL * 2
|
||||
@@ -108,14 +480,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Connected Displays")
|
||||
text: I18n.tr("Connected Displays")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Configure which displays show shell components")
|
||||
text: I18n.tr("Configure which displays show shell components")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -131,7 +503,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Available Screens (") + Quickshell.screens.length + ")"
|
||||
text: I18n.tr("Available Screens (") + Quickshell.screens.length + ")"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -273,7 +645,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Show on screens:")
|
||||
text: I18n.tr("Show on screens:")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -288,8 +660,8 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("All displays")
|
||||
description: "Show on all connected displays"
|
||||
text: I18n.tr("All displays")
|
||||
description: I18n.tr("Show on all connected displays")
|
||||
checked: parent.selectedScreens.includes("all")
|
||||
onToggled: (checked) => {
|
||||
if (checked)
|
||||
|
||||
@@ -50,7 +50,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
id: positionText
|
||||
text: qsTr("Dock Position")
|
||||
text: I18n.tr("Dock Position")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -125,14 +125,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Auto-hide Dock")
|
||||
text: I18n.tr("Auto-hide Dock")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Hide the dock when not in use and reveal it when hovering near the dock area")
|
||||
text: I18n.tr("Hide the dock when not in use and reveal it when hovering near the dock area")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -176,14 +176,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Show Dock")
|
||||
text: I18n.tr("Show Dock")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen")
|
||||
text: I18n.tr("Display a dock with pinned and running applications that can be positioned at the top, bottom, left, or right edge of the screen")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -229,14 +229,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Show on Overview")
|
||||
text: I18n.tr("Show on Overview")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Always show the dock when niri's overview is open"
|
||||
text: I18n.tr("Always show the dock when niri's overview is open")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -294,14 +294,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Group by App")
|
||||
text: I18n.tr("Group by App")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Group multiple windows of the same app together with a window count indicator")
|
||||
text: I18n.tr("Group multiple windows of the same app together with a window count indicator")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -360,7 +360,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Spacing")
|
||||
text: I18n.tr("Spacing")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -373,7 +373,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Padding")
|
||||
text: I18n.tr("Padding")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -401,7 +401,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Height to Edge Gap (Exclusive Zone)")
|
||||
text: I18n.tr("Height to Edge Gap (Exclusive Zone)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -464,7 +464,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Dock Transparency")
|
||||
text: I18n.tr("Dock Transparency")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user