1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-25 05:52:50 -05:00

Compare commits

..

13 Commits

Author SHA1 Message Date
Ivan Molodetskikh
623eec3689 Add screencast indicator for niri (#1361)
* niri: Handle new Cast events

* bar: Add screen sharing indicator

Configurable like other icons; on by default.

* lockscreen: Add screen sharing indicator
2026-01-15 00:55:21 -05:00
bbedward
53a033fe35 dankdash: fix weather open IPC
fixes #1367
2026-01-14 22:29:29 -05:00
bbedward
c490ee24f4 matugen: fix nvim ID in skipTemplates 2026-01-14 22:27:07 -05:00
bbedward
cc1e49294e i18n: update terms 2026-01-14 22:22:27 -05:00
purian23
e6fa46ae26 dankdash: Center Media Art & Controls 2026-01-14 18:03:16 -05:00
purian23
35fe774a1b Update OBS Choice selection 2026-01-13 17:51:55 -05:00
purian23
1e6a0f9423 Update OBS DMS Stable workflow 2026-01-13 17:31:01 -05:00
bbedward
cc1877aadb modals: fix wifi passowrd, polkit, and VPN import 2026-01-13 17:21:16 -05:00
bbedward
f1eb1fa9ba settings: fix child windows on newer quickshell-git 2026-01-13 16:57:23 -05:00
Lucas
bdd01e335d settings: fix modal not opening on latest quickshell (#1357) 2026-01-13 16:41:54 -05:00
Lucas
4b7baf82cd nix: escape version string (#1353) 2026-01-13 11:24:51 -05:00
purian23
15c88ce1d2 quickshell: Despace Versioning 2026-01-13 11:07:12 -05:00
bbedward
8891c388d0 bump to v1.4-unstable 2026-01-13 08:40:56 -05:00
34 changed files with 743 additions and 795 deletions

View File

@@ -4,13 +4,14 @@ on:
workflow_dispatch:
inputs:
package:
description: "Package to update (dms, dms-git, or all)"
required: false
default: "all"
tag_version:
description: "Specific tag version for dms stable (e.g., v1.0.2). Leave empty to auto-detect latest release."
required: false
default: ""
description: "Package to update"
required: true
type: choice
options:
- dms
- dms-git
- all
default: "dms"
rebuild_release:
description: "Release number for rebuilds (e.g., 2, 3, 4 to increment spec Release)"
required: false
@@ -56,8 +57,9 @@ jobs:
}
# Helper function to check dms stable tag
# Sets LATEST_TAG variable in parent scope if update needed
check_dms_stable() {
local LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "v\?\([^"]*\)".*/\1/' || echo "")
LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "")
local OBS_SPEC=$(curl -s -u "$OBS_USERNAME:$OBS_PASSWORD" "https://api.opensuse.org/source/home:AvengeMedia:dms/dms/dms.spec" 2>/dev/null || echo "")
local OBS_VERSION=$(echo "$OBS_SPEC" | grep "^Version:" | awk '{print $2}' | xargs || echo "")
@@ -73,8 +75,8 @@ jobs:
# Main logic
REBUILD="${{ github.event.inputs.rebuild_release }}"
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/ ]]; then
# Tag push - always update stable package
if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
# Tag selected or pushed - always update stable package
echo "packages=dms" >> $GITHUB_OUTPUT
VERSION="${GITHUB_REF#refs/tags/}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
@@ -104,7 +106,12 @@ jobs:
# Check each package and build list of those needing updates
PACKAGES_TO_UPDATE=()
check_dms_git && PACKAGES_TO_UPDATE+=("dms-git")
check_dms_stable && PACKAGES_TO_UPDATE+=("dms")
if check_dms_stable; then
PACKAGES_TO_UPDATE+=("dms")
if [[ -n "$LATEST_TAG" ]]; then
echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT
fi
fi
if [[ ${#PACKAGES_TO_UPDATE[@]} -gt 0 ]]; then
echo "packages=${PACKAGES_TO_UPDATE[*]}" >> $GITHUB_OUTPUT
@@ -129,6 +136,9 @@ jobs:
if check_dms_stable; then
echo "packages=$PKG" >> $GITHUB_OUTPUT
echo "has_updates=true" >> $GITHUB_OUTPUT
if [[ -n "$LATEST_TAG" ]]; then
echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT
fi
else
echo "packages=" >> $GITHUB_OUTPUT
echo "has_updates=false" >> $GITHUB_OUTPUT
@@ -161,12 +171,19 @@ jobs:
- name: Determine packages to update
id: packages
run: |
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/ ]]; then
# Tag push event - use the pushed tag
# Check if GITHUB_REF points to a tag (works for both push events and workflow_dispatch with tag selected)
if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
# Tag selected or pushed - use the tag from GITHUB_REF
echo "packages=dms" >> $GITHUB_OUTPUT
VERSION="${GITHUB_REF#refs/tags/}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Triggered by tag: $VERSION"
echo "Using tag from GITHUB_REF: $VERSION"
# Check if check-updates already determined a version (from auto-detection)
elif [[ -n "${{ needs.check-updates.outputs.version }}" ]]; then
# Use version from check-updates job
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
echo "version=${{ needs.check-updates.outputs.version }}" >> $GITHUB_OUTPUT
echo "Using version from check-updates: ${{ needs.check-updates.outputs.version }}"
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
# Scheduled run - dms-git only
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
@@ -176,22 +193,28 @@ jobs:
# Determine version for dms stable
if [[ "${{ github.event.inputs.package }}" == "dms" ]]; then
# For explicit dms selection, require tag_version
if [[ -n "${{ github.event.inputs.tag_version }}" ]]; then
VERSION="${{ github.event.inputs.tag_version }}"
# Use github.ref if tag selected, otherwise auto-detect latest
if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Using specified tag: $VERSION"
echo "Using tag from GITHUB_REF: $VERSION"
else
echo "ERROR: tag_version is required when package=dms"
echo "Please specify a tag version (e.g., v1.0.2) or use package=all for auto-detection"
exit 1
# Auto-detect latest release for dms
LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "")
if [[ -n "$LATEST_TAG" ]]; then
echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT
echo "Auto-detected latest release: $LATEST_TAG"
else
echo "ERROR: Could not auto-detect latest release"
exit 1
fi
fi
elif [[ "${{ github.event.inputs.package }}" == "all" ]]; then
# For "all", auto-detect if tag_version not specified
if [[ -n "${{ github.event.inputs.tag_version }}" ]]; then
VERSION="${{ github.event.inputs.tag_version }}"
# Use github.ref if tag selected, otherwise auto-detect latest
if [[ "${{ github.ref }}" =~ ^refs/tags/ ]]; then
VERSION="${GITHUB_REF#refs/tags/}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Using specified tag: $VERSION"
echo "Using tag from GITHUB_REF: $VERSION"
else
# Auto-detect latest release for "all"
LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "")
@@ -206,7 +229,7 @@ jobs:
fi
# Use filtered packages from check-updates when package="all" and no rebuild/tag specified
if [[ "${{ github.event.inputs.package }}" == "all" ]] && [[ -z "${{ github.event.inputs.rebuild_release }}" ]] && [[ -z "${{ github.event.inputs.tag_version }}" ]]; then
if [[ "${{ github.event.inputs.package }}" == "all" ]] && [[ -z "${{ github.event.inputs.rebuild_release }}" ]] && [[ ! "${{ github.ref }}" =~ ^refs/tags/ ]]; then
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
echo "Manual trigger: all (filtered to: ${{ needs.check-updates.outputs.packages }})"
else
@@ -215,6 +238,9 @@ jobs:
fi
else
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
if [[ -n "${{ needs.check-updates.outputs.version }}" ]]; then
echo "version=${{ needs.check-updates.outputs.version }}" >> $GITHUB_OUTPUT
fi
fi
- name: Update dms-git spec version

View File

