mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -717,8 +710,8 @@ Singleton {
|
||||
if (typeof SettingsData === "undefined") return ""
|
||||
const colorOverride = SettingsData.launcherLogoColorOverride
|
||||
if (!colorOverride || colorOverride === "") return ""
|
||||
if (colorOverride === "primary") return Theme.primary
|
||||
if (colorOverride === "surface") return Theme.surfaceText
|
||||
if (colorOverride === "primary") return primary
|
||||
if (colorOverride === "surface") return surfaceText
|
||||
return colorOverride
|
||||
}
|
||||
|
||||
@@ -728,19 +721,18 @@ Singleton {
|
||||
const colorOverride = SettingsData.launcherLogoColorOverride
|
||||
if (!colorOverride || colorOverride === "") return ""
|
||||
|
||||
let baseColor = colorOverride
|
||||
if (colorOverride === "primary") baseColor = Theme.primary
|
||||
if (colorOverride === "surface") baseColor = Theme.surfaceText
|
||||
if (colorOverride === "primary") return primary
|
||||
if (colorOverride === "surface") return surfaceText
|
||||
|
||||
if (!SettingsData.launcherLogoColorInvertOnMode) {
|
||||
return baseColor
|
||||
return colorOverride
|
||||
}
|
||||
|
||||
if (typeof SessionData !== "undefined" && SessionData.isLightMode) {
|
||||
return invertHex(baseColor)
|
||||
if (isLightMode) {
|
||||
return invertHex(colorOverride)
|
||||
}
|
||||
|
||||
return baseColor
|
||||
return colorOverride
|
||||
}
|
||||
|
||||
|
||||
@@ -906,7 +898,6 @@ Singleton {
|
||||
const colorsText = dynamicColorsFileView.text()
|
||||
if (colorsText) {
|
||||
root.matugenColors = JSON.parse(colorsText)
|
||||
root.colorUpdateTrigger++
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.clearWallpaperError()
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ Item {
|
||||
delegate: DankSlideout {
|
||||
id: notepadSlideout
|
||||
modelData: item
|
||||
title: qsTr("Notepad")
|
||||
title: I18n.tr("Notepad")
|
||||
slideoutWidth: 480
|
||||
expandable: true
|
||||
expandedWidthValue: 960
|
||||
|
||||
@@ -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,6 @@ Item {
|
||||
leftIconName: "search"
|
||||
showClearButton: true
|
||||
focus: true
|
||||
ignoreLeftRightKeys: true
|
||||
keyForwardTargets: [modal.modalFocusScope]
|
||||
onTextChanged: {
|
||||
modal.searchText = text
|
||||
@@ -116,7 +115,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
@@ -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,7 +19,7 @@ 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
|
||||
@@ -51,7 +51,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 +79,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 +115,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 +151,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 +187,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
|
||||
|
||||
@@ -221,14 +221,23 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Lock before suspend")
|
||||
text: I18n.tr("Enable loginctl lock integration")
|
||||
description: "Bind lock screen to dbus signals from loginctl. Disable if using an external lock screen."
|
||||
checked: SessionData.loginctlLockIntegration
|
||||
onToggled: checked => 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: SessionData.loginctlLockIntegration
|
||||
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
|
||||
|
||||
@@ -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,40 @@ 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 & Date"),
|
||||
"icon": "schedule"
|
||||
}, {
|
||||
"text": "Weather",
|
||||
"text": I18n.tr("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",
|
||||
"text": I18n.tr("Power"),
|
||||
"icon": "power_settings_new"
|
||||
}, {
|
||||
"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,7 @@ Item {
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
enabled: parentModal ? parentModal.spotlightOpen : true
|
||||
placeholderText: ""
|
||||
ignoreLeftRightKeys: true
|
||||
ignoreLeftRightKeys: appLauncher.viewMode !== "list"
|
||||
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
|
||||
@@ -105,10 +105,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
|
||||
@@ -248,7 +248,7 @@ Popup {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch")
|
||||
text: I18n.tr("Launch")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -308,7 +308,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
|
||||
|
||||
@@ -100,7 +100,7 @@ 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
|
||||
@@ -269,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
|
||||
@@ -297,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
|
||||
@@ -329,7 +329,7 @@ DankModal {
|
||||
id: connectText
|
||||
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Connect")
|
||||
text: I18n.tr("Connect")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.background
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -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 = ""
|
||||
@@ -166,11 +166,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 +175,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 +216,7 @@ DankPopout {
|
||||
showClearButton: true
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
enabled: appDrawerPopout.shouldBeVisible
|
||||
ignoreLeftRightKeys: true
|
||||
ignoreLeftRightKeys: appLauncher.viewMode !== "list"
|
||||
keyForwardTargets: [keyHandler]
|
||||
onTextEdited: {
|
||||
appLauncher.searchQuery = text
|
||||
@@ -684,7 +677,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 +750,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
|
||||
@@ -891,7 +884,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch")
|
||||
text: I18n.tr("Launch")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -951,7 +944,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)
|
||||
|
||||
@@ -87,7 +87,7 @@ PluginComponent {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Disconnect")
|
||||
text: I18n.tr("Disconnect")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -138,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
|
||||
|
||||
@@ -183,11 +183,11 @@ Column {
|
||||
height: 60
|
||||
primaryMessage: {
|
||||
if (!DMSService.dmsAvailable) {
|
||||
return qsTr("DMS_SOCKET not available")
|
||||
return I18n.tr("DMS_SOCKET not available")
|
||||
}
|
||||
return qsTr("NM not supported")
|
||||
return I18n.tr("NM not supported")
|
||||
}
|
||||
secondaryMessage: qsTr("update dms for NM integration.")
|
||||
secondaryMessage: I18n.tr("update dms for NM integration.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -41,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
|
||||
@@ -148,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
|
||||
@@ -166,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
|
||||
@@ -396,7 +396,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
MenuItem {
|
||||
text: qsTr("Network Info")
|
||||
text: I18n.tr("Network Info")
|
||||
height: 32
|
||||
|
||||
contentItem: StyledText {
|
||||
@@ -419,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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -100,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
|
||||
@@ -210,7 +210,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Disconnect")
|
||||
text: I18n.tr("Disconnect")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -266,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -448,7 +448,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Back")
|
||||
text: I18n.tr("Back")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -322,6 +323,8 @@ Item {
|
||||
TextInput {
|
||||
id: inputField
|
||||
|
||||
property bool syncingFromState: false
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: lockIcon.width + Theme.spacingM * 2
|
||||
anchors.rightMargin: {
|
||||
@@ -329,6 +332,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 +344,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,13 +362,17 @@ 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
|
||||
syncingFromState = false
|
||||
if (isPrimaryScreen)
|
||||
forceActiveFocus()
|
||||
}
|
||||
@@ -371,12 +382,18 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
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 +430,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 +458,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 +467,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 +584,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Switch User")
|
||||
text: I18n.tr("Switch User")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -1256,7 +1291,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"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1325,7 +1360,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Cancel")
|
||||
text: I18n.tr("Cancel")
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
}
|
||||
|
||||
@@ -18,34 +18,43 @@ The easiest thing is to run `dms greeter install` or `dms` for interactive insta
|
||||
|
||||
### 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 770 /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 +75,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 +118,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
|
||||
@@ -8,81 +8,54 @@ import qs.Services
|
||||
Item {
|
||||
id: root
|
||||
|
||||
function activate() {
|
||||
loader.activeAsync = true
|
||||
}
|
||||
property string sharedPasswordBuffer: ""
|
||||
property bool shouldLock: false
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SessionService.loginctlAvailable || SessionService.sessionPath) {
|
||||
if (SessionService.locked || SessionService.lockedHint) {
|
||||
console.log("Lock: Session locked on startup")
|
||||
loader.activeAsync = true
|
||||
}
|
||||
}
|
||||
IdleService.lockComponent = root
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: IdleService
|
||||
function onLockRequested() {
|
||||
console.log("Lock: Received lock request from IdleService")
|
||||
SessionService.lockSession()
|
||||
}
|
||||
function activate() {
|
||||
shouldLock = true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
|
||||
function onSessionLocked() {
|
||||
console.log("Lock: Lock signal received -> show lock")
|
||||
loader.activeAsync = true
|
||||
shouldLock = true
|
||||
}
|
||||
|
||||
function onSessionUnlocked() {
|
||||
console.log("Lock: Unlock signal received -> hide lock")
|
||||
loader.active = false
|
||||
}
|
||||
|
||||
function onLoginctlStateChanged() {
|
||||
if (SessionService.lockedHint && !loader.active) {
|
||||
console.log("Lock: LockedHint=true -> show lock")
|
||||
loader.activeAsync = true
|
||||
} else if (!SessionService.locked && !SessionService.lockedHint && loader.active) {
|
||||
console.log("Lock: LockedHint=false -> hide lock")
|
||||
loader.active = false
|
||||
}
|
||||
}
|
||||
|
||||
function onPrepareForSleep() {
|
||||
if (SessionService.preparingForSleep && SessionData.lockBeforeSuspend) {
|
||||
console.log("Lock: PrepareForSleep -> lock before suspend")
|
||||
loader.activeAsync = true
|
||||
}
|
||||
shouldLock = false
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: loader
|
||||
Connections {
|
||||
target: IdleService
|
||||
|
||||
WlSessionLock {
|
||||
id: sessionLock
|
||||
function onLockRequested() {
|
||||
shouldLock = true
|
||||
}
|
||||
}
|
||||
|
||||
property bool unlocked: false
|
||||
property string sharedPasswordBuffer: ""
|
||||
WlSessionLock {
|
||||
id: sessionLock
|
||||
|
||||
locked: true
|
||||
locked: root.shouldLock
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,17 +69,15 @@ Item {
|
||||
target: "lock"
|
||||
|
||||
function lock() {
|
||||
console.log("Lock screen requested via IPC")
|
||||
SessionService.lockSession()
|
||||
shouldLock = true
|
||||
}
|
||||
|
||||
function demo() {
|
||||
console.log("Lock screen DEMO mode requested via IPC")
|
||||
demoWindow.showDemo()
|
||||
}
|
||||
|
||||
function isLocked(): bool {
|
||||
return SessionService.locked || loader.active
|
||||
return sessionLock.locked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +609,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
|
||||
@@ -1244,7 +1244,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Cancel")
|
||||
text: I18n.tr("Cancel")
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -537,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
|
||||
@@ -630,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
|
||||
@@ -476,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
|
||||
|
||||
@@ -17,7 +17,14 @@ Item {
|
||||
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()
|
||||
@@ -98,7 +105,7 @@ Item {
|
||||
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: qsTr("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) {
|
||||
|
||||
@@ -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
|
||||
@@ -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 (Qt Modeling Language)")
|
||||
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
|
||||
@@ -943,7 +943,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Edge Spacing (0 = edge-to-edge)"
|
||||
text: I18n.tr("Edge Spacing (0 = edge-to-edge)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -971,7 +971,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Exclusive Zone Offset")
|
||||
text: I18n.tr("Exclusive Zone Offset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -999,7 +999,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Size")
|
||||
text: I18n.tr("Size")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -1025,7 +1025,7 @@ Item {
|
||||
|
||||
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 +1036,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 +1047,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 => {
|
||||
@@ -1058,7 +1058,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Border")
|
||||
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 => {
|
||||
@@ -1088,14 +1088,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 +1190,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 +1228,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Reset")
|
||||
text: I18n.tr("Reset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1270,7 +1270,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 +1372,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
|
||||
|
||||
@@ -108,14 +108,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 +131,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 +273,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 +288,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
|
||||
|
||||
@@ -13,7 +13,7 @@ Item {
|
||||
|
||||
FileBrowserModal {
|
||||
id: logoFileBrowser
|
||||
browserTitle: qsTr("Select Launcher Logo")
|
||||
browserTitle: I18n.tr("Select Launcher Logo")
|
||||
browserIcon: "image"
|
||||
browserType: "generic"
|
||||
filterExtensions: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"]
|
||||
@@ -62,7 +62,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launcher Button Logo")
|
||||
text: I18n.tr("Launcher Button Logo")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -72,7 +72,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: qsTr("Choose the logo displayed on the launcher button in DankBar")
|
||||
text: I18n.tr("Choose the logo displayed on the launcher button in DankBar")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -86,12 +86,12 @@ Item {
|
||||
id: logoModeGroup
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
model: {
|
||||
const modes = [qsTr("Apps Icon"), qsTr("OS Logo")]
|
||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo")]
|
||||
if (CompositorService.isNiri || CompositorService.isHyprland) {
|
||||
const compositorName = CompositorService.isNiri ? "niri" : "Hyprland"
|
||||
modes.push(compositorName)
|
||||
}
|
||||
modes.push(qsTr("Custom"))
|
||||
modes.push(I18n.tr("Custom"))
|
||||
return modes
|
||||
}
|
||||
currentIndex: {
|
||||
@@ -149,7 +149,7 @@ Item {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: SettingsData.launcherLogoCustomPath || qsTr("Select an image file...")
|
||||
text: SettingsData.launcherLogoCustomPath || I18n.tr("Select an image file...")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: SettingsData.launcherLogoCustomPath ? Theme.surfaceText : Theme.outlineButton
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
@@ -184,7 +184,7 @@ Item {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Color Override")
|
||||
text: I18n.tr("Color Override")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -197,7 +197,7 @@ Item {
|
||||
|
||||
DankButtonGroup {
|
||||
id: colorModeGroup
|
||||
model: [qsTr("Default"), qsTr("Primary"), qsTr("Surface"), qsTr("Custom")]
|
||||
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
||||
currentIndex: {
|
||||
const override = SettingsData.launcherLogoColorOverride
|
||||
if (override === "") return 0
|
||||
@@ -248,7 +248,7 @@ Item {
|
||||
onClicked: {
|
||||
if (PopoutService.colorPickerModal) {
|
||||
PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride
|
||||
PopoutService.colorPickerModal.pickerTitle = qsTr("Choose Launcher Logo Color")
|
||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color")
|
||||
PopoutService.colorPickerModal.onColorSelectedCallback = function(selectedColor) {
|
||||
SettingsData.setLauncherLogoColorOverride(selectedColor)
|
||||
}
|
||||
@@ -270,7 +270,7 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Size Offset")
|
||||
text: I18n.tr("Size Offset")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -321,7 +321,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Brightness")
|
||||
text: I18n.tr("Brightness")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -350,7 +350,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Contrast")
|
||||
text: I18n.tr("Contrast")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -379,7 +379,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Invert on mode change")
|
||||
text: I18n.tr("Invert on mode change")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -430,7 +430,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Launch Prefix")
|
||||
text: I18n.tr("Launch Prefix")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -440,7 +440,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers."
|
||||
text: I18n.tr("Add a custom prefix to all application launches. This can be used for things like 'uwsm-app', 'systemd-run', or other command wrappers.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -510,7 +510,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Recently Used Apps")
|
||||
text: I18n.tr("Recently Used Apps")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -540,7 +540,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: qsTr("Apps are ordered by usage frequency, then last used, then alphabetically.")
|
||||
text: I18n.tr("Apps are ordered by usage frequency, then last used, then alphabetically.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
@@ -104,7 +104,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Wallpaper")
|
||||
text: I18n.tr("Wallpaper")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -438,14 +438,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Per-Mode Wallpapers")
|
||||
text: I18n.tr("Per-Mode Wallpapers")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Set different wallpapers for light and dark mode")
|
||||
text: I18n.tr("Set different wallpapers for light and dark mode")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
@@ -495,14 +495,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Per-Monitor Wallpapers")
|
||||
text: I18n.tr("Per-Monitor Wallpapers")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Set different wallpapers for each connected monitor")
|
||||
text: I18n.tr("Set different wallpapers for each connected monitor")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
@@ -527,7 +527,7 @@ Item {
|
||||
leftPadding: Theme.iconSize + Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Monitor Selection:")
|
||||
text: I18n.tr("Monitor Selection:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -536,8 +536,8 @@ Item {
|
||||
DankDropdown {
|
||||
id: monitorDropdown
|
||||
|
||||
text: qsTr("Monitor")
|
||||
description: "Select monitor to configure wallpaper"
|
||||
text: I18n.tr("Monitor")
|
||||
description: I18n.tr("Select monitor to configure wallpaper")
|
||||
currentValue: selectedMonitorName || "No monitors"
|
||||
options: {
|
||||
var screenNames = []
|
||||
@@ -584,14 +584,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Automatic Cycling")
|
||||
text: I18n.tr("Automatic Cycling")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Automatically cycle through wallpapers in the same folder")
|
||||
text: I18n.tr("Automatically cycle through wallpapers in the same folder")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
@@ -633,7 +633,7 @@ Item {
|
||||
width: parent.width - parent.leftPadding
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Mode:")
|
||||
text: I18n.tr("Mode:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -700,8 +700,8 @@ Item {
|
||||
return SessionData.wallpaperCyclingMode === "interval"
|
||||
}
|
||||
}
|
||||
text: qsTr("Interval")
|
||||
description: "How often to change wallpaper"
|
||||
text: I18n.tr("Interval")
|
||||
description: I18n.tr("How often to change wallpaper")
|
||||
options: intervalOptions
|
||||
currentValue: {
|
||||
var currentSeconds
|
||||
@@ -755,7 +755,7 @@ Item {
|
||||
width: parent.width - parent.leftPadding
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Daily at:")
|
||||
text: I18n.tr("Daily at:")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -830,7 +830,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("24-hour format")
|
||||
text: I18n.tr("24-hour format")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -847,8 +847,8 @@ Item {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Transition Effect")
|
||||
description: "Visual effect used when wallpaper changes"
|
||||
text: I18n.tr("Transition Effect")
|
||||
description: I18n.tr("Visual effect used when wallpaper changes")
|
||||
currentValue: {
|
||||
if (SessionData.wallpaperTransition === "random") return "Random"
|
||||
return SessionData.wallpaperTransition.charAt(0).toUpperCase() + SessionData.wallpaperTransition.slice(1)
|
||||
@@ -866,14 +866,14 @@ Item {
|
||||
visible: SessionData.wallpaperTransition === "random"
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Include Transitions")
|
||||
text: I18n.tr("Include Transitions")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Select which transitions to include in randomization")
|
||||
text: I18n.tr("Select which transitions to include in randomization")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -938,14 +938,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Dynamic Theming")
|
||||
text: I18n.tr("Dynamic Theming")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Automatically extract colors from wallpaper")
|
||||
text: I18n.tr("Automatically extract colors from wallpaper")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -970,7 +970,7 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
id: personalizationMatugenPaletteDropdown
|
||||
text: qsTr("Matugen Palette")
|
||||
text: I18n.tr("Matugen Palette")
|
||||
description: "Select the palette algorithm used for wallpaper-based colors"
|
||||
options: Theme.availableMatugenSchemes.map(function (option) { return option.label })
|
||||
currentValue: Theme.getMatugenScheme(SettingsData.matugenScheme).label
|
||||
@@ -999,7 +999,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("matugen not detected - dynamic theming unavailable")
|
||||
text: I18n.tr("matugen not detected - dynamic theming unavailable")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.error
|
||||
visible: ToastService.wallpaperErrorStatus === "matugen_missing"
|
||||
@@ -1037,7 +1037,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Display Settings")
|
||||
text: I18n.tr("Display Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1047,8 +1047,8 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Light Mode")
|
||||
description: "Use light theme instead of dark theme"
|
||||
text: I18n.tr("Light Mode")
|
||||
description: I18n.tr("Use light theme instead of dark theme")
|
||||
checked: SessionData.isLightMode
|
||||
onToggleCompleted: checked => {
|
||||
Theme.screenTransition()
|
||||
@@ -1068,7 +1068,7 @@ Item {
|
||||
id: nightModeToggle
|
||||
|
||||
width: parent.width
|
||||
text: qsTr("Night Mode")
|
||||
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 => {
|
||||
@@ -1085,8 +1085,8 @@ Item {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Temperature")
|
||||
description: "Color temperature for night mode"
|
||||
text: I18n.tr("Temperature")
|
||||
description: I18n.tr("Color temperature for night mode")
|
||||
currentValue: SessionData.nightModeTemperature + "K"
|
||||
options: {
|
||||
var temps = []
|
||||
@@ -1104,7 +1104,7 @@ Item {
|
||||
DankToggle {
|
||||
id: automaticToggle
|
||||
width: parent.width
|
||||
text: qsTr("Automatic Control")
|
||||
text: I18n.tr("Automatic Control")
|
||||
description: "Only adjust gamma based on time or location rules."
|
||||
checked: SessionData.nightModeAutoEnabled
|
||||
onToggled: checked => {
|
||||
@@ -1187,7 +1187,7 @@ Item {
|
||||
leftPadding: 45
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Hour")
|
||||
text: I18n.tr("Hour")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: 50
|
||||
@@ -1196,7 +1196,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Minute")
|
||||
text: I18n.tr("Minute")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: 50
|
||||
@@ -1212,7 +1212,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
id: startLabel
|
||||
text: qsTr("Start")
|
||||
text: I18n.tr("Start")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
width: 50
|
||||
@@ -1260,7 +1260,7 @@ Item {
|
||||
height: 32
|
||||
|
||||
StyledText {
|
||||
text: qsTr("End")
|
||||
text: I18n.tr("End")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
width: startLabel.width
|
||||
@@ -1311,7 +1311,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Auto-location")
|
||||
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
|
||||
@@ -1327,7 +1327,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Manual Coordinates")
|
||||
text: I18n.tr("Manual Coordinates")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
visible: SessionData.nightModeLocationProvider !== "geoclue2"
|
||||
@@ -1341,7 +1341,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Latitude")
|
||||
text: I18n.tr("Latitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -1364,7 +1364,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Longitude")
|
||||
text: I18n.tr("Longitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -1385,7 +1385,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Uses sunrise/sunset times to automatically adjust night mode based on your location."
|
||||
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
|
||||
@@ -1424,7 +1424,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Notification Popups")
|
||||
text: I18n.tr("Notification Popups")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1433,8 +1433,8 @@ Item {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Popup Position")
|
||||
description: "Choose where notification popups appear on screen"
|
||||
text: I18n.tr("Popup Position")
|
||||
description: I18n.tr("Choose where notification popups appear on screen")
|
||||
currentValue: {
|
||||
if (SettingsData.notificationPopupPosition === -1) {
|
||||
return "Top Center"
|
||||
@@ -1484,8 +1484,8 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Always Show OSD Percentage")
|
||||
description: "Display volume and brightness percentage values by default in OSD popups"
|
||||
text: I18n.tr("Always Show OSD Percentage")
|
||||
description: I18n.tr("Display volume and brightness percentage values by default in OSD popups")
|
||||
checked: SettingsData.osdAlwaysShowValue
|
||||
onToggled: checked => {
|
||||
SettingsData.setOsdAlwaysShowValue(checked)
|
||||
@@ -1522,7 +1522,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Font Settings")
|
||||
text: I18n.tr("Font Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1531,8 +1531,8 @@ Item {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Font Family")
|
||||
description: "Select system font family"
|
||||
text: I18n.tr("Font Family")
|
||||
description: I18n.tr("Select system font family")
|
||||
currentValue: {
|
||||
if (SettingsData.fontFamily === SettingsData.defaultFontFamily)
|
||||
return "Default"
|
||||
@@ -1552,8 +1552,8 @@ Item {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Font Weight")
|
||||
description: "Select font weight"
|
||||
text: I18n.tr("Font Weight")
|
||||
description: I18n.tr("Select font weight")
|
||||
currentValue: {
|
||||
switch (SettingsData.fontWeight) {
|
||||
case Font.Thin:
|
||||
@@ -1618,8 +1618,8 @@ Item {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
text: qsTr("Monospace Font")
|
||||
description: "Select monospace font for process list and technical displays"
|
||||
text: I18n.tr("Monospace Font")
|
||||
description: I18n.tr("Select monospace font for process list and technical displays")
|
||||
currentValue: {
|
||||
if (SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily)
|
||||
return "Default"
|
||||
@@ -1653,14 +1653,14 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Font Scale")
|
||||
text: I18n.tr("Font Scale")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Scale all font sizes")
|
||||
text: I18n.tr("Scale all font sizes")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
@@ -1752,7 +1752,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Animations")
|
||||
text: I18n.tr("Animations")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1765,14 +1765,14 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Animation Speed")
|
||||
text: I18n.tr("Animation Speed")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Control the speed of animations throughout the interface")
|
||||
text: I18n.tr("Control the speed of animations throughout the interface")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -1823,7 +1823,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Lock Screen")
|
||||
text: I18n.tr("Lock Screen")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1833,7 +1833,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Show Power Actions")
|
||||
text: I18n.tr("Show Power Actions")
|
||||
description: "Show power, restart, and logout buttons on the lock screen"
|
||||
checked: SettingsData.lockScreenShowPowerActions
|
||||
onToggled: checked => {
|
||||
|
||||
@@ -58,14 +58,14 @@ FocusScope {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Plugin Management")
|
||||
text: I18n.tr("Plugin Management")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Manage and configure plugins for extending DMS functionality")
|
||||
text: I18n.tr("Manage and configure plugins for extending DMS functionality")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -98,7 +98,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("DMS Plugin Manager Unavailable")
|
||||
text: I18n.tr("DMS Plugin Manager Unavailable")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning
|
||||
font.weight: Font.Medium
|
||||
@@ -107,7 +107,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.")
|
||||
text: I18n.tr("The DMS_SOCKET environment variable is not set or the socket is unavailable. Automated plugin management requires the DMS_SOCKET.")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -121,7 +121,7 @@ FocusScope {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankButton {
|
||||
text: qsTr("Browse")
|
||||
text: I18n.tr("Browse")
|
||||
iconName: "store"
|
||||
enabled: DMSService.dmsAvailable
|
||||
onClicked: {
|
||||
@@ -130,7 +130,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
DankButton {
|
||||
text: qsTr("Scan")
|
||||
text: I18n.tr("Scan")
|
||||
iconName: "refresh"
|
||||
onClicked: {
|
||||
pluginsTab.isRefreshingPlugins = true
|
||||
@@ -143,7 +143,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
DankButton {
|
||||
text: qsTr("Create Dir")
|
||||
text: I18n.tr("Create Dir")
|
||||
iconName: "create_new_folder"
|
||||
onClicked: {
|
||||
PluginService.createPluginDirectory()
|
||||
@@ -169,7 +169,7 @@ FocusScope {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Plugin Directory")
|
||||
text: I18n.tr("Plugin Directory")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -183,7 +183,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Place plugin directories here. Each plugin should have a plugin.json manifest file.")
|
||||
text: I18n.tr("Place plugin directories here. Each plugin should have a plugin.json manifest file.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -207,7 +207,7 @@ FocusScope {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Available Plugins")
|
||||
text: I18n.tr("Available Plugins")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -563,7 +563,7 @@ FocusScope {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "No plugins found.\nPlace plugins in " + PluginService.pluginDirectory
|
||||
text: I18n.tr("No plugins found.") + "\n" + I18n.tr("Place plugins in") + " " + PluginService.pluginDirectory
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
@@ -600,6 +600,9 @@ FocusScope {
|
||||
pluginsTab.expandedPluginId = ""
|
||||
}
|
||||
}
|
||||
function onPluginListUpdated() {
|
||||
refreshPluginList()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -782,7 +785,7 @@ FocusScope {
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: qsTr("Browse Plugins")
|
||||
text: I18n.tr("Browse Plugins")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -831,7 +834,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Install plugins from the DMS plugin registry")
|
||||
text: I18n.tr("Install plugins from the DMS plugin registry")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
width: parent.width
|
||||
@@ -853,7 +856,7 @@ FocusScope {
|
||||
showClearButton: true
|
||||
textColor: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
placeholderText: qsTr("Search plugins...")
|
||||
placeholderText: I18n.tr("Search plugins...")
|
||||
text: pluginBrowserModal.searchQuery
|
||||
focus: true
|
||||
ignoreLeftRightKeys: true
|
||||
@@ -889,7 +892,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Loading plugins...")
|
||||
text: I18n.tr("Loading plugins...")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -969,7 +972,7 @@ FocusScope {
|
||||
StyledText {
|
||||
id: firstPartyText
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("official")
|
||||
text: I18n.tr("official")
|
||||
font.pixelSize: Theme.fontSizeSmall - 2
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -989,7 +992,7 @@ FocusScope {
|
||||
StyledText {
|
||||
id: thirdPartyText
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("3rd party")
|
||||
text: I18n.tr("3rd party")
|
||||
font.pixelSize: Theme.fontSizeSmall - 2
|
||||
color: Theme.warning
|
||||
font.weight: Font.Medium
|
||||
@@ -1113,7 +1116,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("No plugins found")
|
||||
text: I18n.tr("No plugins found")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -1162,7 +1165,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Third-Party Plugin Warning")
|
||||
text: I18n.tr("Third-Party Plugin Warning")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1172,7 +1175,7 @@ FocusScope {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk."
|
||||
text: I18n.tr("Third-party plugins are created by the community and are not officially supported by DankMaterialShell.\n\nThese plugins may pose security and privacy risks - install at your own risk.")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -1183,19 +1186,19 @@ FocusScope {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• Plugins may contain bugs or security issues")
|
||||
text: I18n.tr("• Plugins may contain bugs or security issues")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• Review code before installation when possible")
|
||||
text: I18n.tr("• Review code before installation when possible")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• Install only from trusted sources")
|
||||
text: I18n.tr("• Install only from trusted sources")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -1211,13 +1214,13 @@ FocusScope {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankButton {
|
||||
text: qsTr("Cancel")
|
||||
text: I18n.tr("Cancel")
|
||||
iconName: "close"
|
||||
onClicked: thirdPartyConfirmModal.close()
|
||||
}
|
||||
|
||||
DankButton {
|
||||
text: qsTr("I Understand")
|
||||
text: I18n.tr("I Understand")
|
||||
iconName: "check"
|
||||
onClicked: {
|
||||
SessionData.setShowThirdPartyPlugins(true)
|
||||
|
||||
@@ -130,7 +130,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Theme Color")
|
||||
text: I18n.tr("Theme Color")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -651,7 +651,7 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
id: matugenPaletteDropdown
|
||||
text: qsTr("Matugen Palette")
|
||||
text: I18n.tr("Matugen Palette")
|
||||
description: "Select the palette algorithm used for wallpaper-based colors"
|
||||
options: Theme.availableMatugenSchemes.map(function (option) { return option.label })
|
||||
currentValue: Theme.getMatugenScheme(SettingsData.matugenScheme).label
|
||||
@@ -756,7 +756,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Widget Styling")
|
||||
text: I18n.tr("Widget Styling")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -769,7 +769,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Dank Bar Transparency")
|
||||
text: I18n.tr("Dank Bar Transparency")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -803,7 +803,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
id: transparencyLabel
|
||||
text: qsTr("Dank Bar Widget Transparency")
|
||||
text: I18n.tr("Dank Bar Widget Transparency")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -867,7 +867,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Popup Transparency")
|
||||
text: I18n.tr("Popup Transparency")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -904,7 +904,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Corner Radius (0 = square corners)"
|
||||
text: I18n.tr("Corner Radius (0 = square corners)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -955,7 +955,7 @@ Item {
|
||||
StyledText {
|
||||
id: warningText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
text: "The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0)."
|
||||
text: I18n.tr("The below settings will modify your GTK and Qt settings. If you wish to preserve your current configurations, please back them up (qt5ct.conf|qt6ct.conf and ~/.config/gtk-3.0|gtk-4.0).")
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width - Theme.iconSizeSmall - Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -993,7 +993,7 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Icon Theme")
|
||||
text: I18n.tr("Icon Theme")
|
||||
description: "DankShell & System Icons\n(requires restart)"
|
||||
currentValue: SettingsData.iconTheme
|
||||
enableFuzzySearch: true
|
||||
@@ -1046,7 +1046,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("System App Theming")
|
||||
text: I18n.tr("System App Theming")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -1078,7 +1078,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Apply GTK Colors")
|
||||
text: I18n.tr("Apply GTK Colors")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -1114,7 +1114,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Apply Qt Colors")
|
||||
text: I18n.tr("Apply Qt Colors")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
|
||||
@@ -54,14 +54,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("24-Hour Format")
|
||||
text: I18n.tr("24-Hour Format")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Use 24-hour time format instead of 12-hour AM/PM"
|
||||
text: I18n.tr("Use 24-hour time format instead of 12-hour AM/PM")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -112,7 +112,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Date Format")
|
||||
text: I18n.tr("Date Format")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -122,7 +122,7 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
height: 50
|
||||
text: qsTr("Top Bar Format")
|
||||
text: I18n.tr("Top Bar Format")
|
||||
description: "Preview: " + (SettingsData.clockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) : new Date().toLocaleDateString(Qt.locale(), "ddd d"))
|
||||
currentValue: {
|
||||
if (!SettingsData.clockDateFormat || SettingsData.clockDateFormat.length === 0) {
|
||||
@@ -158,7 +158,7 @@ Item {
|
||||
return p.format
|
||||
=== SettingsData.clockDateFormat
|
||||
})
|
||||
return match ? match.label: qsTr("Custom: ") + SettingsData.clockDateFormat
|
||||
return match ? match.label: I18n.tr("Custom: ") + SettingsData.clockDateFormat
|
||||
}
|
||||
options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
|
||||
onValueChanged: value => {
|
||||
@@ -185,7 +185,7 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
height: 50
|
||||
text: qsTr("Lock Screen Format")
|
||||
text: I18n.tr("Lock Screen Format")
|
||||
description: "Preview: " + (SettingsData.lockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat) : new Date().toLocaleDateString(Qt.locale(), Locale.LongFormat))
|
||||
currentValue: {
|
||||
if (!SettingsData.lockDateFormat || SettingsData.lockDateFormat.length === 0) {
|
||||
@@ -221,7 +221,7 @@ Item {
|
||||
return p.format
|
||||
=== SettingsData.lockDateFormat
|
||||
})
|
||||
return match ? match.label: qsTr("Custom: ") + SettingsData.lockDateFormat
|
||||
return match ? match.label: I18n.tr("Custom: ") + SettingsData.lockDateFormat
|
||||
}
|
||||
options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
|
||||
onValueChanged: value => {
|
||||
@@ -251,7 +251,7 @@ Item {
|
||||
|
||||
width: parent.width
|
||||
visible: false
|
||||
placeholderText: qsTr("Enter custom top bar format (e.g., ddd MMM d)")
|
||||
placeholderText: I18n.tr("Enter custom top bar format (e.g., ddd MMM d)")
|
||||
text: SettingsData.clockDateFormat
|
||||
onTextChanged: {
|
||||
if (visible && text)
|
||||
@@ -264,7 +264,7 @@ Item {
|
||||
|
||||
width: parent.width
|
||||
visible: false
|
||||
placeholderText: qsTr("Enter custom lock screen format (e.g., dddd, MMMM d)")
|
||||
placeholderText: I18n.tr("Enter custom lock screen format (e.g., dddd, MMMM d)")
|
||||
text: SettingsData.lockDateFormat
|
||||
onTextChanged: {
|
||||
if (visible && text)
|
||||
@@ -289,7 +289,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Format Legend")
|
||||
text: I18n.tr("Format Legend")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Medium
|
||||
@@ -304,31 +304,31 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• d - Day (1-31)")
|
||||
text: I18n.tr("• d - Day (1-31)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• dd - Day (01-31)")
|
||||
text: I18n.tr("• dd - Day (01-31)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• ddd - Day name (Mon)")
|
||||
text: I18n.tr("• ddd - Day name (Mon)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• dddd - Day name (Monday)")
|
||||
text: I18n.tr("• dddd - Day name (Monday)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• M - Month (1-12)")
|
||||
text: I18n.tr("• M - Month (1-12)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -339,31 +339,31 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• MM - Month (01-12)")
|
||||
text: I18n.tr("• MM - Month (01-12)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• MMM - Month (Jan)")
|
||||
text: I18n.tr("• MMM - Month (Jan)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• MMMM - Month (January)")
|
||||
text: I18n.tr("• MMMM - Month (January)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• yy - Year (24)")
|
||||
text: I18n.tr("• yy - Year (24)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("• yyyy - Year (2024)")
|
||||
text: I18n.tr("• yyyy - Year (2024)")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
@@ -54,14 +54,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Enable Weather")
|
||||
text: I18n.tr("Enable Weather")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Show weather information in top bar and control center")
|
||||
text: I18n.tr("Show weather information in top bar and control center")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -120,14 +120,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Use Fahrenheit")
|
||||
text: I18n.tr("Use Fahrenheit")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Use Fahrenheit instead of Celsius for temperature")
|
||||
text: I18n.tr("Use Fahrenheit instead of Celsius for temperature")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -193,14 +193,14 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Auto Location")
|
||||
text: I18n.tr("Auto Location")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Automatically determine your location using your IP address")
|
||||
text: I18n.tr("Automatically determine your location using your IP address")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -233,7 +233,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Custom Location")
|
||||
text: I18n.tr("Custom Location")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -248,7 +248,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Latitude")
|
||||
text: I18n.tr("Latitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -299,7 +299,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Longitude")
|
||||
text: I18n.tr("Longitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
@@ -352,7 +352,7 @@ Item {
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Location Search")
|
||||
text: I18n.tr("Location Search")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
font.weight: Font.Medium
|
||||
@@ -362,7 +362,7 @@ Item {
|
||||
id: locationSearchInput
|
||||
width: parent.width
|
||||
currentLocation: ""
|
||||
placeholderText: qsTr("New York, NY")
|
||||
placeholderText: I18n.tr("New York, NY")
|
||||
keyNavigationBacktab: longitudeInput
|
||||
onLocationSelected: (displayName, coordinates) => {
|
||||
SettingsData.setWeatherLocation(displayName, coordinates)
|
||||
|
||||
@@ -165,10 +165,6 @@ DankModal {
|
||||
root.close()
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +199,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Add Widget to ") + root.targetSection + " Section"
|
||||
text: I18n.tr("Add Widget to ") + root.targetSection + " Section"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -212,7 +208,7 @@ DankModal {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Select a widget to add to the ") + root.targetSection.toLowerCase(
|
||||
text: I18n.tr("Select a widget to add to the ") + root.targetSection.toLowerCase(
|
||||
) + " section of the top bar. You can add multiple instances of the same widget if needed."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
|
||||
@@ -47,7 +47,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Workspace Settings")
|
||||
text: I18n.tr("Workspace Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -57,7 +57,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Workspace Index Numbers")
|
||||
text: I18n.tr("Workspace Index Numbers")
|
||||
description: "Show workspace index numbers in the top bar workspace switcher"
|
||||
checked: SettingsData.showWorkspaceIndex
|
||||
onToggled: checked => {
|
||||
@@ -68,7 +68,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Workspace Padding")
|
||||
text: I18n.tr("Workspace Padding")
|
||||
description: "Always show a minimum of 3 workspaces, even if fewer are available"
|
||||
checked: SettingsData.showWorkspacePadding
|
||||
onToggled: checked => {
|
||||
@@ -79,7 +79,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Show Workspace Apps")
|
||||
text: I18n.tr("Show Workspace Apps")
|
||||
description: "Display application icons in workspace indicators"
|
||||
checked: SettingsData.showWorkspaceApps
|
||||
onToggled: checked => {
|
||||
@@ -101,7 +101,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Max apps to show")
|
||||
text: I18n.tr("Max apps to show")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -132,7 +132,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Per-Monitor Workspaces")
|
||||
text: I18n.tr("Per-Monitor Workspaces")
|
||||
description: "Show only workspaces belonging to each specific monitor."
|
||||
checked: SettingsData.workspacesPerMonitor
|
||||
onToggled: checked => {
|
||||
@@ -170,7 +170,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Media Player Settings")
|
||||
text: I18n.tr("Media Player Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -180,7 +180,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Wave Progress Bars")
|
||||
text: I18n.tr("Wave Progress Bars")
|
||||
description: "Use animated wave progress bars for media playback"
|
||||
checked: SettingsData.waveProgressEnabled
|
||||
onToggled: checked => {
|
||||
@@ -218,7 +218,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Running Apps Settings")
|
||||
text: I18n.tr("Running Apps Settings")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -228,7 +228,7 @@ Item {
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: qsTr("Running Apps Only In Current Workspace")
|
||||
text: I18n.tr("Running Apps Only In Current Workspace")
|
||||
description: "Show only apps running in current workspace"
|
||||
checked: SettingsData.runningAppsCurrentWorkspace
|
||||
onToggled: checked => {
|
||||
@@ -268,7 +268,7 @@ Item {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Named Workspace Icons")
|
||||
text: I18n.tr("Named Workspace Icons")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -278,7 +278,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: qsTr("Configure icons for named workspaces. Icons take priority over numbers when both are enabled.")
|
||||
text: I18n.tr("Configure icons for named workspaces. Icons take priority over numbers when both are enabled.")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
@@ -480,7 +480,7 @@ Column {
|
||||
StyledText {
|
||||
id: tooltipText
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Compact Mode")
|
||||
text: I18n.tr("Compact Mode")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
@@ -667,7 +667,7 @@ Column {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Add Widget")
|
||||
text: I18n.tr("Add Widget")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.primary
|
||||
@@ -752,7 +752,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Network Icon")
|
||||
text: I18n.tr("Network Icon")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -805,7 +805,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Bluetooth Icon")
|
||||
text: I18n.tr("Bluetooth Icon")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
@@ -858,7 +858,7 @@ Column {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Audio Icon")
|
||||
text: I18n.tr("Audio Icon")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Normal
|
||||
|
||||
@@ -86,7 +86,7 @@ DankPopout {
|
||||
height: 40
|
||||
|
||||
StyledText {
|
||||
text: qsTr("System Updates")
|
||||
text: I18n.tr("System Updates")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -171,7 +171,7 @@ DankPopout {
|
||||
return "Failed to check for updates:\n" + SystemUpdateService.errorMessage;
|
||||
}
|
||||
if (!SystemUpdateService.helperAvailable) {
|
||||
return "No package manager found. Please install 'paru' or 'yay' to check for updates.";
|
||||
return "No package manager found. Please install 'paru' or 'yay' on Arch-based systems to check for updates.";
|
||||
}
|
||||
if (SystemUpdateService.isChecking) {
|
||||
return "Checking for updates...";
|
||||
@@ -282,7 +282,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Update All")
|
||||
text: I18n.tr("Update All")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.primary
|
||||
@@ -326,7 +326,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: qsTr("Close")
|
||||
text: I18n.tr("Close")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
|
||||
@@ -14,6 +14,7 @@ PanelWindow {
|
||||
property var modelData
|
||||
property bool shouldBeVisible: false
|
||||
property real frozenWidth: 0
|
||||
readonly property string copiedText: I18n.tr("Copied!")
|
||||
|
||||
Connections {
|
||||
target: ToastService
|
||||
@@ -280,7 +281,7 @@ PanelWindow {
|
||||
StyledText {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: qsTr("Copied!")
|
||||
text: root.copiedText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
10
README.md
10
README.md
@@ -661,6 +661,16 @@ cp -R ./PLUGINS/ExampleEmojiPlugin ~/.config/DankMaterialShell/plugins
|
||||
|
||||
**Only install plugins from TRUSTED sources.** Plugins execute QML and javascript at runtime, plugins from third parties should be reviewed before enabling them in dms.
|
||||
|
||||
### nixOS - via home-manager
|
||||
|
||||
Add the following to your home-manager config to install a plugin:
|
||||
|
||||
```nix
|
||||
programs.dankMaterialShell.plugins = {
|
||||
ExampleEmojiPlugin.src = "${inputs.dankMaterialShell}/PLUGINS/ExampleEmojiPlugin";
|
||||
};
|
||||
```
|
||||
|
||||
### Calendar Setup
|
||||
|
||||
Sync your caldev compatible calendar (Google, Office365, etc.) for dashboard integration:
|
||||
|
||||
@@ -152,30 +152,30 @@ Singleton {
|
||||
return []
|
||||
|
||||
const categoryMap = {
|
||||
"AudioVideo": qsTr("Media"),
|
||||
"Audio": qsTr("Media"),
|
||||
"Video": qsTr("Media"),
|
||||
"Development": qsTr("Development"),
|
||||
"TextEditor": qsTr("Development"),
|
||||
"IDE": qsTr("Development"),
|
||||
"Education": qsTr("Education"),
|
||||
"Game": qsTr("Games"),
|
||||
"Graphics": qsTr("Graphics"),
|
||||
"Photography": qsTr("Graphics"),
|
||||
"Network": qsTr("Internet"),
|
||||
"WebBrowser": qsTr("Internet"),
|
||||
"Email": qsTr("Internet"),
|
||||
"Office": qsTr("Office"),
|
||||
"WordProcessor": qsTr("Office"),
|
||||
"Spreadsheet": qsTr("Office"),
|
||||
"Presentation": qsTr("Office"),
|
||||
"Science": qsTr("Science"),
|
||||
"Settings": qsTr("Settings"),
|
||||
"System": qsTr("System"),
|
||||
"Utility": qsTr("Utilities"),
|
||||
"Accessories": qsTr("Utilities"),
|
||||
"FileManager": qsTr("Utilities"),
|
||||
"TerminalEmulator": qsTr("Utilities")
|
||||
"AudioVideo": I18n.tr("Media"),
|
||||
"Audio": I18n.tr("Media"),
|
||||
"Video": I18n.tr("Media"),
|
||||
"Development": I18n.tr("Development"),
|
||||
"TextEditor": I18n.tr("Development"),
|
||||
"IDE": I18n.tr("Development"),
|
||||
"Education": I18n.tr("Education"),
|
||||
"Game": I18n.tr("Games"),
|
||||
"Graphics": I18n.tr("Graphics"),
|
||||
"Photography": I18n.tr("Graphics"),
|
||||
"Network": I18n.tr("Internet"),
|
||||
"WebBrowser": I18n.tr("Internet"),
|
||||
"Email": I18n.tr("Internet"),
|
||||
"Office": I18n.tr("Office"),
|
||||
"WordProcessor": I18n.tr("Office"),
|
||||
"Spreadsheet": I18n.tr("Office"),
|
||||
"Presentation": I18n.tr("Office"),
|
||||
"Science": I18n.tr("Science"),
|
||||
"Settings": I18n.tr("Settings"),
|
||||
"System": I18n.tr("System"),
|
||||
"Utility": I18n.tr("Utilities"),
|
||||
"Accessories": I18n.tr("Utilities"),
|
||||
"FileManager": I18n.tr("Utilities"),
|
||||
"TerminalEmulator": I18n.tr("Utilities")
|
||||
}
|
||||
|
||||
const mappedCategories = new Set()
|
||||
@@ -206,7 +206,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function getAllCategories() {
|
||||
const categories = new Set([qsTr("All")])
|
||||
const categories = new Set([I18n.tr("All")])
|
||||
|
||||
for (const app of applications) {
|
||||
const appCategories = getCategoriesForApp(app)
|
||||
@@ -217,7 +217,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function getAppsInCategory(category) {
|
||||
if (category === qsTr("All")) {
|
||||
if (category === I18n.tr("All")) {
|
||||
return applications
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,15 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
function onPrepareForSleep() {
|
||||
if (SessionData.lockBeforeSuspend) {
|
||||
root.lockRequested()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!idleMonitorAvailable) {
|
||||
console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell.")
|
||||
|
||||
@@ -76,14 +76,15 @@ Singleton {
|
||||
signal networksUpdated
|
||||
signal connectionChanged
|
||||
|
||||
property var dmsService: null
|
||||
property bool subscriptionConnected: false
|
||||
|
||||
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
||||
|
||||
Component.onCompleted: {
|
||||
root.userPreference = SettingsData.networkPreference
|
||||
Qt.callLater(initializeDMSConnection)
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
|
||||
DankSocket {
|
||||
@@ -133,65 +134,43 @@ Singleton {
|
||||
console.log("NetworkManagerService: Sent network.subscribe request")
|
||||
}
|
||||
|
||||
function initializeDMSConnection() {
|
||||
try {
|
||||
console.log("NetworkManagerService: Initializing DMS connection...")
|
||||
dmsService = Qt.createQmlObject('import QtQuick; import qs.Services; QtObject { property var service: DMSService }', root)
|
||||
if (dmsService && dmsService.service) {
|
||||
console.log("NetworkManagerService: DMS service reference created")
|
||||
checkCapabilities()
|
||||
dmsService.service.connectionStateChanged.connect(onDMSConnectionStateChanged)
|
||||
dmsService.service.capabilitiesChanged.connect(onDMSCapabilitiesChanged)
|
||||
console.log("NetworkManagerService: Callbacks registered, isConnected:", dmsService.service.isConnected, "capabilities:", JSON.stringify(dmsService.service.capabilities))
|
||||
} else {
|
||||
console.warn("NetworkManagerService: Failed to get DMS service reference")
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("NetworkManagerService: Failed to initialize DMS connection:", e)
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: DMSService
|
||||
|
||||
function checkCapabilities() {
|
||||
if (dmsService && dmsService.service && dmsService.service.isConnected) {
|
||||
onDMSConnected()
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSConnectionStateChanged() {
|
||||
if (dmsService && dmsService.service && dmsService.service.isConnected) {
|
||||
onDMSConnected()
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSCapabilitiesChanged() {
|
||||
console.log("NetworkManagerService: onDMSCapabilitiesChanged called, capabilities:", dmsService ? JSON.stringify(dmsService.service.capabilities) : "no service")
|
||||
if (dmsService && dmsService.service && dmsService.service.capabilities.includes("network")) {
|
||||
console.log("NetworkManagerService: Network capability detected!")
|
||||
networkAvailable = true
|
||||
if (dmsService.service.isConnected && !stateInitialized) {
|
||||
console.log("NetworkManagerService: DMS is connected, fetching state and starting subscription socket...")
|
||||
stateInitialized = true
|
||||
getState()
|
||||
subscriptionSocket.connected = true
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected) {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSConnected() {
|
||||
console.log("NetworkManagerService: onDMSConnected called")
|
||||
if (dmsService && dmsService.service && dmsService.service.capabilities && dmsService.service.capabilities.length > 0) {
|
||||
console.log("NetworkManagerService: Capabilities:", JSON.stringify(dmsService.service.capabilities))
|
||||
networkAvailable = dmsService.service.capabilities.includes("network")
|
||||
console.log("NetworkManagerService: Network available:", networkAvailable)
|
||||
Connections {
|
||||
target: DMSService
|
||||
enabled: DMSService.isConnected
|
||||
|
||||
if (networkAvailable && !stateInitialized) {
|
||||
console.log("NetworkManagerService: Requesting network state and starting subscription socket...")
|
||||
stateInitialized = true
|
||||
getState()
|
||||
subscriptionSocket.connected = true
|
||||
}
|
||||
} else {
|
||||
console.log("NetworkManagerService: No capabilities yet or service not ready")
|
||||
function onCapabilitiesChanged() {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
|
||||
function checkDMSCapabilities() {
|
||||
if (!DMSService.isConnected) {
|
||||
return
|
||||
}
|
||||
|
||||
if (DMSService.capabilities.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
console.log("NetworkManagerService: Capabilities:", JSON.stringify(DMSService.capabilities))
|
||||
networkAvailable = DMSService.capabilities.includes("network")
|
||||
console.log("NetworkManagerService: Network available:", networkAvailable)
|
||||
|
||||
if (networkAvailable && !stateInitialized) {
|
||||
console.log("NetworkManagerService: Requesting network state and starting subscription socket...")
|
||||
stateInitialized = true
|
||||
getState()
|
||||
subscriptionSocket.connected = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,9 +191,9 @@ Singleton {
|
||||
property bool initialStateFetched: false
|
||||
|
||||
function getState() {
|
||||
if (!networkAvailable || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable) return
|
||||
|
||||
dmsService.service.sendRequest("network.getState", null, response => {
|
||||
DMSService.sendRequest("network.getState", null, response => {
|
||||
if (response.result) {
|
||||
updateState(response.result)
|
||||
if (!initialStateFetched && response.result.wifiEnabled && (!response.result.wifiNetworks || response.result.wifiNetworks.length === 0)) {
|
||||
@@ -277,11 +256,11 @@ Singleton {
|
||||
}
|
||||
|
||||
function scanWifi() {
|
||||
if (!networkAvailable || isScanning || !wifiEnabled || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable || isScanning || !wifiEnabled) return
|
||||
|
||||
console.log("NetworkManagerService: Starting WiFi scan...")
|
||||
isScanning = true
|
||||
dmsService.service.sendRequest("network.wifi.scan", null, response => {
|
||||
DMSService.sendRequest("network.wifi.scan", null, response => {
|
||||
isScanning = false
|
||||
if (response.error) {
|
||||
console.warn("NetworkManagerService: WiFi scan failed:", response.error)
|
||||
@@ -297,7 +276,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function connectToWifi(ssid, password = "", username = "") {
|
||||
if (!networkAvailable || isConnecting || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable || isConnecting) return
|
||||
|
||||
isConnecting = true
|
||||
connectingSSID = ssid
|
||||
@@ -308,7 +287,7 @@ Singleton {
|
||||
if (password) params.password = password
|
||||
if (username) params.username = username
|
||||
|
||||
dmsService.service.sendRequest("network.wifi.connect", params, response => {
|
||||
DMSService.sendRequest("network.wifi.connect", params, response => {
|
||||
if (response.error) {
|
||||
connectionError = response.error
|
||||
lastConnectionError = response.error
|
||||
@@ -338,9 +317,9 @@ Singleton {
|
||||
}
|
||||
|
||||
function disconnectWifi() {
|
||||
if (!networkAvailable || !wifiInterface || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable || !wifiInterface) return
|
||||
|
||||
dmsService.service.sendRequest("network.wifi.disconnect", null, response => {
|
||||
DMSService.sendRequest("network.wifi.disconnect", null, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError("Failed to disconnect WiFi")
|
||||
} else {
|
||||
@@ -352,10 +331,10 @@ Singleton {
|
||||
}
|
||||
|
||||
function forgetWifiNetwork(ssid) {
|
||||
if (!networkAvailable || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable) return
|
||||
|
||||
forgetSSID = ssid
|
||||
dmsService.service.sendRequest("network.wifi.forget", { ssid: ssid }, response => {
|
||||
DMSService.sendRequest("network.wifi.forget", { ssid: ssid }, response => {
|
||||
if (response.error) {
|
||||
console.warn("Failed to forget network:", response.error)
|
||||
} else {
|
||||
@@ -382,10 +361,10 @@ Singleton {
|
||||
}
|
||||
|
||||
function toggleWifiRadio() {
|
||||
if (!networkAvailable || wifiToggling || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable || wifiToggling) return
|
||||
|
||||
wifiToggling = true
|
||||
dmsService.service.sendRequest("network.wifi.toggle", null, response => {
|
||||
DMSService.sendRequest("network.wifi.toggle", null, response => {
|
||||
wifiToggling = false
|
||||
|
||||
if (response.error) {
|
||||
@@ -398,9 +377,9 @@ Singleton {
|
||||
}
|
||||
|
||||
function enableWifiDevice() {
|
||||
if (!networkAvailable || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable) return
|
||||
|
||||
dmsService.service.sendRequest("network.wifi.enable", null, response => {
|
||||
DMSService.sendRequest("network.wifi.enable", null, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError("Failed to enable WiFi")
|
||||
} else {
|
||||
@@ -410,14 +389,14 @@ Singleton {
|
||||
}
|
||||
|
||||
function setNetworkPreference(preference) {
|
||||
if (!networkAvailable || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable) return
|
||||
|
||||
userPreference = preference
|
||||
changingPreference = true
|
||||
targetPreference = preference
|
||||
SettingsData.setNetworkPreference(preference)
|
||||
|
||||
dmsService.service.sendRequest("network.preference.set", { preference: preference }, response => {
|
||||
DMSService.sendRequest("network.preference.set", { preference: preference }, response => {
|
||||
changingPreference = false
|
||||
targetPreference = ""
|
||||
|
||||
@@ -441,13 +420,13 @@ Singleton {
|
||||
}
|
||||
|
||||
function toggleNetworkConnection(type) {
|
||||
if (!networkAvailable || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable) return
|
||||
|
||||
if (type === "ethernet") {
|
||||
if (networkStatus === "ethernet") {
|
||||
dmsService.service.sendRequest("network.ethernet.disconnect", null, null)
|
||||
DMSService.sendRequest("network.ethernet.disconnect", null, null)
|
||||
} else {
|
||||
dmsService.service.sendRequest("network.ethernet.connect", null, null)
|
||||
DMSService.sendRequest("network.ethernet.connect", null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -466,13 +445,13 @@ Singleton {
|
||||
}
|
||||
|
||||
function fetchNetworkInfo(ssid) {
|
||||
if (!networkAvailable || !dmsService || !dmsService.service) return
|
||||
if (!networkAvailable) return
|
||||
|
||||
networkInfoSSID = ssid
|
||||
networkInfoLoading = true
|
||||
networkInfoDetails = "Loading network information..."
|
||||
|
||||
dmsService.service.sendRequest("network.info", { ssid: ssid }, response => {
|
||||
DMSService.sendRequest("network.info", { ssid: ssid }, response => {
|
||||
networkInfoLoading = false
|
||||
|
||||
if (response.error) {
|
||||
|
||||
@@ -59,7 +59,7 @@ Singleton {
|
||||
createEmptyFile(fullPath, function() {
|
||||
root.tabs = [{
|
||||
id: id,
|
||||
title: qsTr("Untitled"),
|
||||
title: I18n.tr("Untitled"),
|
||||
filePath: filePath,
|
||||
isTemporary: true,
|
||||
lastModified: new Date().toISOString(),
|
||||
@@ -129,7 +129,7 @@ Singleton {
|
||||
|
||||
var newTab = {
|
||||
id: id,
|
||||
title: qsTr("Untitled"),
|
||||
title: I18n.tr("Untitled"),
|
||||
filePath: filePath,
|
||||
isTemporary: true,
|
||||
lastModified: new Date().toISOString(),
|
||||
@@ -170,7 +170,7 @@ Singleton {
|
||||
createEmptyFile(baseDir + "/" + filePath, function() {
|
||||
newTabs[0] = {
|
||||
id: id,
|
||||
title: qsTr("Untitled"),
|
||||
title: I18n.tr("Untitled"),
|
||||
filePath: filePath,
|
||||
isTemporary: true,
|
||||
lastModified: new Date().toISOString(),
|
||||
|
||||
@@ -4,6 +4,7 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
@@ -24,197 +25,202 @@ Singleton {
|
||||
return configDirStr + "/DankMaterialShell/plugins"
|
||||
}
|
||||
property string systemPluginDirectory: "/etc/xdg/quickshell/dms-plugins"
|
||||
property var pluginDirectories: [pluginDirectory, systemPluginDirectory]
|
||||
|
||||
property var knownManifests: ({})
|
||||
property var pathToPluginId: ({})
|
||||
property var pluginInstances: ({})
|
||||
|
||||
signal pluginLoaded(string pluginId)
|
||||
signal pluginUnloaded(string pluginId)
|
||||
signal pluginLoadFailed(string pluginId, string error)
|
||||
signal pluginDataChanged(string pluginId)
|
||||
signal pluginListUpdated()
|
||||
|
||||
Timer {
|
||||
id: resyncDebounce
|
||||
interval: 120
|
||||
repeat: false
|
||||
onTriggered: resyncAll()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Qt.callLater(initializePlugins)
|
||||
userWatcher.folder = Paths.toFileUrl(root.pluginDirectory)
|
||||
systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory)
|
||||
Qt.callLater(resyncAll)
|
||||
}
|
||||
|
||||
function initializePlugins() {
|
||||
scanPlugins()
|
||||
FolderListModel {
|
||||
id: userWatcher
|
||||
showDirs: true
|
||||
showFiles: false
|
||||
showDotAndDotDot: false
|
||||
nameFilters: ["plugin.json"]
|
||||
|
||||
onCountChanged: resyncDebounce.restart()
|
||||
onStatusChanged: if (status === FolderListModel.Ready) resyncDebounce.restart()
|
||||
}
|
||||
|
||||
property int currentScanIndex: 0
|
||||
property var scanResults: []
|
||||
property var foundPlugins: ({})
|
||||
FolderListModel {
|
||||
id: systemWatcher
|
||||
showDirs: true
|
||||
showFiles: false
|
||||
showDotAndDotDot: false
|
||||
nameFilters: ["plugin.json"]
|
||||
|
||||
property var lsProcess: Process {
|
||||
id: dirScanner
|
||||
onCountChanged: resyncDebounce.restart()
|
||||
onStatusChanged: if (status === FolderListModel.Ready) resyncDebounce.restart()
|
||||
}
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
var output = text.trim()
|
||||
var currentDir = pluginDirectories[currentScanIndex]
|
||||
if (output) {
|
||||
var directories = output.split('\n')
|
||||
for (var i = 0; i < directories.length; i++) {
|
||||
var dir = directories[i].trim()
|
||||
if (dir) {
|
||||
var manifestPath = currentDir + "/" + dir + "/plugin.json"
|
||||
loadPluginManifest(manifestPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
function snapshotModel(model, sourceTag) {
|
||||
const out = []
|
||||
const n = model.count
|
||||
const baseDir = sourceTag === "user" ? pluginDirectory : systemPluginDirectory
|
||||
for (let i = 0; i < n; i++) {
|
||||
let dirPath = model.get(i, "filePath")
|
||||
if (dirPath.startsWith("file://")) {
|
||||
dirPath = dirPath.substring(7)
|
||||
}
|
||||
if (!dirPath.startsWith(baseDir)) {
|
||||
continue
|
||||
}
|
||||
const manifestPath = dirPath + "/plugin.json"
|
||||
out.push({ path: manifestPath, source: sourceTag })
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
function resyncAll() {
|
||||
const userList = snapshotModel(userWatcher, "user")
|
||||
const sysList = snapshotModel(systemWatcher, "system")
|
||||
const seenPaths = {}
|
||||
|
||||
function consider(entry) {
|
||||
const key = entry.path
|
||||
seenPaths[key] = true
|
||||
const prev = knownManifests[key]
|
||||
if (!prev) {
|
||||
loadPluginManifestFile(entry.path, entry.source, Date.now())
|
||||
}
|
||||
}
|
||||
for (let i=0;i<userList.length;i++) consider(userList[i])
|
||||
for (let i=0;i<sysList.length;i++) consider(sysList[i])
|
||||
|
||||
onExited: function(exitCode) {
|
||||
currentScanIndex++
|
||||
if (currentScanIndex < pluginDirectories.length) {
|
||||
scanNextDirectory()
|
||||
} else {
|
||||
currentScanIndex = 0
|
||||
cleanupRemovedPlugins()
|
||||
}
|
||||
const removed = []
|
||||
for (const path in knownManifests) {
|
||||
if (!seenPaths[path]) removed.push(path)
|
||||
}
|
||||
}
|
||||
|
||||
function scanPlugins() {
|
||||
currentScanIndex = 0
|
||||
foundPlugins = {}
|
||||
scanNextDirectory()
|
||||
}
|
||||
|
||||
function scanNextDirectory() {
|
||||
var dir = pluginDirectories[currentScanIndex]
|
||||
lsProcess.command = ["find", "-L", dir, "-maxdepth", "1", "-type", "d", "-not", "-path", dir, "-exec", "basename", "{}", ";"]
|
||||
lsProcess.running = true
|
||||
}
|
||||
|
||||
property var manifestReaders: ({})
|
||||
|
||||
function loadPluginManifest(manifestPath) {
|
||||
var readerId = "reader_" + Date.now() + "_" + Math.random()
|
||||
|
||||
var checkProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { stdout: StdioCollector { } }")
|
||||
if (checkProcess.status === Component.Ready) {
|
||||
var checker = checkProcess.createObject(root)
|
||||
checker.command = ["test", "-f", manifestPath]
|
||||
checker.exited.connect(function(exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
checker.destroy()
|
||||
delete manifestReaders[readerId]
|
||||
return
|
||||
if (removed.length) {
|
||||
removed.forEach(function(path) {
|
||||
const pid = pathToPluginId[path]
|
||||
if (pid) {
|
||||
unregisterPluginByPath(path, pid)
|
||||
}
|
||||
|
||||
var catProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { stdout: StdioCollector { } }")
|
||||
if (catProcess.status === Component.Ready) {
|
||||
var process = catProcess.createObject(root)
|
||||
process.command = ["cat", manifestPath]
|
||||
process.stdout.streamFinished.connect(function() {
|
||||
try {
|
||||
var manifest = JSON.parse(process.stdout.text.trim())
|
||||
processManifest(manifest, manifestPath)
|
||||
} catch (e) {
|
||||
console.error("PluginService: Failed to parse manifest", manifestPath, ":", e.message)
|
||||
}
|
||||
process.destroy()
|
||||
delete manifestReaders[readerId]
|
||||
})
|
||||
process.exited.connect(function(exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
console.error("PluginService: Failed to read manifest file:", manifestPath, "exit code:", exitCode)
|
||||
process.destroy()
|
||||
delete manifestReaders[readerId]
|
||||
}
|
||||
})
|
||||
manifestReaders[readerId] = process
|
||||
process.running = true
|
||||
} else {
|
||||
console.error("PluginService: Failed to create manifest reader process")
|
||||
}
|
||||
|
||||
checker.destroy()
|
||||
delete knownManifests[path]
|
||||
delete pathToPluginId[path]
|
||||
})
|
||||
manifestReaders[readerId] = checker
|
||||
checker.running = true
|
||||
} else {
|
||||
console.error("PluginService: Failed to create file check process")
|
||||
pluginListUpdated()
|
||||
}
|
||||
}
|
||||
|
||||
function processManifest(manifest, manifestPath) {
|
||||
registerPlugin(manifest, manifestPath)
|
||||
|
||||
var enabled = SettingsData.getPluginSetting(manifest.id, "enabled", false)
|
||||
if (enabled) {
|
||||
loadPlugin(manifest.id)
|
||||
}
|
||||
function loadPluginManifestFile(manifestPathNoScheme, sourceTag, mtimeEpochMs) {
|
||||
const manifestId = "m_" + Math.random().toString(36).slice(2)
|
||||
const qml = `
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
FileView {
|
||||
id: fv
|
||||
property string absPath: ""
|
||||
onLoaded: {
|
||||
try {
|
||||
let raw = text()
|
||||
if (raw.charCodeAt(0) === 0xFEFF) raw = raw.slice(1)
|
||||
const manifest = JSON.parse(raw)
|
||||
root._onManifestParsed(absPath, manifest, "${sourceTag}", ${mtimeEpochMs})
|
||||
} catch (e) {
|
||||
console.error("PluginService: bad manifest", absPath, e.message)
|
||||
knownManifests[absPath] = { mtime: ${mtimeEpochMs}, source: "${sourceTag}", bad: true }
|
||||
}
|
||||
fv.destroy()
|
||||
}
|
||||
onLoadFailed: (err) => {
|
||||
console.warn("PluginService: manifest load failed", absPath, err)
|
||||
fv.destroy()
|
||||
}
|
||||
}
|
||||
`
|
||||
const loader = Qt.createQmlObject(qml, root, "mf_" + manifestId)
|
||||
loader.absPath = manifestPathNoScheme
|
||||
loader.path = manifestPathNoScheme
|
||||
}
|
||||
|
||||
function registerPlugin(manifest, manifestPath) {
|
||||
if (!manifest.id || !manifest.name || !manifest.component) {
|
||||
console.error("PluginService: Invalid manifest, missing required fields:", manifestPath)
|
||||
function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) {
|
||||
if (!manifest || !manifest.id || !manifest.name || !manifest.component) {
|
||||
console.error("PluginService: invalid manifest fields:", absPath)
|
||||
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag, bad: true }
|
||||
return
|
||||
}
|
||||
|
||||
var pluginDir = manifestPath.substring(0, manifestPath.lastIndexOf('/'))
|
||||
const dir = absPath.substring(0, absPath.lastIndexOf('/'))
|
||||
let comp = manifest.component
|
||||
if (comp.startsWith("./")) comp = comp.slice(2)
|
||||
let settings = manifest.settings
|
||||
if (settings && settings.startsWith("./")) settings = settings.slice(2)
|
||||
|
||||
// Clean up relative paths by removing './' prefix
|
||||
var componentFile = manifest.component
|
||||
if (componentFile.startsWith('./')) {
|
||||
componentFile = componentFile.substring(2)
|
||||
const info = {}
|
||||
for (const k in manifest) info[k] = manifest[k]
|
||||
|
||||
let perms = manifest.permissions
|
||||
if (typeof perms === "string") {
|
||||
perms = perms.split(/\s*,\s*/)
|
||||
}
|
||||
|
||||
var settingsFile = manifest.settings
|
||||
if (settingsFile && settingsFile.startsWith('./')) {
|
||||
settingsFile = settingsFile.substring(2)
|
||||
if (!Array.isArray(perms)) {
|
||||
perms = []
|
||||
}
|
||||
info.permissions = perms.map(p => String(p).trim())
|
||||
|
||||
var pluginInfo = {}
|
||||
for (var key in manifest) {
|
||||
pluginInfo[key] = manifest[key]
|
||||
info.manifestPath = absPath
|
||||
info.pluginDirectory = dir
|
||||
info.componentPath = dir + "/" + comp
|
||||
info.settingsPath = settings ? (dir + "/" + settings) : null
|
||||
info.loaded = isPluginLoaded(manifest.id)
|
||||
info.type = manifest.type || "widget"
|
||||
info.source = sourceTag
|
||||
|
||||
const existing = availablePlugins[manifest.id]
|
||||
const shouldReplace =
|
||||
(!existing) ||
|
||||
(existing && existing.source === "system" && sourceTag === "user")
|
||||
|
||||
if (shouldReplace) {
|
||||
if (existing && existing.loaded && existing.source !== sourceTag) {
|
||||
unloadPlugin(manifest.id)
|
||||
}
|
||||
const newMap = Object.assign({}, availablePlugins)
|
||||
newMap[manifest.id] = info
|
||||
availablePlugins = newMap
|
||||
pathToPluginId[absPath] = manifest.id
|
||||
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag }
|
||||
pluginListUpdated()
|
||||
const enabled = SettingsData.getPluginSetting(manifest.id, "enabled", false)
|
||||
if (enabled && !info.loaded) loadPlugin(manifest.id)
|
||||
} else {
|
||||
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag, shadowedBy: existing.source }
|
||||
pathToPluginId[absPath] = manifest.id
|
||||
}
|
||||
pluginInfo.manifestPath = manifestPath
|
||||
pluginInfo.pluginDirectory = pluginDir
|
||||
pluginInfo.componentPath = pluginDir + '/' + componentFile
|
||||
pluginInfo.settingsPath = settingsFile ? pluginDir + '/' + settingsFile : null
|
||||
pluginInfo.loaded = false
|
||||
pluginInfo.type = manifest.type || "widget"
|
||||
|
||||
var newPlugins = Object.assign({}, availablePlugins)
|
||||
newPlugins[manifest.id] = pluginInfo
|
||||
availablePlugins = newPlugins
|
||||
foundPlugins[manifest.id] = true
|
||||
}
|
||||
|
||||
function hasPermission(pluginId, permission) {
|
||||
var plugin = availablePlugins[pluginId]
|
||||
if (!plugin) {
|
||||
return false
|
||||
}
|
||||
var permissions = plugin.permissions || []
|
||||
return permissions.indexOf(permission) !== -1
|
||||
}
|
||||
|
||||
function cleanupRemovedPlugins() {
|
||||
var pluginsToRemove = []
|
||||
for (var pluginId in availablePlugins) {
|
||||
if (!foundPlugins[pluginId]) {
|
||||
pluginsToRemove.push(pluginId)
|
||||
}
|
||||
}
|
||||
|
||||
if (pluginsToRemove.length > 0) {
|
||||
var newPlugins = Object.assign({}, availablePlugins)
|
||||
for (var i = 0; i < pluginsToRemove.length; i++) {
|
||||
var pluginId = pluginsToRemove[i]
|
||||
if (isPluginLoaded(pluginId)) {
|
||||
unloadPlugin(pluginId)
|
||||
}
|
||||
delete newPlugins[pluginId]
|
||||
}
|
||||
availablePlugins = newPlugins
|
||||
function unregisterPluginByPath(absPath, pluginId) {
|
||||
const current = availablePlugins[pluginId]
|
||||
if (current && current.manifestPath === absPath) {
|
||||
if (current.loaded) unloadPlugin(pluginId)
|
||||
const newMap = Object.assign({}, availablePlugins)
|
||||
delete newMap[pluginId]
|
||||
availablePlugins = newMap
|
||||
}
|
||||
}
|
||||
|
||||
function loadPlugin(pluginId) {
|
||||
var plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId]
|
||||
if (!plugin) {
|
||||
console.error("PluginService: Plugin not found:", pluginId)
|
||||
pluginLoadFailed(pluginId, "Plugin not found")
|
||||
@@ -225,48 +231,43 @@ Singleton {
|
||||
return true
|
||||
}
|
||||
|
||||
var isDaemon = plugin.type === "daemon"
|
||||
var componentMap = isDaemon ? pluginDaemonComponents : pluginWidgetComponents
|
||||
const isDaemon = plugin.type === "daemon"
|
||||
const map = isDaemon ? pluginDaemonComponents : pluginWidgetComponents
|
||||
|
||||
if (componentMap[pluginId]) {
|
||||
componentMap[pluginId]?.destroy()
|
||||
if (isDaemon) {
|
||||
var newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
delete newDaemons[pluginId]
|
||||
pluginDaemonComponents = newDaemons
|
||||
} else {
|
||||
var newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
delete newComponents[pluginId]
|
||||
pluginWidgetComponents = newComponents
|
||||
}
|
||||
const prevInstance = pluginInstances[pluginId]
|
||||
if (prevInstance) {
|
||||
prevInstance.destroy()
|
||||
const newInstances = Object.assign({}, pluginInstances)
|
||||
delete newInstances[pluginId]
|
||||
pluginInstances = newInstances
|
||||
}
|
||||
|
||||
try {
|
||||
var componentUrl = "file://" + plugin.componentPath
|
||||
var component = Qt.createComponent(componentUrl, Component.PreferSynchronous)
|
||||
|
||||
if (component.status === Component.Loading) {
|
||||
component.statusChanged.connect(function() {
|
||||
if (component.status === Component.Error) {
|
||||
console.error("PluginService: Failed to create component for plugin:", pluginId, "Error:", component.errorString())
|
||||
pluginLoadFailed(pluginId, component.errorString())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (component.status === Component.Error) {
|
||||
console.error("PluginService: Failed to create component for plugin:", pluginId, "Error:", component.errorString())
|
||||
pluginLoadFailed(pluginId, component.errorString())
|
||||
const url = "file://" + plugin.componentPath
|
||||
const comp = Qt.createComponent(url, Component.PreferSynchronous)
|
||||
if (comp.status === Component.Error) {
|
||||
console.error("PluginService: component error", pluginId, comp.errorString())
|
||||
pluginLoadFailed(pluginId, comp.errorString())
|
||||
return false
|
||||
}
|
||||
|
||||
if (isDaemon) {
|
||||
var newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
newDaemons[pluginId] = component
|
||||
const instance = comp.createObject(root, { "pluginId": pluginId })
|
||||
if (!instance) {
|
||||
console.error("PluginService: failed to instantiate daemon:", pluginId, comp.errorString())
|
||||
pluginLoadFailed(pluginId, comp.errorString())
|
||||
return false
|
||||
}
|
||||
const newInstances = Object.assign({}, pluginInstances)
|
||||
newInstances[pluginId] = instance
|
||||
pluginInstances = newInstances
|
||||
|
||||
const newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
newDaemons[pluginId] = comp
|
||||
pluginDaemonComponents = newDaemons
|
||||
} else {
|
||||
var newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
newComponents[pluginId] = component
|
||||
const newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
newComponents[pluginId] = comp
|
||||
pluginWidgetComponents = newComponents
|
||||
}
|
||||
|
||||
@@ -276,31 +277,37 @@ Singleton {
|
||||
pluginLoaded(pluginId)
|
||||
return true
|
||||
|
||||
} catch (error) {
|
||||
console.error("PluginService: Error loading plugin:", pluginId, "Error:", error.message)
|
||||
pluginLoadFailed(pluginId, error.message)
|
||||
} catch (e) {
|
||||
console.error("PluginService: Error loading plugin:", pluginId, e.message)
|
||||
pluginLoadFailed(pluginId, e.message)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function unloadPlugin(pluginId) {
|
||||
var plugin = loadedPlugins[pluginId]
|
||||
const plugin = loadedPlugins[pluginId]
|
||||
if (!plugin) {
|
||||
console.warn("PluginService: Plugin not loaded:", pluginId)
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
var isDaemon = plugin.type === "daemon"
|
||||
const isDaemon = plugin.type === "daemon"
|
||||
|
||||
const instance = pluginInstances[pluginId]
|
||||
if (instance) {
|
||||
instance.destroy()
|
||||
const newInstances = Object.assign({}, pluginInstances)
|
||||
delete newInstances[pluginId]
|
||||
pluginInstances = newInstances
|
||||
}
|
||||
|
||||
if (isDaemon && pluginDaemonComponents[pluginId]) {
|
||||
pluginDaemonComponents[pluginId]?.destroy()
|
||||
var newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
const newDaemons = Object.assign({}, pluginDaemonComponents)
|
||||
delete newDaemons[pluginId]
|
||||
pluginDaemonComponents = newDaemons
|
||||
} else if (pluginWidgetComponents[pluginId]) {
|
||||
pluginWidgetComponents[pluginId]?.destroy()
|
||||
var newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
const newComponents = Object.assign({}, pluginWidgetComponents)
|
||||
delete newComponents[pluginId]
|
||||
pluginWidgetComponents = newComponents
|
||||
}
|
||||
@@ -326,30 +333,30 @@ Singleton {
|
||||
}
|
||||
|
||||
function getAvailablePlugins() {
|
||||
var result = []
|
||||
for (var key in availablePlugins) {
|
||||
const result = []
|
||||
for (const key in availablePlugins) {
|
||||
result.push(availablePlugins[key])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function getPluginVariants(pluginId) {
|
||||
var plugin = availablePlugins[pluginId]
|
||||
const plugin = availablePlugins[pluginId]
|
||||
if (!plugin) {
|
||||
return []
|
||||
}
|
||||
var variants = SettingsData.getPluginSetting(pluginId, "variants", [])
|
||||
const variants = SettingsData.getPluginSetting(pluginId, "variants", [])
|
||||
return variants
|
||||
}
|
||||
|
||||
function getAllPluginVariants() {
|
||||
var result = []
|
||||
for (var pluginId in availablePlugins) {
|
||||
var plugin = availablePlugins[pluginId]
|
||||
const result = []
|
||||
for (const pluginId in availablePlugins) {
|
||||
const plugin = availablePlugins[pluginId]
|
||||
if (plugin.type !== "widget") {
|
||||
continue
|
||||
}
|
||||
var variants = getPluginVariants(pluginId)
|
||||
const variants = getPluginVariants(pluginId)
|
||||
if (variants.length === 0) {
|
||||
result.push({
|
||||
pluginId: pluginId,
|
||||
@@ -361,8 +368,8 @@ Singleton {
|
||||
loaded: plugin.loaded
|
||||
})
|
||||
} else {
|
||||
for (var i = 0; i < variants.length; i++) {
|
||||
var variant = variants[i]
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
const variant = variants[i]
|
||||
result.push({
|
||||
pluginId: pluginId,
|
||||
variantId: variant.id,
|
||||
@@ -379,9 +386,9 @@ Singleton {
|
||||
}
|
||||
|
||||
function createPluginVariant(pluginId, variantName, variantConfig) {
|
||||
var variants = getPluginVariants(pluginId)
|
||||
var variantId = "variant_" + Date.now()
|
||||
var newVariant = Object.assign({}, variantConfig, {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const variantId = "variant_" + Date.now()
|
||||
const newVariant = Object.assign({}, variantConfig, {
|
||||
id: variantId,
|
||||
name: variantName
|
||||
})
|
||||
@@ -392,15 +399,15 @@ Singleton {
|
||||
}
|
||||
|
||||
function removePluginVariant(pluginId, variantId) {
|
||||
var variants = getPluginVariants(pluginId)
|
||||
var newVariants = variants.filter(function(v) { return v.id !== variantId })
|
||||
const variants = getPluginVariants(pluginId)
|
||||
const newVariants = variants.filter(function(v) { return v.id !== variantId })
|
||||
SettingsData.setPluginSetting(pluginId, "variants", newVariants)
|
||||
pluginDataChanged(pluginId)
|
||||
}
|
||||
|
||||
function updatePluginVariant(pluginId, variantId, variantConfig) {
|
||||
var variants = getPluginVariants(pluginId)
|
||||
for (var i = 0; i < variants.length; i++) {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
if (variants[i].id === variantId) {
|
||||
variants[i] = Object.assign({}, variants[i], variantConfig)
|
||||
break
|
||||
@@ -411,8 +418,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function getPluginVariantData(pluginId, variantId) {
|
||||
var variants = getPluginVariants(pluginId)
|
||||
for (var i = 0; i < variants.length; i++) {
|
||||
const variants = getPluginVariants(pluginId)
|
||||
for (let i = 0; i < variants.length; i++) {
|
||||
if (variants[i].id === variantId) {
|
||||
return variants[i]
|
||||
}
|
||||
@@ -421,8 +428,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function getLoadedPlugins() {
|
||||
var result = []
|
||||
for (var key in loadedPlugins) {
|
||||
const result = []
|
||||
for (const key in loadedPlugins) {
|
||||
result.push(loadedPlugins[key])
|
||||
}
|
||||
return result
|
||||
@@ -463,10 +470,14 @@ Singleton {
|
||||
SettingsData.savePluginSettings()
|
||||
}
|
||||
|
||||
function scanPlugins() {
|
||||
resyncDebounce.restart()
|
||||
}
|
||||
|
||||
function createPluginDirectory() {
|
||||
var mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }")
|
||||
const mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }")
|
||||
if (mkdirProcess.status === Component.Ready) {
|
||||
var process = mkdirProcess.createObject(root)
|
||||
const process = mkdirProcess.createObject(root)
|
||||
process.command = ["mkdir", "-p", pluginDirectory]
|
||||
process.exited.connect(function(exitCode) {
|
||||
if (exitCode !== 0) {
|
||||
|
||||
@@ -15,17 +15,18 @@ Singleton {
|
||||
property bool settingsPortalAvailable: false
|
||||
property int systemColorScheme: 0
|
||||
|
||||
property var dmsService: null
|
||||
property bool freedeskAvailable: false
|
||||
|
||||
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
||||
|
||||
function init() {}
|
||||
|
||||
function getSystemProfileImage() {
|
||||
if (freedeskAvailable && dmsService && dmsService.service) {
|
||||
if (freedeskAvailable) {
|
||||
const username = Quickshell.env("USER")
|
||||
if (!username) return
|
||||
|
||||
dmsService.service.sendRequest("freedesktop.accounts.getUserIconFile", { username: username }, response => {
|
||||
DMSService.sendRequest("freedesktop.accounts.getUserIconFile", { username: username }, response => {
|
||||
if (response.result && response.result.success) {
|
||||
const iconFile = response.result.value || ""
|
||||
if (iconFile && iconFile !== "" && iconFile !== "/var/lib/AccountsService/icons/") {
|
||||
@@ -51,8 +52,8 @@ Singleton {
|
||||
return
|
||||
}
|
||||
|
||||
if (freedeskAvailable && dmsService && dmsService.service) {
|
||||
dmsService.service.sendRequest("freedesktop.accounts.getUserIconFile", { username: username }, response => {
|
||||
if (freedeskAvailable) {
|
||||
DMSService.sendRequest("freedesktop.accounts.getUserIconFile", { username: username }, response => {
|
||||
if (response.result && response.result.success) {
|
||||
const icon = response.result.value || ""
|
||||
if (icon && icon !== "" && icon !== "/var/lib/AccountsService/icons/") {
|
||||
@@ -85,8 +86,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function getSystemColorScheme() {
|
||||
if (freedeskAvailable && dmsService && dmsService.service) {
|
||||
dmsService.service.sendRequest("freedesktop.settings.getColorScheme", null, response => {
|
||||
if (freedeskAvailable) {
|
||||
DMSService.sendRequest("freedesktop.settings.getColorScheme", null, response => {
|
||||
if (response.result) {
|
||||
systemColorScheme = response.result.value || 0
|
||||
|
||||
@@ -134,8 +135,8 @@ Singleton {
|
||||
function setSystemProfileImage(imagePath) {
|
||||
if (!accountsServiceAvailable) return
|
||||
|
||||
if (freedeskAvailable && dmsService && dmsService.service) {
|
||||
dmsService.service.sendRequest("freedesktop.accounts.setIconFile", { path: imagePath || "" }, response => {
|
||||
if (freedeskAvailable) {
|
||||
DMSService.sendRequest("freedesktop.accounts.setIconFile", { path: imagePath || "" }, response => {
|
||||
if (response.error) {
|
||||
console.warn("PortalService: Failed to set icon file:", response.error)
|
||||
} else {
|
||||
@@ -150,65 +151,58 @@ Singleton {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Qt.callLater(initializeDMSConnection)
|
||||
}
|
||||
|
||||
function initializeDMSConnection() {
|
||||
try {
|
||||
dmsService = Qt.createQmlObject('import QtQuick; import qs.Services; QtObject { property var service: DMSService }', root)
|
||||
if (dmsService && dmsService.service) {
|
||||
dmsService.service.connectionStateChanged.connect(onDMSConnectionStateChanged)
|
||||
dmsService.service.capabilitiesChanged.connect(onDMSCapabilitiesChanged)
|
||||
if (dmsService.service.isConnected) {
|
||||
onDMSConnected()
|
||||
} else {
|
||||
Qt.callLater(checkFallback)
|
||||
}
|
||||
} else {
|
||||
Qt.callLater(checkFallback)
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("PortalService: Failed to initialize DMS connection:", e)
|
||||
Qt.callLater(checkFallback)
|
||||
}
|
||||
}
|
||||
|
||||
function checkFallback() {
|
||||
if (!freedeskAvailable) {
|
||||
console.log("PortalService: DMS not available, using fallback methods")
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities()
|
||||
} else {
|
||||
console.log("PortalService: DMS_SOCKET not set, using fallback methods")
|
||||
checkAccountsServiceFallback()
|
||||
checkSettingsPortalFallback()
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSConnectionStateChanged() {
|
||||
if (dmsService && dmsService.service && dmsService.service.isConnected) {
|
||||
onDMSConnected()
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: DMSService
|
||||
|
||||
function onDMSCapabilitiesChanged() {
|
||||
if (dmsService && dmsService.service && dmsService.service.capabilities.includes("freedesktop")) {
|
||||
freedeskAvailable = true
|
||||
checkAccountsService()
|
||||
checkSettingsPortal()
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSConnected() {
|
||||
if (dmsService && dmsService.service && dmsService.service.capabilities && dmsService.service.capabilities.length > 0) {
|
||||
freedeskAvailable = dmsService.service.capabilities.includes("freedesktop")
|
||||
if (freedeskAvailable) {
|
||||
checkAccountsService()
|
||||
checkSettingsPortal()
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected) {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkAccountsService() {
|
||||
if (!freedeskAvailable || !dmsService || !dmsService.service) return
|
||||
Connections {
|
||||
target: DMSService
|
||||
enabled: DMSService.isConnected
|
||||
|
||||
dmsService.service.sendRequest("freedesktop.getState", null, response => {
|
||||
function onCapabilitiesChanged() {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
|
||||
function checkDMSCapabilities() {
|
||||
if (!DMSService.isConnected) {
|
||||
return
|
||||
}
|
||||
|
||||
if (DMSService.capabilities.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
freedeskAvailable = DMSService.capabilities.includes("freedesktop")
|
||||
if (freedeskAvailable) {
|
||||
checkAccountsService()
|
||||
checkSettingsPortal()
|
||||
} else {
|
||||
console.log("PortalService: freedesktop capability not available in DMS, using fallback methods")
|
||||
checkAccountsServiceFallback()
|
||||
checkSettingsPortalFallback()
|
||||
}
|
||||
}
|
||||
|
||||
function checkAccountsService() {
|
||||
if (!freedeskAvailable) return
|
||||
|
||||
DMSService.sendRequest("freedesktop.getState", null, response => {
|
||||
if (response.result && response.result.accounts) {
|
||||
accountsServiceAvailable = response.result.accounts.available || false
|
||||
if (accountsServiceAvailable) {
|
||||
@@ -219,9 +213,9 @@ Singleton {
|
||||
}
|
||||
|
||||
function checkSettingsPortal() {
|
||||
if (!freedeskAvailable || !dmsService || !dmsService.service) return
|
||||
if (!freedeskAvailable) return
|
||||
|
||||
dmsService.service.sendRequest("freedesktop.getState", null, response => {
|
||||
DMSService.sendRequest("freedesktop.getState", null, response => {
|
||||
if (response.result && response.result.settings) {
|
||||
settingsPortalAvailable = response.result.settings.available || false
|
||||
if (settingsPortalAvailable) {
|
||||
|
||||
@@ -46,7 +46,6 @@ Singleton {
|
||||
signal prepareForSleep()
|
||||
signal loginctlStateChanged()
|
||||
|
||||
property var dmsService: null
|
||||
property bool subscriptionConnected: false
|
||||
property bool stateInitialized: false
|
||||
|
||||
@@ -62,7 +61,16 @@ Singleton {
|
||||
detectHibernateProcess.running = true
|
||||
detectPrimeRunProcess.running = true
|
||||
console.log("SessionService: Native inhibitor available:", nativeInhibitorAvailable)
|
||||
Qt.callLater(initializeDMSConnection)
|
||||
if (!SessionData.loginctlLockIntegration) {
|
||||
console.log("SessionService: loginctl lock integration disabled by user")
|
||||
return
|
||||
}
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities()
|
||||
} else {
|
||||
console.log("SessionService: DMS_SOCKET not set, using fallback")
|
||||
initFallbackLoginctl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,10 +276,48 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected) {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
enabled: DMSService.isConnected
|
||||
|
||||
function onCapabilitiesChanged() {
|
||||
checkDMSCapabilities()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
|
||||
function onLoginctlLockIntegrationChanged() {
|
||||
if (SessionData.loginctlLockIntegration) {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities()
|
||||
} else {
|
||||
initFallbackLoginctl()
|
||||
}
|
||||
} else {
|
||||
subscriptionSocket.connected = false
|
||||
lockStateMonitorFallback.running = false
|
||||
loginctlAvailable = false
|
||||
stateInitialized = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankSocket {
|
||||
id: subscriptionSocket
|
||||
path: root.socketPath
|
||||
connected: loginctlAvailable
|
||||
connected: loginctlAvailable && SessionData.loginctlLockIntegration
|
||||
|
||||
onConnectionStateChanged: {
|
||||
root.subscriptionConnected = connected
|
||||
@@ -310,76 +356,36 @@ Singleton {
|
||||
})
|
||||
}
|
||||
|
||||
function initializeDMSConnection() {
|
||||
if (!socketPath || socketPath.length === 0) {
|
||||
console.log("SessionService: DMS_SOCKET not set, using fallback")
|
||||
initFallbackLoginctl()
|
||||
function checkDMSCapabilities() {
|
||||
if (!DMSService.isConnected) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
dmsService = Qt.createQmlObject('import QtQuick; import qs.Services; QtObject { property var service: DMSService }', root)
|
||||
if (dmsService && dmsService.service) {
|
||||
dmsService.service.connectionStateChanged.connect(onDMSConnectionStateChanged)
|
||||
dmsService.service.capabilitiesChanged.connect(onDMSCapabilitiesChanged)
|
||||
checkCapabilities()
|
||||
} else {
|
||||
console.warn("SessionService: Failed to get DMS service reference, using fallback")
|
||||
initFallbackLoginctl()
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("SessionService: Failed to initialize DMS connection, using fallback:", e)
|
||||
initFallbackLoginctl()
|
||||
if (DMSService.capabilities.length === 0) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function checkCapabilities() {
|
||||
if (dmsService && dmsService.service && dmsService.service.isConnected) {
|
||||
onDMSConnected()
|
||||
if (!SessionData.loginctlLockIntegration) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSConnectionStateChanged() {
|
||||
if (dmsService && dmsService.service && dmsService.service.isConnected) {
|
||||
onDMSConnected()
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSCapabilitiesChanged() {
|
||||
if (dmsService && dmsService.service) {
|
||||
if (dmsService.service.capabilities.includes("loginctl")) {
|
||||
loginctlAvailable = true
|
||||
if (dmsService.service.isConnected && !stateInitialized) {
|
||||
stateInitialized = true
|
||||
getLoginctlState()
|
||||
subscriptionSocket.connected = true
|
||||
}
|
||||
} else if (dmsService.service.capabilities.length > 0 && !loginctlAvailable) {
|
||||
console.log("SessionService: loginctl capability not available in DMS, using fallback")
|
||||
initFallbackLoginctl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDMSConnected() {
|
||||
if (dmsService && dmsService.service && dmsService.service.capabilities && dmsService.service.capabilities.length > 0) {
|
||||
loginctlAvailable = dmsService.service.capabilities.includes("loginctl")
|
||||
|
||||
if (loginctlAvailable && !stateInitialized) {
|
||||
if (DMSService.capabilities.includes("loginctl")) {
|
||||
loginctlAvailable = true
|
||||
if (!stateInitialized) {
|
||||
stateInitialized = true
|
||||
getLoginctlState()
|
||||
subscriptionSocket.connected = true
|
||||
} else if (!loginctlAvailable) {
|
||||
console.log("SessionService: loginctl capability not available in DMS, using fallback")
|
||||
initFallbackLoginctl()
|
||||
}
|
||||
} else {
|
||||
console.log("SessionService: loginctl capability not available in DMS, using fallback")
|
||||
initFallbackLoginctl()
|
||||
}
|
||||
}
|
||||
|
||||
function getLoginctlState() {
|
||||
if (!loginctlAvailable || !dmsService || !dmsService.service) return
|
||||
if (!loginctlAvailable) return
|
||||
|
||||
dmsService.service.sendRequest("loginctl.getState", null, response => {
|
||||
DMSService.sendRequest("loginctl.getState", null, response => {
|
||||
if (response.result) {
|
||||
updateLoginctlState(response.result)
|
||||
}
|
||||
@@ -387,6 +393,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function updateLoginctlState(state) {
|
||||
const wasLocked = locked
|
||||
|
||||
sessionId = state.sessionId || ""
|
||||
sessionPath = state.sessionPath || ""
|
||||
locked = state.locked || false
|
||||
@@ -405,6 +413,12 @@ Singleton {
|
||||
prepareForSleep()
|
||||
}
|
||||
|
||||
if (locked && !wasLocked) {
|
||||
sessionLocked()
|
||||
} else if (!locked && wasLocked) {
|
||||
sessionUnlocked()
|
||||
}
|
||||
|
||||
loginctlStateChanged()
|
||||
}
|
||||
|
||||
@@ -425,18 +439,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function lockSession() {
|
||||
if (loginctlAvailable && dmsService && dmsService.service) {
|
||||
dmsService.service.sendRequest("loginctl.lock", null, response => {
|
||||
if (response.error) {
|
||||
console.warn("SessionService: Failed to lock session:", response.error)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
lockSessionFallback.running = true
|
||||
}
|
||||
}
|
||||
|
||||
function initFallbackLoginctl() {
|
||||
getSessionPathFallback.running = true
|
||||
}
|
||||
@@ -516,10 +518,4 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: lockSessionFallback
|
||||
command: ["loginctl", "lock-session"]
|
||||
running: false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,48 @@ Singleton {
|
||||
property bool distributionSupported: false
|
||||
property string shellVersion: ""
|
||||
|
||||
readonly property list<string> supportedDistributions: ["arch", "cachyos", "manjaro", "endeavouros"]
|
||||
readonly property var archBasedSettings: {
|
||||
"listUpdatesParams": ["-Qu"],
|
||||
"upgradeSettings": {
|
||||
"params": ["-Syu"],
|
||||
"requiresSudo": false
|
||||
},
|
||||
"parserSettings": {
|
||||
"lineRegex": /^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/,
|
||||
"entryProducer": function (match) {
|
||||
return {
|
||||
"name": match[1],
|
||||
"currentVersion": match[2],
|
||||
"newVersion": match[3],
|
||||
"description": `${match[1]} ${match[2]} → ${match[3]}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var packageManagerParams: {
|
||||
"yay": archBasedSettings,
|
||||
"paru": archBasedSettings,
|
||||
"dnf": {
|
||||
"listUpdatesParams": ["list", "--upgrades", "--quiet", "--color=never"],
|
||||
"upgradeSettings": {
|
||||
"params": ["upgrade"],
|
||||
"requiresSudo": true
|
||||
},
|
||||
"parserSettings": {
|
||||
"lineRegex": /^([^\s]+)\s+([^\s]+)\s+.*$/,
|
||||
"entryProducer": function (match) {
|
||||
return {
|
||||
"name": match[1],
|
||||
"currentVersion": "",
|
||||
"newVersion": match[2],
|
||||
"description": `${match[1]} → ${match[2]}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
readonly property list<string> supportedDistributions: ["arch", "cachyos", "manjaro", "endeavouros", "fedora"]
|
||||
readonly property int updateCount: availableUpdates.length
|
||||
readonly property bool helperAvailable: pkgManager !== "" && distributionSupported
|
||||
|
||||
@@ -63,7 +104,7 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: helperDetection
|
||||
command: ["sh", "-c", "which paru || which yay"]
|
||||
command: ["sh", "-c", "which paru || which yay || which dnf"]
|
||||
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode === 0) {
|
||||
@@ -110,7 +151,7 @@ Singleton {
|
||||
|
||||
isChecking = true
|
||||
hasError = false
|
||||
updateChecker.command = [pkgManager, "-Qu"]
|
||||
updateChecker.command = [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesParams)
|
||||
updateChecker.running = true
|
||||
}
|
||||
|
||||
@@ -118,15 +159,13 @@ Singleton {
|
||||
const lines = output.trim().split('\n').filter(line => line.trim())
|
||||
const updates = []
|
||||
|
||||
const regex = packageManagerParams[pkgManager].parserSettings.lineRegex
|
||||
const entryProducer = packageManagerParams[pkgManager].parserSettings.entryProducer
|
||||
|
||||
for (const line of lines) {
|
||||
const match = line.match(/^(\S+)\s+([^\s]+)\s+->\s+([^\s]+)$/)
|
||||
const match = line.match(regex)
|
||||
if (match) {
|
||||
updates.push({
|
||||
name: match[1],
|
||||
currentVersion: match[2],
|
||||
newVersion: match[3],
|
||||
description: `${match[1]} ${match[2]} → ${match[3]}`
|
||||
})
|
||||
updates.push(entryProducer(match))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +176,9 @@ Singleton {
|
||||
if (!distributionSupported || !pkgManager || updateCount === 0) return
|
||||
|
||||
const terminal = Quickshell.env("TERMINAL") || "xterm"
|
||||
const updateCommand = `${pkgManager} -Syu && echo "Updates complete! Press Enter to close..." && read`
|
||||
const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" ")
|
||||
const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : ""
|
||||
const updateCommand = `${sudo} ${pkgManager} ${params} && echo "Updates complete! Press Enter to close..." && read`
|
||||
|
||||
updater.command = [terminal, "-e", "sh", "-c", updateCommand]
|
||||
updater.running = true
|
||||
@@ -149,4 +190,4 @@ Singleton {
|
||||
running: distributionSupported && pkgManager
|
||||
onTriggered: checkForUpdates()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +166,8 @@ Singleton {
|
||||
|
||||
try {
|
||||
const date = new Date(isoString)
|
||||
if (index === 0) return qsTr("Today")
|
||||
if (index === 1) return qsTr("Tomorrow")
|
||||
if (index === 0) return I18n.tr("Today")
|
||||
if (index === 1) return I18n.tr("Tomorrow")
|
||||
|
||||
const locale = Qt.locale()
|
||||
return locale.dayName(date.getDay(), Locale.ShortFormat)
|
||||
|
||||
@@ -23,7 +23,7 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
asynchronous: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
smooth: true
|
||||
mipmap: true
|
||||
cache: true
|
||||
@@ -44,8 +44,9 @@ Rectangle {
|
||||
|
||||
Item {
|
||||
id: circularMask
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - 4
|
||||
height: parent.height - 4
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
@@ -257,7 +257,7 @@ Item {
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
placeholderText: qsTr("Search...")
|
||||
placeholderText: I18n.tr("Search...")
|
||||
text: dropdownMenu.searchQuery
|
||||
topPadding: Theme.spacingS
|
||||
bottomPadding: Theme.spacingS
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user