@@ -87,8 +87,6 @@ var (
swayVersionRegex = regexp.MustCompile(`sway version (\d+\.\d+)`)
riverVersionRegex = regexp.MustCompile(`river (\d+\.\d+)`)
wayfireVersionRegex = regexp.MustCompile(`wayfire (\d+\.\d+)`)
labwcVersionRegex = regexp.MustCompile(`labwc (\d+\.\d+\.\d+)`)
mangowcVersionRegex = regexp.MustCompile(`mango (\d+\.\d+\.\d+)`)
)
var doctorCmd = &cobra.Command{
@@ -450,13 +448,11 @@ func checkWindowManagers() []checkResult {
versionRegex *regexp.Regexp
commands []string
}{
{"Hyprland", "Hyprland", "--version", hyprlandVersionRegex, []string{"hyprland", "Hyprland"}},
{"Hyprland", "hyprctl", "version", hyprlandVersionRegex, []string{"hyprland", "Hyprland"}},
{"niri", "niri", "--version", niriVersionRegex, []string{"niri"}},
{"Sway", "sway", "--version", swayVersionRegex, []string{"sway"}},
{"River", "river", "-version", riverVersionRegex, []string{"river"}},
{"Wayfire", "wayfire", "--version", wayfireVersionRegex, []string{"wayfire"}},
{"labwc", "labwc", "--version", labwcVersionRegex, []string{"labwc"}},
{"mangowc", "mango", "-v", mangowcVersionRegex, []string{"mango"}},
}
var results []checkResult
@@ -481,7 +477,7 @@ func checkWindowManagers() []checkResult {
results = append(results, checkResult{
catCompositor, c.name, statusOK,
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
doctorDocsURL + "#compositor-checks",
doctorDocsURL + "#compositor",
})
}
@@ -490,7 +486,7 @@ func checkWindowManagers() []checkResult {
catCompositor, "Compositor", statusError,
"No supported Wayland compositor found",
"Install Hyprland, niri, Sway, River, or Wayfire",
doctorDocsURL + "#compositor-checks",
doctorDocsURL + "#compositor",
})
}
@@ -502,8 +498,8 @@ func checkWindowManagers() []checkResult {
}
func getVersionFromCommand(cmd, arg string, regex *regexp.Regexp) string {
output, err := exec.Command(cmd, arg).CombinedOutput()
if err != nil && len(output) == 0 {
output, err := exec.Command(cmd, arg).Output()
if err != nil {
return "installed"
}
@@ -638,14 +634,19 @@ func checkI2CAvailability() checkResult {
return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"}
}
func detectNetworkBackend(stackResult *network.DetectResult) string {
switch stackResult.Backend {
func detectNetworkBackend() string {
result, err := network.DetectNetworkStack()
if err != nil {
return ""
}
switch result.Backend {
case network.BackendNetworkManager:
return "NetworkManager"
case network.BackendIwd:
return "iwd"
case network.BackendNetworkd:
if stackResult.HasIwd {
if result.HasIwd {
return "iwd + systemd-networkd"
}
return "systemd-networkd"
@@ -656,73 +657,75 @@ func detectNetworkBackend(stackResult *network.DetectResult) string {
}
}
func getOptionalDBusStatus(busName string) (status, string) {
if utils.IsDBusServiceAvailable(busName) {
return statusOK, "Available"
} else {
return statusWarn, "Not available"
}
}
func checkOptionalDependencies() []checkResult {
var results []checkResult
optionalFeaturesURL := doctorDocsURL + "#optional-features"
if utils.IsServiceActive("accounts-daemon", false) {
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusOK, "Running", "User accounts", doctorDocsURL + "#optional-features"})
} else {
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusWarn, "Not running", "User accounts", doctorDocsURL + "#optional-features"})
}
accountsStatus, accountsMsg := getOptionalDBusStatus("org.freedesktop.Accounts")
results = append(results, checkResult{catOptionalFeatures, "accountsservice", accountsStatus, accountsMsg, "User accounts", optionalFeaturesURL})
ppdStatus, ppdMsg := getOptionalDBusStatus("org.freedesktop.UPower.PowerProfiles")
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", ppdStatus, ppdMsg, "Power profile management", optionalFeaturesURL})
logindStatus, logindMsg := getOptionalDBusStatus("org.freedesktop.login1")
results = append(results, checkResult{catOptionalFeatures, "logind", logindStatus, logindMsg, "Session management", optionalFeaturesURL})
if utils.IsServiceActive("power-profiles-daemon", false) {
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusOK, "Running", "Power profile management", doctorDocsURL + "#optional-features"})
} else {
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusInfo, "Not running", "Power profile management", doctorDocsURL + "#optional-features"})
}
results = append(results, checkI2CAvailability())
terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"}
if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 {
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", optionalFeaturesURL})
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", doctorDocsURL + "#optional-features"})
} else {
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", optionalFeaturesURL})
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", doctorDocsURL + "#optional-features"})
}
networkResult, err := network.DetectNetworkStack()
networkStatus, networkMessage, networkDetails := statusOK, "Not available", "Network management"
if err == nil && networkResult.Backend != network.BackendNone {
networkMessage = detectNetworkBackend(networkResult)
if doctorVerbose {
networkDetails = networkResult.ChosenReason
}
} else {
networkStatus = statusInfo
}
results = append(results, checkResult{catOptionalFeatures, "Network", networkStatus, networkMessage, networkDetails, optionalFeaturesURL})
deps := []struct {
name, cmd, desc string
important bool
name, cmd, altCmd, desc string
important bool
}{
{"matugen", "matugen", "Dynamic theming", true},
{"dgop", "dgop", "System monitoring", true},
{"cava", "cava", "Audio visualizer", true},
{"khal", "khal", "Calendar events", false},
{"danksearch", "dsearch", "File search", false},
{"fprintd", "fprintd-list", "Fingerprint auth", false},
{"matugen", "matugen", "", "Dynamic theming", true},
{"dgop", "dgop", "", "System monitoring", true},
{"cava", "cava", "", "Audio visualizer", true},
{"khal", "khal", "", "Calendar events", false},
{"Network", "nmcli", "iwctl", "Network management", false},
{"danksearch", "dsearch", "", "File search", false},
{"loginctl", "loginctl", "", "Session management", false},
{"fprintd", "fprintd-list", "", "Fingerprint auth", false},
}
for _, d := range deps {
found := utils.CommandExists(d.cmd)
found, foundCmd := utils.CommandExists(d.cmd), d.cmd
if !found && d.altCmd != "" && utils.CommandExists(d.altCmd) {
found, foundCmd = true, d.altCmd
}
switch {
case found:
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, "Installed", d.desc, optionalFeaturesURL})
message := "Installed"
details := d.desc
if d.name == "Network" {
result, err := network.DetectNetworkStack()
if err == nil && result.Backend != network.BackendNone {
message = detectNetworkBackend() + " (active)"
if doctorVerbose {
details = result.ChosenReason
}
} else {
switch foundCmd {
case "nmcli":
message = "NetworkManager (installed)"
case "iwctl":
message = "iwd (installed)"
}
}
}
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, message, details, doctorDocsURL + "#optional-features"})
case d.important:
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, optionalFeaturesURL})
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, doctorDocsURL + "#optional-features"})
default:
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, optionalFeaturesURL})
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, doctorDocsURL + "#optional-features"})
}
}
@@ -890,10 +893,6 @@ func printResultLine(r checkResult, styles tui.Styles) {
if doctorVerbose && r.details != "" {
fmt.Printf(" %s\n", styles.Subtle.Render("└─ "+r.details))
}
if (r.status == statusError || r.status == statusWarn) && r.url != "" {
fmt.Printf(" %s\n", styles.Subtle.Render("→ "+r.url))
}
}
func printSummary(results []checkResult, qsMissingFeatures bool) {

View File

@@ -108,6 +108,7 @@ func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManag
packages := map[string]PackageMapping{
// Standard zypper packages
"git": {Name: "git", Repository: RepoTypeSystem},
"ghostty": {Name: "ghostty", Repository: RepoTypeSystem},
"kitty": {Name: "kitty", Repository: RepoTypeSystem},
"alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
"xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
@@ -116,7 +117,6 @@ func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManag
// DMS packages from OBS
"dms (DankMaterialShell)": o.getDmsMapping(variants["dms (DankMaterialShell)"]),
"quickshell": o.getQuickshellMapping(variants["quickshell"]),
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
}

View File

@@ -1,20 +0,0 @@
package utils
import (
"github.com/godbus/dbus/v5"
)
func IsDBusServiceAvailable(busName string) bool {
conn, err := dbus.ConnectSystemBus()
if err != nil {
return false
}
defer conn.Close()
obj := conn.Object("org.freedesktop.DBus", "/org/freedesktop/DBus")
var owned bool
if err := obj.Call("org.freedesktop.DBus.NameHasOwner", 0, busName).Store(&owned); err != nil {
return false
}
return owned
}

View File

@@ -2,6 +2,7 @@ package utils
import (
"os/exec"
"strings"
)
type AppChecker interface {
@@ -42,3 +43,16 @@ func AnyCommandExists(cmds ...string) bool {
}
return false
}
func IsServiceActive(name string, userService bool) bool {
if !CommandExists("systemctl") {
return false
}
args := []string{"is-active", name}
if userService {
args = []string{"--user", "is-active", name}
}
output, _ := exec.Command("systemctl", args...).Output()
return strings.EqualFold(strings.TrimSpace(string(output)), "active")
}

View File

@@ -11,18 +11,12 @@ let
inherit (config.services.greetd.settings.default_session) user;
compositorPackage =
let
configured = lib.attrByPath [ "programs" cfg.compositor.name "package" ] null config;
in
if configured != null then configured else builtins.getAttr cfg.compositor.name pkgs;
cacheDir = "/var/lib/dms-greeter";
greeterScript = pkgs.writeShellScriptBin "dms-greeter" ''
export PATH=$PATH:${
lib.makeBinPath [
cfg.quickshell.package
compositorPackage
config.programs.${cfg.compositor.name}.package
]
}
${
@@ -70,7 +64,6 @@ in
"niri"
"hyprland"
"sway"
"labwc"
];
description = "Compositor to run greeter in";
};

View File

@@ -73,13 +73,6 @@ in
default = hasPluginSettings;
description = ''Whether to manage plugin settings. Automatically enabled if any plugins have settings configured.'';
};
systemd.target = lib.mkOption {
type = lib.types.str;
default = config.wayland.systemd.target;
defaultText = lib.literalExpression "config.wayland.systemd.target";
description = "Systemd target to bind to.";
};
};
config = lib.mkIf cfg.enable {
@@ -91,8 +84,8 @@ in
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
Unit = {
Description = "DankMaterialShell";
PartOf = [ cfg.systemd.target ];
After = [ cfg.systemd.target ];
PartOf = [ config.wayland.systemd.target ];
After = [ config.wayland.systemd.target ];
};
Service = {
@@ -100,7 +93,7 @@ in
Restart = "on-failure";
};
Install.WantedBy = [ cfg.systemd.target ];
Install.WantedBy = [ config.wayland.systemd.target ];
};
xdg.stateFile."DankMaterialShell/session.json" = lib.mkIf (cfg.session != { }) {

View File

@@ -20,19 +20,15 @@ in
imports = [
(import ./options.nix args)
];
options.programs.dank-material-shell.systemd.target = lib.mkOption {
type = lib.types.str;
description = "Systemd target to bind to.";
default = "graphical-session.target";
};
config = lib.mkIf cfg.enable {
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
description = "DankMaterialShell";
path = lib.mkForce [ ];
partOf = [ cfg.systemd.target ];
after = [ cfg.systemd.target ];
wantedBy = [ cfg.systemd.target ];
partOf = [ "graphical-session.target" ];
after = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
restartIfChanged = cfg.systemd.restartIfChanged;
serviceConfig = {

View File

@@ -1 +1 @@
Spicy Miso
Saffron Bloom

View File

@@ -45,10 +45,6 @@ Singleton {
Quickshell.execDetached(["cp", strip(from), strip(to)]);
}
function isSteamApp(appId: string): bool {
return appId && /^steam_app_\d+$/.test(appId);
}
function moddedAppId(appId: string): string {
const subs = SettingsData.appIdSubstitutions || [];
for (let i = 0; i < subs.length; i++) {
@@ -64,9 +60,6 @@ Singleton {
}
}
}
const steamMatch = appId.match(/^steam_app_(\d+)$/);
if (steamMatch)
return `steam_icon_${steamMatch[1]}`;
return appId;
}

View File

@@ -82,19 +82,15 @@ Singleton {
popoutOpening();
}
let movedFromOtherScreen = false;
let justClosedSamePopout = false;
for (const otherScreenName in currentPopoutsByScreen) {
if (otherScreenName === screenName)
continue;
const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout)
continue;
if (otherPopout === popout) {
movedFromOtherScreen = true;
currentPopoutsByScreen[otherScreenName] = null;
currentPopoutTriggers[otherScreenName] = null;
continue;
justClosedSamePopout = true;
}
if (otherPopout.dashVisible !== undefined) {
@@ -116,7 +112,7 @@ Singleton {
}
}
if (currentPopout === popout && popout.shouldBeVisible && !movedFromOtherScreen) {
if (currentPopout === popout && popout.shouldBeVisible) {
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
if (popout.dashVisible !== undefined) {
popout.dashVisible = false;
@@ -143,7 +139,6 @@ Singleton {
popout.currentTabIndex = tabIndex;
}
currentPopoutTriggers[screenName] = triggerId;
return;
}
currentPopoutTriggers[screenName] = triggerId;
@@ -158,8 +153,16 @@ Singleton {
ModalManager.closeAllModalsExcept(null);
}
if (movedFromOtherScreen) {
popout.open();
if (justClosedSamePopout) {
Qt.callLater(() => {
if (popout.dashVisible !== undefined) {
popout.dashVisible = true;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true;
} else {
popout.open();
}
});
} else {
if (popout.dashVisible !== undefined) {
popout.dashVisible = true;

View File

@@ -122,21 +122,6 @@ Rectangle {
contentHeight: audioColumn.height
clip: true
property int maxPinnedInputs: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedInputs() {
const pins = SettingsData.audioInputDevicePins || {}
return normalizePinList(pins["preferredInput"])
}
Column {
id: audioColumn
width: parent.width
@@ -148,20 +133,16 @@ Rectangle {
const nodes = Pipewire.nodes.values.filter(node => {
return node.audio && !node.isSink && !node.isStream;
});
const pinnedList = audioContent.getPinnedInputs();
const pins = SettingsData.audioInputDevicePins || {};
const pinnedName = pins["preferredInput"];
let sorted = [...nodes];
sorted.sort((a, b) => {
// Pinned device first
const aPinnedIndex = pinnedList.indexOf(a.name)
const bPinnedIndex = pinnedList.indexOf(b.name)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
if (a.name === pinnedName && b.name !== pinnedName)
return -1;
if (b.name === pinnedName && a.name !== pinnedName)
return 1;
// Then active device
if (a === AudioService.source && b !== AudioService.source)
return -1;
@@ -243,7 +224,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
@@ -256,7 +237,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -264,12 +245,12 @@ Rectangle {
StyledText {
text: {
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -280,24 +261,16 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}))
let pinnedList = audioContent.normalizePinList(pins["preferredInput"])
const pinIndex = pinnedList.indexOf(modelData.name)
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}));
const isCurrentlyPinned = pins["preferredInput"] === modelData.name;
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
if (isCurrentlyPinned) {
delete pins["preferredInput"];
} else {
pinnedList.unshift(modelData.name)
if (pinnedList.length > audioContent.maxPinnedInputs)
pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs)
pins["preferredInput"] = modelData.name;
}
if (pinnedList.length > 0)
pins["preferredInput"] = pinnedList
else
delete pins["preferredInput"]
SettingsData.set("audioInputDevicePins", pins)
SettingsData.set("audioInputDevicePins", pins);
}
}
}

View File

@@ -132,21 +132,6 @@ Rectangle {
contentHeight: audioColumn.height
clip: true
property int maxPinnedOutputs: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedOutputs() {
const pins = SettingsData.audioOutputDevicePins || {}
return normalizePinList(pins["preferredOutput"])
}
Column {
id: audioColumn
width: parent.width
@@ -158,20 +143,16 @@ Rectangle {
const nodes = Pipewire.nodes.values.filter(node => {
return node.audio && node.isSink && !node.isStream;
});
const pinnedList = audioContent.getPinnedOutputs();
const pins = SettingsData.audioOutputDevicePins || {};
const pinnedName = pins["preferredOutput"];
let sorted = [...nodes];
sorted.sort((a, b) => {
// Pinned device first
const aPinnedIndex = pinnedList.indexOf(a.name)
const bPinnedIndex = pinnedList.indexOf(b.name)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
if (a.name === pinnedName && b.name !== pinnedName)
return -1;
if (b.name === pinnedName && a.name !== pinnedName)
return 1;
// Then active device
if (a === AudioService.sink && b !== AudioService.sink)
return -1;
@@ -255,7 +236,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
@@ -268,7 +249,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -276,12 +257,12 @@ Rectangle {
StyledText {
text: {
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -292,24 +273,16 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}))
let pinnedList = audioContent.normalizePinList(pins["preferredOutput"])
const pinIndex = pinnedList.indexOf(modelData.name)
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}));
const isCurrentlyPinned = pins["preferredOutput"] === modelData.name;
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
if (isCurrentlyPinned) {
delete pins["preferredOutput"];
} else {
pinnedList.unshift(modelData.name)
if (pinnedList.length > audioContent.maxPinnedOutputs)
pinnedList = pinnedList.slice(0, audioContent.maxPinnedOutputs)
pins["preferredOutput"] = modelData.name;
}
if (pinnedList.length > 0)
pins["preferredOutput"] = pinnedList
else
delete pins["preferredOutput"]
SettingsData.set("audioOutputDevicePins", pins)
SettingsData.set("audioOutputDevicePins", pins);
}
}
}

View File

@@ -150,21 +150,6 @@ Rectangle {
contentHeight: bluetoothColumn.height
clip: true
property int maxPinnedDevices: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedDevices() {
const pins = SettingsData.bluetoothDevicePins || {}
return normalizePinList(pins["preferredDevice"])
}
Column {
id: bluetoothColumn
width: parent.width
@@ -177,18 +162,14 @@ Rectangle {
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
return []
const pinnedList = bluetoothContent.getPinnedDevices()
const pins = SettingsData.bluetoothDevicePins || {}
const pinnedAddr = pins["preferredDevice"]
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
devices.sort((a, b) => {
// Pinned device first
const aPinnedIndex = pinnedList.indexOf(a.address)
const bPinnedIndex = pinnedList.indexOf(b.address)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1) return 1
if (bPinnedIndex === -1) return -1
return aPinnedIndex - bPinnedIndex
}
if (a.address === pinnedAddr && b.address !== pinnedAddr) return -1
if (b.address === pinnedAddr && a.address !== pinnedAddr) return 1
// Then connected devices
if (a.connected && !b.connected) return -1
if (!a.connected && b.connected) return 1
@@ -321,7 +302,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05)
}
@@ -334,7 +315,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
@@ -342,12 +323,12 @@ Rectangle {
StyledText {
text: {
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin")
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
}
anchors.verticalCenter: parent.verticalCenter
@@ -359,21 +340,13 @@ Rectangle {
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.bluetoothDevicePins || {}))
let pinnedList = bluetoothContent.normalizePinList(pins["preferredDevice"])
const pinIndex = pinnedList.indexOf(modelData.address)
const isCurrentlyPinned = pins["preferredDevice"] === modelData.address
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pinnedList.unshift(modelData.address)
if (pinnedList.length > bluetoothContent.maxPinnedDevices)
pinnedList = pinnedList.slice(0, bluetoothContent.maxPinnedDevices)
}
if (pinnedList.length > 0)
pins["preferredDevice"] = pinnedList
else
if (isCurrentlyPinned) {
delete pins["preferredDevice"]
} else {
pins["preferredDevice"] = modelData.address
}
SettingsData.set("bluetoothDevicePins", pins)
}

View File

@@ -463,39 +463,20 @@ Rectangle {
contentHeight: wifiColumn.height
clip: true
property int maxPinnedNetworks: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedNetworks() {
const pins = SettingsData.wifiNetworkPins || {}
return normalizePinList(pins["preferredWifi"])
}
property var frozenNetworks: []
property bool menuOpen: false
property var sortedNetworks: {
const ssid = NetworkService.currentWifiSSID;
const networks = NetworkService.wifiNetworks;
const pinnedList = getPinnedNetworks()
const pins = SettingsData.wifiNetworkPins || {};
const pinnedSSID = pins["preferredWifi"];
let sorted = [...networks];
sorted.sort((a, b) => {
const aPinnedIndex = pinnedList.indexOf(a.ssid)
const bPinnedIndex = pinnedList.indexOf(b.ssid)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID)
return -1;
if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID)
return 1;
if (a.ssid === ssid)
return -1;
if (b.ssid === ssid)
@@ -644,7 +625,7 @@ Rectangle {
height: 28
radius: height / 2
color: {
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
return isThisNetworkPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
}
@@ -657,7 +638,7 @@ Rectangle {
name: "push_pin"
size: 16
color: {
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -665,12 +646,12 @@ Rectangle {
StyledText {
text: {
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
return isThisNetworkPinned ? I18n.tr("Pinned") : I18n.tr("Pin");
}
font.pixelSize: Theme.fontSizeSmall
color: {
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
}
anchors.verticalCenter: parent.verticalCenter
@@ -681,24 +662,16 @@ Rectangle {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}))
let pinnedList = wifiContent.normalizePinList(pins["preferredWifi"])
const pinIndex = pinnedList.indexOf(modelData.ssid)
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
const isCurrentlyPinned = pins["preferredWifi"] === modelData.ssid;
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
if (isCurrentlyPinned) {
delete pins["preferredWifi"];
} else {
pinnedList.unshift(modelData.ssid)
if (pinnedList.length > wifiContent.maxPinnedNetworks)
pinnedList = pinnedList.slice(0, wifiContent.maxPinnedNetworks)
pins["preferredWifi"] = modelData.ssid;
}
if (pinnedList.length > 0)
pins["preferredWifi"] = pinnedList
else
delete pins["preferredWifi"]
SettingsData.set("wifiNetworkPins", pins)
SettingsData.set("wifiNetworkPins", pins);
}
}
}

View File

@@ -29,7 +29,6 @@ BasePill {
property real micAccumulator: 0
property real volumeAccumulator: 0
property real brightnessAccumulator: 0
readonly property real vIconSize: Theme.barIconSize(root.barThickness, -4)
Loader {
active: root.showPrinterIcon
@@ -215,25 +214,7 @@ BasePill {
}
function hasNoVisibleIcons() {
if (root.showScreenSharingIcon && NiriService.hasCasts)
return false;
if (root.showNetworkIcon && NetworkService.networkAvailable)
return false;
if (root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected)
return false;
if (root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled)
return false;
if (root.showAudioIcon)
return false;
if (root.showMicIcon)
return false;
if (root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice())
return false;
if (root.showBatteryIcon && BatteryService.batteryAvailable)
return false;
if (root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs())
return false;
return true;
return !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon && !root.showVpnIcon && !root.showBrightnessIcon && !root.showMicIcon && !root.showBatteryIcon && !root.showPrinterIcon && !root.showScreenSharingIcon;
}
content: Component {
@@ -244,74 +225,56 @@ BasePill {
Column {
id: controlColumn
visible: root.isVerticalOrientation
width: root.vIconSize
anchors.horizontalCenter: parent.horizontalCenter
anchors.centerIn: parent
spacing: Theme.spacingXS
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: "screen_record"
size: Theme.barIconSize(root.barThickness, -4)
color: NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showScreenSharingIcon && NiriService.hasCasts
DankIcon {
name: "screen_record"
size: root.vIconSize
color: NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
}
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: root.getNetworkIconName()
size: Theme.barIconSize(root.barThickness, -4)
color: root.getNetworkIconColor()
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showNetworkIcon && NetworkService.networkAvailable
DankIcon {
name: root.getNetworkIconName()
size: root.vIconSize
color: root.getNetworkIconColor()
anchors.centerIn: parent
}
}
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: "vpn_lock"
size: Theme.barIconSize(root.barThickness, -4)
color: NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
DankIcon {
name: "vpn_lock"
size: root.vIconSize
color: NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
}
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: "bluetooth"
size: Theme.barIconSize(root.barThickness, -4)
color: BluetoothService.connected ? Theme.primary : Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled
DankIcon {
name: "bluetooth"
size: root.vIconSize
color: BluetoothService.connected ? Theme.primary : Theme.surfaceText
anchors.centerIn: parent
}
}
Item {
width: root.vIconSize
height: root.vIconSize + (root.showAudioPercent ? audioPercentV.implicitHeight + 2 : 0)
Rectangle {
width: audioIconV.implicitWidth + 4
height: audioIconV.implicitHeight + (root.showAudioPercent ? audioPercentV.implicitHeight : 0) + 4
color: "transparent"
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showAudioIcon
DankIcon {
id: audioIconV
name: root.getVolumeIconName()
size: root.vIconSize
size: Theme.barIconSize(root.barThickness, -4)
color: Theme.widgetIconColor
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 2
}
StyledText {
@@ -338,18 +301,21 @@ BasePill {
}
}
Item {
width: root.vIconSize
height: root.vIconSize + (root.showMicPercent ? micPercentV.implicitHeight + 2 : 0)
Rectangle {
width: micIconV.implicitWidth + 4
height: micIconV.implicitHeight + (root.showAudioPercent ? micPercentV.implicitHeight : 0) + 4
color: "transparent"
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showMicIcon
DankIcon {
id: micIconV
name: root.getMicIconName()
size: root.vIconSize
size: Theme.barIconSize(root.barThickness, -4)
color: root.getMicIconColor()
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 2
}
StyledText {
@@ -376,18 +342,21 @@ BasePill {
}
}
Item {
width: root.vIconSize
height: root.vIconSize + (root.showBrightnessPercent ? brightnessPercentV.implicitHeight + 2 : 0)
Rectangle {
width: brightnessIconV.implicitWidth + 4
height: brightnessIconV.implicitHeight + (root.showBrightnessPercent ? brightnessPercentV.implicitHeight : 0) + 4
color: "transparent"
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
DankIcon {
id: brightnessIconV
name: root.getBrightnessIconName()
size: root.vIconSize
size: Theme.barIconSize(root.barThickness, -4)
color: Theme.widgetIconColor
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 2
}
StyledText {
@@ -411,43 +380,28 @@ BasePill {
}
}
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
size: Theme.barIconSize(root.barThickness, -4)
color: root.getBatteryIconColor()
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showBatteryIcon && BatteryService.batteryAvailable
DankIcon {
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
size: root.vIconSize
color: root.getBatteryIconColor()
anchors.centerIn: parent
}
}
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: "print"
size: Theme.barIconSize(root.barThickness, -4)
color: Theme.primary
anchors.horizontalCenter: parent.horizontalCenter
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
DankIcon {
name: "print"
size: root.vIconSize
color: Theme.primary
anchors.centerIn: parent
}
}
Item {
width: root.vIconSize
height: root.vIconSize
DankIcon {
name: "settings"
size: Theme.barIconSize(root.barThickness, -4)
color: root.isActive ? Theme.primary : Theme.widgetIconColor
anchors.horizontalCenter: parent.horizontalCenter
visible: root.hasNoVisibleIcons()
DankIcon {
name: "settings"
size: root.vIconSize
color: root.isActive ? Theme.primary : Theme.widgetIconColor
anchors.centerIn: parent
}
}
}

View File

@@ -155,17 +155,9 @@ BasePill {
}
}
DankIcon {
anchors.centerIn: parent
size: 18
name: "sports_esports"
color: Theme.widgetTextColor
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && Paths.isSteamApp(activeWindow.appId)
}
Text {
anchors.centerIn: parent
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && !Paths.isSteamApp(activeWindow.appId)
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready
text: {
if (!activeWindow || !activeWindow.appId)
return "?";

View File

@@ -393,19 +393,9 @@ Item {
}
}
DankIcon {
anchors.left: parent.left
anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness)) / 2) : Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
size: Theme.barIconSize(root.barThickness)
name: "sports_esports"
color: Theme.widgetTextColor
visible: !iconImg.visible && Paths.isSteamApp(appId)
}
Text {
anchors.centerIn: parent
visible: !iconImg.visible && !Paths.isSteamApp(appId)
visible: !iconImg.visible
text: {
root._desktopEntriesUpdateTrigger;
if (!appId)
@@ -638,19 +628,9 @@ Item {
}
}
DankIcon {
anchors.left: parent.left
anchors.leftMargin: (widgetData?.runningAppsCompactMode !== undefined ? widgetData.runningAppsCompactMode : SettingsData.runningAppsCompactMode) ? Math.round((parent.width - Theme.barIconSize(root.barThickness)) / 2) : Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
size: Theme.barIconSize(root.barThickness)
name: "sports_esports"
color: Theme.widgetTextColor
visible: !iconImg.visible && Paths.isSteamApp(appId)
}
Text {
anchors.centerIn: parent
visible: !iconImg.visible && !Paths.isSteamApp(appId)
visible: !iconImg.visible
text: {
root._desktopEntriesUpdateTrigger;
if (!appId)

View File

@@ -265,7 +265,6 @@ Item {
if (!byApp[key]) {
const isQuickshell = keyBase === "org.quickshell";
const isSteamApp = Paths.isSteamApp(keyBase);
const moddedId = Paths.moddedAppId(keyBase);
const desktopEntry = DesktopEntries.heuristicLookup(moddedId);
const icon = Paths.getAppIcon(keyBase, desktopEntry);
@@ -273,7 +272,6 @@ Item {
"type": "icon",
"icon": icon,
"isQuickshell": isQuickshell,
"isSteamApp": isSteamApp,
"active": !!((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)),
"count": 1,
"windowId": w.address || w.id,
@@ -1137,7 +1135,7 @@ Item {
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
visible: !modelData.isQuickshell && !modelData.isSteamApp
visible: !modelData.isQuickshell
}
IconImage {
@@ -1153,22 +1151,6 @@ Item {
}
}
IconImage {
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp && modelData.icon
}
DankIcon {
anchors.centerIn: parent
size: root.appIconSize
name: "sports_esports"
color: Theme.widgetTextColor
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp && !modelData.icon
}
MouseArea {
id: rowAppMouseArea
anchors.fill: parent
@@ -1247,7 +1229,7 @@ Item {
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
visible: !modelData.isQuickshell && !modelData.isSteamApp
visible: !modelData.isQuickshell
}
IconImage {
@@ -1263,22 +1245,6 @@ Item {
}
}
IconImage {
anchors.fill: parent
source: modelData.icon
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp && modelData.icon
}
DankIcon {
anchors.centerIn: parent
size: root.appIconSize
name: "sports_esports"
color: Theme.widgetTextColor
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
visible: modelData.isSteamApp && !modelData.icon
}
MouseArea {
id: colAppMouseArea
anchors.fill: parent

View File

@@ -403,7 +403,7 @@ Item {
width: actualIconSize
height: actualIconSize
anchors.centerIn: parent
visible: iconImg.status !== Image.Ready && appData && appData.appId && !Paths.isSteamApp(appData.appId)
visible: iconImg.status !== Image.Ready
color: Theme.surfaceLight
radius: Theme.cornerRadius
border.width: 1
@@ -425,14 +425,6 @@ Item {
}
}
DankIcon {
anchors.centerIn: parent
size: actualIconSize
name: "sports_esports"
color: Theme.surfaceText
visible: iconImg.status !== Image.Ready && appData && appData.appId && Paths.isSteamApp(appData.appId)
}
Loader {
anchors.horizontalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.horizontalCenter
anchors.verticalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? parent.verticalCenter : undefined

View File

@@ -2,6 +2,8 @@
set -e
export WLR_DRM_DEVICES=/dev/dri/card1
COMPOSITOR=""
COMPOSITOR_CONFIG=""
DMS_PATH="dms-greeter"
@@ -14,7 +16,7 @@ dms-greeter - DankMaterialShell greeter launcher
Usage: dms-greeter --command COMPOSITOR [OPTIONS]
Required:
--command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll, mangowc, or labwc)
--command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll or mangowc)
Options:
-C, --config PATH Custom compositor config file
@@ -31,7 +33,6 @@ Examples:
dms-greeter --command scroll -p /home/user/.config/quickshell/custom-dms
dms-greeter --command niri --cache-dir /tmp/dmsgreeter
dms-greeter --command mangowc
dms-greeter --command labwc
EOF
}
@@ -230,15 +231,6 @@ SCROLL_EOF
exec scroll -c "$COMPOSITOR_CONFIG"
;;
labwc)
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
exec labwc --config "$COMPOSITOR_CONFIG" --session "$QS_CMD"
else
exec labwc --session "$QS_CMD"
fi
;;
mangowc)
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
exec mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit"
@@ -249,7 +241,7 @@ SCROLL_EOF
*)
echo "Error: Unsupported compositor: $COMPOSITOR" >&2
echo "Supported compositors: niri, hyprland, sway, scroll, mangowc, labwc" >&2
echo "Supported compositors: niri, hyprland, sway, mangowc" >&2
exit 1
;;
esac

View File

@@ -262,7 +262,9 @@ DankOSD {
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
function onVolumeChanged() {
vertSlider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100));
if (!vertSlider.dragging) {
vertSlider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100));
}
}
}
}

View File

@@ -177,11 +177,10 @@ Item {
StyledText {
text: {
if (!SystemUpdateService.shellVersion && !DMSService.cliVersion)
if (!SystemUpdateService.shellVersion)
return "dms";
let version = SystemUpdateService.shellVersion || "";
let cliVersion = DMSService.cliVersion || "";
let version = SystemUpdateService.shellVersion;
// Debian/Ubuntu/OpenSUSE git format: 1.0.3+git2264.c5c5ce84
let match = version.match(/^([\d.]+)\+git(\d+)\./);
@@ -192,25 +191,7 @@ Item {
// Fedora COPR git format: 0.0.git.2267.d430cae9
match = version.match(/^[\d.]+\.git\.(\d+)\./);
if (match) {
function extractBaseVersion(value) {
if (!value)
return "";
let baseMatch = value.match(/(\d+\.\d+\.\d+)/);
if (baseMatch)
return baseMatch[1];
baseMatch = value.match(/(\d+\.\d+)/);
if (baseMatch)
return baseMatch[1];
return "";
}
let baseVersion = extractBaseVersion(cliVersion);
if (!baseVersion)
baseVersion = extractBaseVersion(SystemUpdateService.semverVersion);
if (baseVersion) {
return `dms (git) v${baseVersion}-${match[1]}`;
}
return `dms (git) v${match[1]}`;
return `dms (git) v1.0.3-${match[1]}`;
}
// Stable release format: 1.0.3
@@ -219,18 +200,6 @@ Item {
return `dms v${match[1]}`;
}
if (!version && cliVersion) {
match = cliVersion.match(/^([\d.]+)\+git(\d+)\./);
if (match) {
return `dms (git) v${match[1]}-${match[2]}`;
}
match = cliVersion.match(/^([\d.]+)$/);
if (match) {
return `dms v${match[1]}`;
}
return `dms ${cliVersion}`;
}
return `dms ${version}`;
}
font.pixelSize: Theme.fontSizeXLarge

View File

@@ -29,9 +29,6 @@ Item {
SettingsButtonGroupRow {
text: I18n.tr("Position")
model: ["Top", "Bottom", "Left", "Right"]
buttonPadding: Theme.spacingS
minButtonWidth: 44
textSize: Theme.fontSizeSmall
currentIndex: {
switch (SettingsData.dockPosition) {
case SettingsData.Position.Top:
@@ -132,9 +129,6 @@ Item {
tags: ["dock", "indicator", "style", "circle", "line"]
text: I18n.tr("Indicator Style")
model: ["Circle", "Line"]
buttonPadding: Theme.spacingS
minButtonWidth: 44
textSize: Theme.fontSizeSmall
currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1
onSelectionChanged: (index, selected) => {
if (selected) {
@@ -231,9 +225,6 @@ Item {
description: I18n.tr("Choose the border accent color")
visible: SettingsData.dockBorderEnabled
model: ["Surface", "Secondary", "Primary"]
buttonPadding: Theme.spacingS
minButtonWidth: 44
textSize: Theme.fontSizeSmall
currentIndex: {
switch (SettingsData.dockBorderColor) {
case "surfaceText":

View File

@@ -15,7 +15,6 @@ Item {
property string expandedVpnUuid: ""
property string expandedWifiSsid: ""
property string expandedEthDevice: ""
property int maxPinnedWifiNetworks: 3
Component.onCompleted: {
NetworkService.addRef();
@@ -31,40 +30,6 @@ Item {
vpnFileBrowserLoader.item.open();
}
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v)
if (typeof value === "string" && value.length > 0)
return [value]
return []
}
function getPinnedWifiNetworks() {
const pins = SettingsData.wifiNetworkPins || {}
return normalizePinList(pins["preferredWifi"])
}
function toggleWifiPin(ssid) {
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}))
let pinnedList = normalizePinList(pins["preferredWifi"])
const pinIndex = pinnedList.indexOf(ssid)
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1)
} else {
pinnedList.unshift(ssid)
if (pinnedList.length > maxPinnedWifiNetworks)
pinnedList = pinnedList.slice(0, maxPinnedWifiNetworks)
}
if (pinnedList.length > 0)
pins["preferredWifi"] = pinnedList
else
delete pins["preferredWifi"]
SettingsData.set("wifiNetworkPins", pins)
}
LazyLoader {
id: vpnFileBrowserLoader
active: false
@@ -1060,19 +1025,15 @@ Item {
model: {
const ssid = NetworkService.currentWifiSSID;
const networks = NetworkService.wifiNetworks || [];
const pinnedList = networkTab.getPinnedWifiNetworks();
const pins = SettingsData.wifiNetworkPins || {};
const pinnedSSID = pins["preferredWifi"];
let sorted = [...networks];
sorted.sort((a, b) => {
const aPinnedIndex = pinnedList.indexOf(a.ssid)
const bPinnedIndex = pinnedList.indexOf(b.ssid)
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1
if (bPinnedIndex === -1)
return -1
return aPinnedIndex - bPinnedIndex
}
if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID)
return -1;
if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID)
return 1;
if (a.ssid === ssid)
return -1;
if (b.ssid === ssid)
@@ -1088,7 +1049,7 @@ Item {
required property int index
readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID
readonly property bool isPinned: networkTab.getPinnedWifiNetworks().includes(modelData.ssid)
readonly property bool isPinned: (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid
readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid
width: parent.width
@@ -1263,7 +1224,13 @@ Item {
buttonSize: 28
iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText
onClicked: {
networkTab.toggleWifiPin(modelData.ssid)
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
if (isPinned) {
delete pins["preferredWifi"];
} else {
pins["preferredWifi"] = modelData.ssid;
}
SettingsData.set("wifiNetworkPins", pins);
}
}

View File

@@ -270,9 +270,7 @@ FloatingWindow {
root.updateFilteredPlugins();
return;
}
thirdPartyConfirmLoader.active = true;
if (thirdPartyConfirmLoader.item)
thirdPartyConfirmLoader.item.show();
thirdPartyConfirmModal.visible = true;
}
}
@@ -670,132 +668,119 @@ FloatingWindow {
}
}
LazyLoader {
id: thirdPartyConfirmLoader
active: false
FloatingWindow {
id: thirdPartyConfirmModal
FloatingWindow {
id: thirdPartyConfirmModal
objectName: "thirdPartyConfirm"
title: I18n.tr("Third-Party Plugin Warning")
implicitWidth: 500
implicitHeight: 350
color: Theme.surfaceContainer
visible: false
function show() {
visible = true;
}
FocusScope {
anchors.fill: parent
focus: true
function hide() {
visible = false;
}
objectName: "thirdPartyConfirm"
title: I18n.tr("Third-Party Plugin Warning")
implicitWidth: 500
implicitHeight: 350
color: Theme.surfaceContainer
visible: false
FocusScope {
anchors.fill: parent
focus: true
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
thirdPartyConfirmModal.hide();
event.accepted = true;
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
thirdPartyConfirmModal.visible = false;
event.accepted = true;
}
}
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
Row {
width: parent.width
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "warning"
size: Theme.iconSize
color: Theme.warning
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Third-Party Plugin Warning")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - parent.spacing * 2 - Theme.iconSize - parent.children[1].implicitWidth - closeConfirmBtn.width
height: 1
}
DankActionButton {
id: closeConfirmBtn
iconName: "close"
iconSize: Theme.iconSize - 2
iconColor: Theme.outline
anchors.verticalCenter: parent.verticalCenter
onClicked: thirdPartyConfirmModal.hide()
}
DankIcon {
name: "warning"
size: Theme.iconSize
color: Theme.warning
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
width: parent.width
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
text: I18n.tr("Third-Party Plugin Warning")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
wrapMode: Text.WordWrap
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("• Plugins may contain bugs or security issues")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: I18n.tr("• Review code before installation when possible")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: I18n.tr("• Install only from trusted sources")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width
height: parent.height - parent.spacing * 3 - y
width: parent.width - parent.spacing * 2 - Theme.iconSize - parent.children[1].implicitWidth - closeConfirmBtn.width
height: 1
}
Row {
anchors.right: parent.right
spacing: Theme.spacingM
DankActionButton {
id: closeConfirmBtn
iconName: "close"
iconSize: Theme.iconSize - 2
iconColor: Theme.outline
anchors.verticalCenter: parent.verticalCenter
onClicked: thirdPartyConfirmModal.visible = false
}
}
DankButton {
text: I18n.tr("Cancel")
iconName: "close"
onClicked: thirdPartyConfirmModal.hide()
}
StyledText {
width: parent.width
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
}
DankButton {
text: I18n.tr("I Understand")
iconName: "check"
onClicked: {
SessionData.setShowThirdPartyPlugins(true);
root.updateFilteredPlugins();
thirdPartyConfirmModal.hide();
}
Column {
width: parent.width
spacing: Theme.spacingS
StyledText {
text: I18n.tr("• Plugins may contain bugs or security issues")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: I18n.tr("• Review code before installation when possible")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: I18n.tr("• Install only from trusted sources")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Item {
width: parent.width
height: parent.height - parent.spacing * 3 - y
}
Row {
anchors.right: parent.right
spacing: Theme.spacingM
DankButton {
text: I18n.tr("Cancel")
iconName: "close"
onClicked: thirdPartyConfirmModal.visible = false
}
DankButton {
text: I18n.tr("I Understand")
iconName: "check"
onClicked: {
SessionData.setShowThirdPartyPlugins(true);
root.updateFilteredPlugins();
thirdPartyConfirmModal.visible = false;
}
}
}

View File

@@ -51,7 +51,6 @@ StyledRect {
Row {
spacing: Theme.spacingM
width: parent.width
DankIcon {
id: headerIcon
@@ -70,8 +69,6 @@ StyledRect {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
visible: root.title !== ""
width: parent.width - (headerIcon.visible ? headerIcon.width + parent.spacing : 0)
horizontalAlignment: Text.AlignLeft
}
}

View File

@@ -402,24 +402,6 @@ Item {
setWidgetsForSection(sectionId, widgets);
}
function cloneWidgetData(widget) {
if (typeof widget === "string")
return {
"id": widget,
"enabled": true
};
var result = {
"id": widget.id,
"enabled": widget.enabled
};
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon"];
for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]];
}
return result;
}
function handleItemEnabledChanged(sectionId, itemId, enabled) {
var widgets = getWidgetsForSection(sectionId).slice();
for (var i = 0; i < widgets.length; i++) {
@@ -427,8 +409,43 @@ Item {
var widgetId = typeof widget === "string" ? widget : widget.id;
if (widgetId !== itemId)
continue;
var newWidget = cloneWidgetData(widget);
newWidget.enabled = enabled;
if (typeof widget === "string") {
widgets[i] = {
"id": widget,
"enabled": enabled
};
break;
}
var newWidget = {
"id": widget.id,
"enabled": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
else if (widget.id === "gpuTemp")
newWidget.selectedGpuIndex = 0;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
else if (widget.id === "gpuTemp")
newWidget.pciId = "";
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon;
newWidget.showAudioIcon = widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon;
newWidget.showAudioPercent = widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent;
newWidget.showVpnIcon = widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon;
newWidget.showBrightnessIcon = widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon;
newWidget.showBrightnessPercent = widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent;
newWidget.showMicIcon = widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon;
newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent;
newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
}
widgets[i] = newWidget;
break;
}
@@ -441,36 +458,130 @@ Item {
function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length)
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var widget = widgets[widgetIndex];
var widgetId = typeof widget === "string" ? widget : widget.id;
if (widgetId !== "spacer")
if (widgetId !== "spacer") {
setWidgetsForSection(sectionId, widgets);
return;
var newWidget = cloneWidgetData(widget);
newWidget.size = newSize;
}
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"size": newSize
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"size": newSize
};
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon;
newWidget.showAudioIcon = widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon;
newWidget.showAudioPercent = widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent;
newWidget.showVpnIcon = widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon;
newWidget.showBrightnessIcon = widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon;
newWidget.showBrightnessPercent = widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent;
newWidget.showMicIcon = widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon;
newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent;
newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length)
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var pciId = DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : "";
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget.selectedGpuIndex = selectedGpuIndex;
newWidget.pciId = pciId;
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"selectedGpuIndex": selectedGpuIndex,
"pciId": pciId
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"selectedGpuIndex": selectedGpuIndex,
"pciId": pciId
};
if (widget.size !== undefined)
newWidget.size = widget.size;
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length)
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget.mountPath = mountPath;
}
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"mountPath": mountPath
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"mountPath": mountPath
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon;
newWidget.showAudioIcon = widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon;
newWidget.showAudioPercent = widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent;
newWidget.showVpnIcon = widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon;
newWidget.showBrightnessIcon = widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon;
newWidget.showBrightnessPercent = widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent;
newWidget.showMicIcon = widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon;
newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent;
newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
@@ -479,8 +590,33 @@ Item {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length)
return;
var newWidget = cloneWidgetData(widgets[widgetIndex]);
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widget = {
"id": widget,
"enabled": true
};
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled !== undefined ? widget.enabled : true,
"showNetworkIcon": widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon,
"showBluetoothIcon": widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon,
"showAudioIcon": widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon,
"showAudioPercent": widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent,
"showVpnIcon": widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon,
"showBrightnessIcon": widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon,
"showBrightnessPercent": widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent,
"showMicIcon": widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon,
"showMicPercent": widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent,
"showBatteryIcon": widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon,
"showPrinterIcon": widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon,
"showScreenSharingIcon": widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon
};
newWidget[settingName] = value;
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
@@ -505,8 +641,47 @@ Item {
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget.minimumWidth = enabled;
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"minimumWidth": enabled
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"minimumWidth": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.showSwap !== undefined)
newWidget.showSwap = widget.showSwap;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon;
newWidget.showAudioIcon = widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon;
newWidget.showAudioPercent = widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent;
newWidget.showVpnIcon = widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon;
newWidget.showBrightnessIcon = widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon;
newWidget.showBrightnessPercent = widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent;
newWidget.showMicIcon = widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon;
newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent;
newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
@@ -517,41 +692,143 @@ Item {
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = cloneWidgetData(widgets[widgetIndex]);
newWidget.showSwap = enabled;
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"showSwap": enabled
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"showSwap": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.minimumWidth !== undefined)
newWidget.minimumWidth = widget.minimumWidth;
if (widget.mediaSize !== undefined)
newWidget.mediaSize = widget.mediaSize;
if (widget.clockCompactMode !== undefined)
newWidget.clockCompactMode = widget.clockCompactMode;
if (widget.focusedWindowCompactMode !== undefined)
newWidget.focusedWindowCompactMode = widget.focusedWindowCompactMode;
if (widget.runningAppsCompactMode !== undefined)
newWidget.runningAppsCompactMode = widget.runningAppsCompactMode;
if (widget.keyboardLayoutNameCompactMode !== undefined)
newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon;
newWidget.showAudioIcon = widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon;
newWidget.showAudioPercent = widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent;
newWidget.showVpnIcon = widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon;
newWidget.showBrightnessIcon = widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon;
newWidget.showBrightnessPercent = widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent;
newWidget.showMicIcon = widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon;
newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent;
newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleCompactModeChanged(sectionId, widgetId, value) {
var widgets = getWidgetsForSection(sectionId).slice();
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i];
var currentId = typeof widget === "string" ? widget : widget.id;
if (currentId !== widgetId)
continue;
var newWidget = cloneWidgetData(widget);
if (typeof widget === "string") {
widgets[i] = {
"id": widget,
"enabled": true
};
widget = widgets[i];
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.minimumWidth !== undefined)
newWidget.minimumWidth = widget.minimumWidth;
if (widget.showSwap !== undefined)
newWidget.showSwap = widget.showSwap;
if (widget.mediaSize !== undefined)
newWidget.mediaSize = widget.mediaSize;
if (widget.clockCompactMode !== undefined)
newWidget.clockCompactMode = widget.clockCompactMode;
if (widget.focusedWindowCompactMode !== undefined)
newWidget.focusedWindowCompactMode = widget.focusedWindowCompactMode;
if (widget.runningAppsCompactMode !== undefined)
newWidget.runningAppsCompactMode = widget.runningAppsCompactMode;
if (widget.keyboardLayoutNameCompactMode !== undefined)
newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? SettingsData.controlCenterShowNetworkIcon;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? SettingsData.controlCenterShowBluetoothIcon;
newWidget.showAudioIcon = widget.showAudioIcon ?? SettingsData.controlCenterShowAudioIcon;
newWidget.showAudioPercent = widget.showAudioPercent ?? SettingsData.controlCenterShowAudioPercent;
newWidget.showVpnIcon = widget.showVpnIcon ?? SettingsData.controlCenterShowVpnIcon;
newWidget.showBrightnessIcon = widget.showBrightnessIcon ?? SettingsData.controlCenterShowBrightnessIcon;
newWidget.showBrightnessPercent = widget.showBrightnessPercent ?? SettingsData.controlCenterShowBrightnessPercent;
newWidget.showMicIcon = widget.showMicIcon ?? SettingsData.controlCenterShowMicIcon;
newWidget.showMicPercent = widget.showMicPercent ?? SettingsData.controlCenterShowMicPercent;
newWidget.showBatteryIcon = widget.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
newWidget.showPrinterIcon = widget.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
newWidget.showScreenSharingIcon = widget.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
}
widgets[i] = newWidget;
widget = newWidget;
}
switch (widgetId) {
case "music":
newWidget.mediaSize = value;
widget.mediaSize = value;
break;
case "clock":
newWidget.clockCompactMode = value;
widget.clockCompactMode = value;
break;
case "focusedWindow":
newWidget.focusedWindowCompactMode = value;
widget.focusedWindowCompactMode = value;
break;
case "runningApps":
newWidget.runningAppsCompactMode = value;
widget.runningAppsCompactMode = value;
break;
case "keyboard_layout_name":
newWidget.keyboardLayoutNameCompactMode = value;
widget.keyboardLayoutNameCompactMode = value;
break;
}
widgets[i] = newWidget;
break;
}
setWidgetsForSection(sectionId, widgets);
}

View File

@@ -31,19 +31,6 @@ Column {
signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled)
signal showSwapChanged(string sectionId, int widgetIndex, bool enabled)
function cloneWidgetData(widget) {
var result = {
"id": widget.id,
"enabled": widget.enabled
};
var keys = ["size", "selectedGpuIndex", "pciId", "mountPath", "minimumWidth", "showSwap", "mediaSize", "clockCompactMode", "focusedWindowCompactMode", "runningAppsCompactMode", "keyboardLayoutNameCompactMode", "showNetworkIcon", "showBluetoothIcon", "showAudioIcon", "showAudioPercent", "showVpnIcon", "showBrightnessIcon", "showBrightnessPercent", "showMicIcon", "showMicPercent", "showBatteryIcon", "showPrinterIcon", "showScreenSharingIcon"];
for (var i = 0; i < keys.length; i++) {
if (widget[keys[i]] !== undefined)
result[keys[i]] = widget[keys[i]];
}
return result;
}
width: parent.width
height: implicitHeight
spacing: Theme.spacingM
@@ -740,7 +727,13 @@ Column {
var newItems = root.items.slice();
var draggedItem = newItems.splice(index, 1)[0];
newItems.splice(newIndex, 0, draggedItem);
root.itemOrderChanged(newItems.map(item => root.cloneWidgetData(item)));
root.itemOrderChanged(newItems.map(item => {
return ({
"id": item.id,
"enabled": item.enabled,
"size": item.size
});
}));
}
}
delegateItem.x = 0;

View File

@@ -63,15 +63,15 @@ Item {
onToggled: checked => SettingsData.set("showWorkspaceApps", checked)
}
Item {
width: parent.width
height: maxAppsColumn.height
Row {
width: parent.width - Theme.spacingL
spacing: Theme.spacingL
visible: SettingsData.showWorkspaceApps
opacity: visible ? 1 : 0
anchors.left: parent.left
anchors.leftMargin: Theme.spacingL
Column {
id: maxAppsColumn
x: Theme.spacingL
width: 120
spacing: Theme.spacingS
@@ -80,15 +80,14 @@ Item {
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
horizontalAlignment: Text.AlignLeft
}
DankTextField {
width: 100
height: 28
placeholderText: "3"
placeholderText: "#ffffff"
text: SettingsData.maxWorkspaceIcons
maximumLength: 2
maximumLength: 7
font.pixelSize: Theme.fontSizeSmall
topPadding: Theme.spacingXS
bottomPadding: Theme.spacingXS

View File

@@ -11,7 +11,7 @@ Singleton {
id: root
readonly property string currentVersion: "1.2"
readonly property bool changelogEnabled: true
readonly property bool changelogEnabled: false
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion

View File

@@ -287,14 +287,11 @@ Singleton {
return false;
}
if (isDaemon) {
const newDaemons = Object.assign({}, pluginDaemonComponents);
newDaemons[pluginId] = comp;
pluginDaemonComponents = newDaemons;
} else if (isLauncher) {
// MODIFICATION: Treat Launchers as persistent instances like Daemons
if (isDaemon || isLauncher) {
const instance = comp.createObject(root, {
"pluginId": pluginId,
"pluginService": root
"pluginService": root // Inject PluginService
});
if (!instance) {
console.error("PluginService: failed to instantiate plugin:", pluginId, comp.errorString());
@@ -305,9 +302,15 @@ Singleton {
newInstances[pluginId] = instance;
pluginInstances = newInstances;
const newLaunchers = Object.assign({}, pluginLauncherComponents);
newLaunchers[pluginId] = comp;
pluginLauncherComponents = newLaunchers;
if (isDaemon) {
const newDaemons = Object.assign({}, pluginDaemonComponents);
newDaemons[pluginId] = comp;
pluginDaemonComponents = newDaemons;
} else {
const newLaunchers = Object.assign({}, pluginLauncherComponents);
newLaunchers[pluginId] = comp;
pluginLauncherComponents = newLaunchers;
}
} else if (isDesktop) {
const newDesktop = Object.assign({}, pluginDesktopComponents);
newDesktop[pluginId] = comp;

View File

@@ -754,7 +754,7 @@ Singleton {
"humidity": Math.round(hourly.relative_humidity_2m?.[i] || 0),
"wind": Math.round(hourly.wind_speed_10m?.[i] || 0),
"pressure": Math.round(hourly.surface_pressure?.[i] || 0),
"precipitationProbability": Math.round(hourly.precipitation_probability?.[i] || 0),
"precipitationProbability": Math.round(hourly.precipitation_probability_max?.[0] || 0),
"visibility": Math.round(hourly.visibility?.[i] || 0),
"isDay": isDay
});

View File

@@ -1 +1 @@
v1.2.3
v1.4-unstable