mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 07:22:50 -05:00
Compare commits
69 Commits
5ae2cd1dfb
...
stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7cdb39b0b | ||
|
|
0ceba92a23 | ||
|
|
4daa7a4c88 | ||
|
|
cc4a6a5899 | ||
|
|
994947477c | ||
|
|
311817ee97 | ||
|
|
b80c73f9b9 | ||
|
|
a85101c099 | ||
|
|
3513d57e06 | ||
|
|
1234847abb | ||
|
|
0ed595b43d | ||
|
|
060cbefc79 | ||
|
|
e022c04519 | ||
|
|
f534384e5e | ||
|
|
a25cdb43d5 | ||
|
|
4e9b4ca400 | ||
|
|
5bab1c98b1 | ||
|
|
2284bb002f | ||
|
|
b0611d6104 | ||
|
|
27965862d6 | ||
|
|
e74a901e05 | ||
|
|
77794deb2c | ||
|
|
1c10746e50 | ||
|
|
8ecb7282b9 | ||
|
|
9b3fa804ab | ||
|
|
b2ad31a27e | ||
|
|
db17e4cb14 | ||
|
|
1b7dcf56a8 | ||
|
|
502bb88e92 | ||
|
|
b76d0ce97d | ||
|
|
fa66d330cf | ||
|
|
157eab2d07 | ||
|
|
f50ad2dc22 | ||
|
|
cd9d92d884 | ||
|
|
1b69a5e62b | ||
|
|
61d311b157 | ||
|
|
6b76b86930 | ||
|
|
dcfb947c36 | ||
|
|
59893b7f44 | ||
|
|
d2c62f5533 | ||
|
|
2bbe9a0c45 | ||
|
|
4e2ce82c0a | ||
|
|
104762186f | ||
|
|
f1233ab1e3 | ||
|
|
d6b407ec37 | ||
|
|
022b4b4bb3 | ||
|
|
49b322582d | ||
|
|
1280bd047d | ||
|
|
6f206d7523 | ||
|
|
2e58283859 | ||
|
|
99a5721fe8 | ||
|
|
5302ebd840 | ||
|
|
fa427ea1ac | ||
|
|
7027bd1646 | ||
|
|
3c38e17472 | ||
|
|
510ea5d2e4 | ||
|
|
bb2234d328 | ||
|
|
edbdeb0fb8 | ||
|
|
19541fc573 | ||
|
|
7c936cacfb | ||
|
|
c60cd3a341 | ||
|
|
e37135f80d | ||
|
|
aac937cbcc | ||
|
|
4b46d022af | ||
|
|
7f0181b310 | ||
|
|
6a109274f8 | ||
|
|
0f09cc693a | ||
|
|
af0166a553 | ||
|
|
a283017f26 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -109,3 +109,4 @@ bin/
|
|||||||
.envrc
|
.envrc
|
||||||
.direnv/
|
.direnv/
|
||||||
quickshell/dms-plugins
|
quickshell/dms-plugins
|
||||||
|
__pycache__
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ var (
|
|||||||
swayVersionRegex = regexp.MustCompile(`sway version (\d+\.\d+)`)
|
swayVersionRegex = regexp.MustCompile(`sway version (\d+\.\d+)`)
|
||||||
riverVersionRegex = regexp.MustCompile(`river (\d+\.\d+)`)
|
riverVersionRegex = regexp.MustCompile(`river (\d+\.\d+)`)
|
||||||
wayfireVersionRegex = regexp.MustCompile(`wayfire (\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{
|
var doctorCmd = &cobra.Command{
|
||||||
@@ -448,11 +450,13 @@ func checkWindowManagers() []checkResult {
|
|||||||
versionRegex *regexp.Regexp
|
versionRegex *regexp.Regexp
|
||||||
commands []string
|
commands []string
|
||||||
}{
|
}{
|
||||||
{"Hyprland", "hyprctl", "version", hyprlandVersionRegex, []string{"hyprland", "Hyprland"}},
|
{"Hyprland", "Hyprland", "--version", hyprlandVersionRegex, []string{"hyprland", "Hyprland"}},
|
||||||
{"niri", "niri", "--version", niriVersionRegex, []string{"niri"}},
|
{"niri", "niri", "--version", niriVersionRegex, []string{"niri"}},
|
||||||
{"Sway", "sway", "--version", swayVersionRegex, []string{"sway"}},
|
{"Sway", "sway", "--version", swayVersionRegex, []string{"sway"}},
|
||||||
{"River", "river", "-version", riverVersionRegex, []string{"river"}},
|
{"River", "river", "-version", riverVersionRegex, []string{"river"}},
|
||||||
{"Wayfire", "wayfire", "--version", wayfireVersionRegex, []string{"wayfire"}},
|
{"Wayfire", "wayfire", "--version", wayfireVersionRegex, []string{"wayfire"}},
|
||||||
|
{"labwc", "labwc", "--version", labwcVersionRegex, []string{"labwc"}},
|
||||||
|
{"mangowc", "mango", "-v", mangowcVersionRegex, []string{"mango"}},
|
||||||
}
|
}
|
||||||
|
|
||||||
var results []checkResult
|
var results []checkResult
|
||||||
@@ -477,7 +481,7 @@ func checkWindowManagers() []checkResult {
|
|||||||
results = append(results, checkResult{
|
results = append(results, checkResult{
|
||||||
catCompositor, c.name, statusOK,
|
catCompositor, c.name, statusOK,
|
||||||
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
|
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
|
||||||
doctorDocsURL + "#compositor",
|
doctorDocsURL + "#compositor-checks",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -486,7 +490,7 @@ func checkWindowManagers() []checkResult {
|
|||||||
catCompositor, "Compositor", statusError,
|
catCompositor, "Compositor", statusError,
|
||||||
"No supported Wayland compositor found",
|
"No supported Wayland compositor found",
|
||||||
"Install Hyprland, niri, Sway, River, or Wayfire",
|
"Install Hyprland, niri, Sway, River, or Wayfire",
|
||||||
doctorDocsURL + "#compositor",
|
doctorDocsURL + "#compositor-checks",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,8 +502,8 @@ func checkWindowManagers() []checkResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getVersionFromCommand(cmd, arg string, regex *regexp.Regexp) string {
|
func getVersionFromCommand(cmd, arg string, regex *regexp.Regexp) string {
|
||||||
output, err := exec.Command(cmd, arg).Output()
|
output, err := exec.Command(cmd, arg).CombinedOutput()
|
||||||
if err != nil {
|
if err != nil && len(output) == 0 {
|
||||||
return "installed"
|
return "installed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -634,19 +638,14 @@ func checkI2CAvailability() checkResult {
|
|||||||
return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"}
|
return checkResult{catOptionalFeatures, "I2C/DDC", statusOK, fmt.Sprintf("%d monitor(s) detected", len(devices)), "External monitor brightness control", doctorDocsURL + "#optional-features"}
|
||||||
}
|
}
|
||||||
|
|
||||||
func detectNetworkBackend() string {
|
func detectNetworkBackend(stackResult *network.DetectResult) string {
|
||||||
result, err := network.DetectNetworkStack()
|
switch stackResult.Backend {
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
switch result.Backend {
|
|
||||||
case network.BackendNetworkManager:
|
case network.BackendNetworkManager:
|
||||||
return "NetworkManager"
|
return "NetworkManager"
|
||||||
case network.BackendIwd:
|
case network.BackendIwd:
|
||||||
return "iwd"
|
return "iwd"
|
||||||
case network.BackendNetworkd:
|
case network.BackendNetworkd:
|
||||||
if result.HasIwd {
|
if stackResult.HasIwd {
|
||||||
return "iwd + systemd-networkd"
|
return "iwd + systemd-networkd"
|
||||||
}
|
}
|
||||||
return "systemd-networkd"
|
return "systemd-networkd"
|
||||||
@@ -657,75 +656,73 @@ func detectNetworkBackend() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOptionalDBusStatus(busName string) (status, string) {
|
||||||
|
if utils.IsDBusServiceAvailable(busName) {
|
||||||
|
return statusOK, "Available"
|
||||||
|
} else {
|
||||||
|
return statusWarn, "Not available"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkOptionalDependencies() []checkResult {
|
func checkOptionalDependencies() []checkResult {
|
||||||
var results []checkResult
|
var results []checkResult
|
||||||
|
|
||||||
if utils.IsServiceActive("accounts-daemon", false) {
|
optionalFeaturesURL := doctorDocsURL + "#optional-features"
|
||||||
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"})
|
|
||||||
}
|
|
||||||
|
|
||||||
if utils.IsServiceActive("power-profiles-daemon", false) {
|
accountsStatus, accountsMsg := getOptionalDBusStatus("org.freedesktop.Accounts")
|
||||||
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusOK, "Running", "Power profile management", doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, "accountsservice", accountsStatus, accountsMsg, "User accounts", optionalFeaturesURL})
|
||||||
} else {
|
|
||||||
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusInfo, "Not running", "Power profile management", doctorDocsURL + "#optional-features"})
|
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})
|
||||||
|
|
||||||
results = append(results, checkI2CAvailability())
|
results = append(results, checkI2CAvailability())
|
||||||
|
|
||||||
terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"}
|
terminals := []string{"ghostty", "kitty", "alacritty", "foot", "wezterm"}
|
||||||
if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 {
|
if idx := slices.IndexFunc(terminals, utils.CommandExists); idx >= 0 {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", optionalFeaturesURL})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", optionalFeaturesURL})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
deps := []struct {
|
||||||
name, cmd, altCmd, desc string
|
name, cmd, desc string
|
||||||
important bool
|
important bool
|
||||||
}{
|
}{
|
||||||
{"matugen", "matugen", "", "Dynamic theming", true},
|
{"matugen", "matugen", "Dynamic theming", true},
|
||||||
{"dgop", "dgop", "", "System monitoring", true},
|
{"dgop", "dgop", "System monitoring", true},
|
||||||
{"cava", "cava", "", "Audio visualizer", true},
|
{"cava", "cava", "Audio visualizer", true},
|
||||||
{"khal", "khal", "", "Calendar events", false},
|
{"khal", "khal", "Calendar events", false},
|
||||||
{"Network", "nmcli", "iwctl", "Network management", false},
|
{"danksearch", "dsearch", "File search", false},
|
||||||
{"danksearch", "dsearch", "", "File search", false},
|
{"fprintd", "fprintd-list", "Fingerprint auth", false},
|
||||||
{"loginctl", "loginctl", "", "Session management", false},
|
|
||||||
{"fprintd", "fprintd-list", "", "Fingerprint auth", false},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range deps {
|
for _, d := range deps {
|
||||||
found, foundCmd := utils.CommandExists(d.cmd), d.cmd
|
found := utils.CommandExists(d.cmd)
|
||||||
if !found && d.altCmd != "" && utils.CommandExists(d.altCmd) {
|
|
||||||
found, foundCmd = true, d.altCmd
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case found:
|
case found:
|
||||||
message := "Installed"
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, "Installed", d.desc, optionalFeaturesURL})
|
||||||
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:
|
case d.important:
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, optionalFeaturesURL})
|
||||||
default:
|
default:
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, doctorDocsURL + "#optional-features"})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, optionalFeaturesURL})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,6 +890,10 @@ func printResultLine(r checkResult, styles tui.Styles) {
|
|||||||
if doctorVerbose && r.details != "" {
|
if doctorVerbose && r.details != "" {
|
||||||
fmt.Printf(" %s\n", styles.Subtle.Render("└─ "+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) {
|
func printSummary(results []checkResult, qsMissingFeatures bool) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ bind = SUPER, N, exec, dms ipc call notifications toggle
|
|||||||
bind = SUPER SHIFT, N, exec, dms ipc call notepad toggle
|
bind = SUPER SHIFT, N, exec, dms ipc call notepad toggle
|
||||||
bind = SUPER, Y, exec, dms ipc call dankdash wallpaper
|
bind = SUPER, Y, exec, dms ipc call dankdash wallpaper
|
||||||
bind = SUPER, TAB, exec, dms ipc call hypr toggleOverview
|
bind = SUPER, TAB, exec, dms ipc call hypr toggleOverview
|
||||||
|
bind = SUPER, X, exec, dms ipc call powermenu toggle
|
||||||
|
|
||||||
# === Cheat sheet
|
# === Cheat sheet
|
||||||
bind = SUPER SHIFT, Slash, exec, dms ipc call keybinds toggle hyprland
|
bind = SUPER SHIFT, Slash, exec, dms ipc call keybinds toggle hyprland
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ binds {
|
|||||||
Mod+M hotkey-overlay-title="Task Manager" {
|
Mod+M hotkey-overlay-title="Task Manager" {
|
||||||
spawn "dms" "ipc" "call" "processlist" "focusOrToggle";
|
spawn "dms" "ipc" "call" "processlist" "focusOrToggle";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Super+X hotkey-overlay-title="Power Menu: Toggle" { spawn "dms" "ipc" "call" "powermenu" "toggle"; }
|
||||||
Mod+Comma hotkey-overlay-title="Settings" {
|
Mod+Comma hotkey-overlay-title="Settings" {
|
||||||
spawn "dms" "ipc" "call" "settings" "focusOrToggle";
|
spawn "dms" "ipc" "call" "settings" "focusOrToggle";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,6 @@ func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManag
|
|||||||
packages := map[string]PackageMapping{
|
packages := map[string]PackageMapping{
|
||||||
// Standard zypper packages
|
// Standard zypper packages
|
||||||
"git": {Name: "git", Repository: RepoTypeSystem},
|
"git": {Name: "git", Repository: RepoTypeSystem},
|
||||||
"ghostty": {Name: "ghostty", Repository: RepoTypeSystem},
|
|
||||||
"kitty": {Name: "kitty", Repository: RepoTypeSystem},
|
"kitty": {Name: "kitty", Repository: RepoTypeSystem},
|
||||||
"alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
|
"alacritty": {Name: "alacritty", Repository: RepoTypeSystem},
|
||||||
"xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
|
"xdg-desktop-portal-gtk": {Name: "xdg-desktop-portal-gtk", Repository: RepoTypeSystem},
|
||||||
@@ -117,6 +116,7 @@ func (o *OpenSUSEDistribution) GetPackageMappingWithVariants(wm deps.WindowManag
|
|||||||
// DMS packages from OBS
|
// DMS packages from OBS
|
||||||
"dms (DankMaterialShell)": o.getDmsMapping(variants["dms (DankMaterialShell)"]),
|
"dms (DankMaterialShell)": o.getDmsMapping(variants["dms (DankMaterialShell)"]),
|
||||||
"quickshell": o.getQuickshellMapping(variants["quickshell"]),
|
"quickshell": o.getQuickshellMapping(variants["quickshell"]),
|
||||||
|
"ghostty": {Name: "ghostty", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"matugen": {Name: "matugen", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
"dgop": {Name: "dgop", Repository: RepoTypeOBS, RepoURL: "home:AvengeMedia:danklinux"},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -325,24 +325,30 @@ func (n *NiriProvider) buildActionFromNode(bindNode *document.Node) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
actionNode := bindNode.Children[0]
|
actionNode := bindNode.Children[0]
|
||||||
|
actionName := actionNode.Name.String()
|
||||||
kdlStr := strings.TrimSpace(actionNode.String())
|
if actionName == "" {
|
||||||
if kdlStr == "" {
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.kdlActionToInternal(kdlStr)
|
parts := []string{actionName}
|
||||||
}
|
for _, arg := range actionNode.Arguments {
|
||||||
|
val := arg.ValueString()
|
||||||
func (n *NiriProvider) kdlActionToInternal(kdlAction string) string {
|
if val == "" {
|
||||||
parts := n.parseActionParts(kdlAction)
|
parts = append(parts, `""`)
|
||||||
if len(parts) == 0 {
|
} else {
|
||||||
return kdlAction
|
parts = append(parts, val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, part := range parts {
|
if actionNode.Properties != nil {
|
||||||
if part == "" {
|
if val, ok := actionNode.Properties.Get("focus"); ok {
|
||||||
parts[i] = `""`
|
parts = append(parts, "focus="+val.String())
|
||||||
|
}
|
||||||
|
if val, ok := actionNode.Properties.Get("show-pointer"); ok {
|
||||||
|
parts = append(parts, "show-pointer="+val.String())
|
||||||
|
}
|
||||||
|
if val, ok := actionNode.Properties.Get("write-to-disk"); ok {
|
||||||
|
parts = append(parts, "write-to-disk="+val.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ output_path = '%s'
|
|||||||
appendVSCodeConfig(cfgFile, "codeoss", filepath.Join(homeDir, ".config/Code - OSS/extensions"), opts.ShellDir)
|
appendVSCodeConfig(cfgFile, "codeoss", filepath.Join(homeDir, ".config/Code - OSS/extensions"), opts.ShellDir)
|
||||||
appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions"), opts.ShellDir)
|
appendVSCodeConfig(cfgFile, "cursor", filepath.Join(homeDir, ".cursor/extensions"), opts.ShellDir)
|
||||||
appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions"), opts.ShellDir)
|
appendVSCodeConfig(cfgFile, "windsurf", filepath.Join(homeDir, ".windsurf/extensions"), opts.ShellDir)
|
||||||
|
appendVSCodeConfig(cfgFile, "vscode-insiders", filepath.Join(homeDir, ".vscode-insiders/extensions"), opts.ShellDir)
|
||||||
default:
|
default:
|
||||||
appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile)
|
appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,27 +124,23 @@ func (sc *SharedContext) eventDispatcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
sc.drainCmdQueue()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-sc.stopChan:
|
case <-sc.stopChan:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.drainCmdQueue()
|
_, err := unix.Poll(pollFds, -1)
|
||||||
|
switch {
|
||||||
n, err := unix.Poll(pollFds, 50)
|
case err == unix.EINTR:
|
||||||
if err != nil {
|
continue
|
||||||
if err == unix.EINTR {
|
case err != nil:
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Errorf("Poll error: %v", err)
|
log.Errorf("Poll error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if pollFds[1].Revents&unix.POLLIN != 0 {
|
if pollFds[1].Revents&unix.POLLIN != 0 {
|
||||||
var buf [64]byte
|
var buf [64]byte
|
||||||
if _, err := unix.Read(sc.wakeR, buf[:]); err != nil && err != unix.EAGAIN {
|
if _, err := unix.Read(sc.wakeR, buf[:]); err != nil && err != unix.EAGAIN {
|
||||||
@@ -152,13 +148,13 @@ func (sc *SharedContext) eventDispatcher() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pollFds[0].Revents&unix.POLLIN != 0 {
|
if pollFds[0].Revents&unix.POLLIN == 0 {
|
||||||
if err := ctx.Dispatch(); err != nil {
|
continue
|
||||||
if !os.IsTimeout(err) {
|
}
|
||||||
log.Errorf("Wayland connection error: %v", err)
|
|
||||||
return
|
if err := ctx.Dispatch(); err != nil && !os.IsTimeout(err) {
|
||||||
}
|
log.Errorf("Wayland connection error: %v", err)
|
||||||
}
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,12 +172,16 @@ func (sc *SharedContext) drainCmdQueue() {
|
|||||||
|
|
||||||
func (sc *SharedContext) Close() {
|
func (sc *SharedContext) Close() {
|
||||||
close(sc.stopChan)
|
close(sc.stopChan)
|
||||||
|
if _, err := unix.Write(sc.wakeW, []byte{1}); err != nil && err != unix.EAGAIN {
|
||||||
|
log.Errorf("wake pipe write error on close: %v", err)
|
||||||
|
}
|
||||||
sc.wg.Wait()
|
sc.wg.Wait()
|
||||||
|
|
||||||
unix.Close(sc.wakeR)
|
unix.Close(sc.wakeR)
|
||||||
unix.Close(sc.wakeW)
|
unix.Close(sc.wakeW)
|
||||||
|
|
||||||
if sc.display != nil {
|
if sc.display == nil {
|
||||||
sc.display.Context().Close()
|
return
|
||||||
}
|
}
|
||||||
|
sc.display.Context().Close()
|
||||||
}
|
}
|
||||||
|
|||||||
20
core/internal/utils/dbus.go
Normal file
20
core/internal/utils/dbus.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppChecker interface {
|
type AppChecker interface {
|
||||||
@@ -43,16 +42,3 @@ func AnyCommandExists(cmds ...string) bool {
|
|||||||
}
|
}
|
||||||
return false
|
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")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ in
|
|||||||
]
|
]
|
||||||
++ lib.optional cfg.enableDynamicTheming pkgs.matugen
|
++ lib.optional cfg.enableDynamicTheming pkgs.matugen
|
||||||
++ lib.optional cfg.enableAudioWavelength pkgs.cava
|
++ lib.optional cfg.enableAudioWavelength pkgs.cava
|
||||||
++ lib.optional cfg.enableCalendarEvents pkgs.khal;
|
++ lib.optional cfg.enableCalendarEvents pkgs.khal
|
||||||
|
++ lib.optional cfg.enableClipboardPaste pkgs.wtype;
|
||||||
|
|
||||||
plugins = lib.mapAttrs (name: plugin: {
|
plugins = lib.mapAttrs (name: plugin: {
|
||||||
source = plugin.src;
|
source = plugin.src;
|
||||||
|
|||||||
@@ -11,12 +11,18 @@ let
|
|||||||
|
|
||||||
inherit (config.services.greetd.settings.default_session) user;
|
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";
|
cacheDir = "/var/lib/dms-greeter";
|
||||||
greeterScript = pkgs.writeShellScriptBin "dms-greeter" ''
|
greeterScript = pkgs.writeShellScriptBin "dms-greeter" ''
|
||||||
export PATH=$PATH:${
|
export PATH=$PATH:${
|
||||||
lib.makeBinPath [
|
lib.makeBinPath [
|
||||||
cfg.quickshell.package
|
cfg.quickshell.package
|
||||||
config.programs.${cfg.compositor.name}.package
|
compositorPackage
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
${
|
${
|
||||||
@@ -64,6 +70,7 @@ in
|
|||||||
"niri"
|
"niri"
|
||||||
"hyprland"
|
"hyprland"
|
||||||
"sway"
|
"sway"
|
||||||
|
"labwc"
|
||||||
];
|
];
|
||||||
description = "Compositor to run greeter in";
|
description = "Compositor to run greeter in";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,6 +73,13 @@ in
|
|||||||
default = hasPluginSettings;
|
default = hasPluginSettings;
|
||||||
description = ''Whether to manage plugin settings. Automatically enabled if any plugins have settings configured.'';
|
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 {
|
config = lib.mkIf cfg.enable {
|
||||||
@@ -84,8 +91,8 @@ in
|
|||||||
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
||||||
Unit = {
|
Unit = {
|
||||||
Description = "DankMaterialShell";
|
Description = "DankMaterialShell";
|
||||||
PartOf = [ config.wayland.systemd.target ];
|
PartOf = [ cfg.systemd.target ];
|
||||||
After = [ config.wayland.systemd.target ];
|
After = [ cfg.systemd.target ];
|
||||||
};
|
};
|
||||||
|
|
||||||
Service = {
|
Service = {
|
||||||
@@ -93,7 +100,7 @@ in
|
|||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
};
|
};
|
||||||
|
|
||||||
Install.WantedBy = [ config.wayland.systemd.target ];
|
Install.WantedBy = [ cfg.systemd.target ];
|
||||||
};
|
};
|
||||||
|
|
||||||
xdg.stateFile."DankMaterialShell/session.json" = lib.mkIf (cfg.session != { }) {
|
xdg.stateFile."DankMaterialShell/session.json" = lib.mkIf (cfg.session != { }) {
|
||||||
|
|||||||
@@ -20,15 +20,19 @@ in
|
|||||||
imports = [
|
imports = [
|
||||||
(import ./options.nix args)
|
(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 {
|
config = lib.mkIf cfg.enable {
|
||||||
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
systemd.user.services.dms = lib.mkIf cfg.systemd.enable {
|
||||||
description = "DankMaterialShell";
|
description = "DankMaterialShell";
|
||||||
path = lib.mkForce [ ];
|
path = lib.mkForce [ ];
|
||||||
|
|
||||||
partOf = [ "graphical-session.target" ];
|
partOf = [ cfg.systemd.target ];
|
||||||
after = [ "graphical-session.target" ];
|
after = [ cfg.systemd.target ];
|
||||||
wantedBy = [ "graphical-session.target" ];
|
wantedBy = [ cfg.systemd.target ];
|
||||||
restartIfChanged = cfg.systemd.restartIfChanged;
|
restartIfChanged = cfg.systemd.restartIfChanged;
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
|||||||
@@ -70,6 +70,12 @@ in
|
|||||||
description = "Add calendar events support via khal";
|
description = "Add calendar events support via khal";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enableClipboardPaste = lib.mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Adds needed dependencies for directly pasting items from the clipboard history.";
|
||||||
|
};
|
||||||
|
|
||||||
quickshell = {
|
quickshell = {
|
||||||
package = lib.mkPackageOption dmsPkgs "quickshell" {
|
package = lib.mkPackageOption dmsPkgs "quickshell" {
|
||||||
extraDescription = "The quickshell package to use (defaults to be built from source, due to unreleased features used by DMS).";
|
extraDescription = "The quickshell package to use (defaults to be built from source, due to unreleased features used by DMS).";
|
||||||
|
|||||||
14
flake.nix
14
flake.nix
@@ -61,11 +61,13 @@
|
|||||||
(builtins.substring 6 2 longDate)
|
(builtins.substring 6 2 longDate)
|
||||||
];
|
];
|
||||||
version =
|
version =
|
||||||
pkgs.lib.removePrefix "v" (pkgs.lib.trim (builtins.readFile ./quickshell/VERSION))
|
let
|
||||||
+ "+date="
|
rawVersion = pkgs.lib.removePrefix "v" (pkgs.lib.trim (builtins.readFile ./quickshell/VERSION));
|
||||||
+ mkDate (self.lastModifiedDate or "19700101")
|
cleanVersion = builtins.replaceStrings [ " " ] [ "" ] rawVersion;
|
||||||
+ "_"
|
dateSuffix = "+date=" + mkDate (self.lastModifiedDate or "19700101");
|
||||||
+ (self.shortRev or "dirty");
|
revSuffix = "_" + (self.shortRev or "dirty");
|
||||||
|
in
|
||||||
|
"${cleanVersion}${dateSuffix}${revSuffix}";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
dms-shell = pkgs.buildGoModule (
|
dms-shell = pkgs.buildGoModule (
|
||||||
@@ -83,7 +85,7 @@
|
|||||||
ldflags = [
|
ldflags = [
|
||||||
"-s"
|
"-s"
|
||||||
"-w"
|
"-w"
|
||||||
"-X main.Version=${version}"
|
"-X 'main.Version=${version}'"
|
||||||
];
|
];
|
||||||
|
|
||||||
nativeBuildInputs = with pkgs; [
|
nativeBuildInputs = with pkgs; [
|
||||||
|
|||||||
@@ -450,10 +450,7 @@ const NIRI_ACTION_ARGS = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"screenshot-window": {
|
"screenshot-window": {
|
||||||
args: [
|
args: [{ name: "write-to-disk", type: "bool", label: "Save to disk" }]
|
||||||
{ name: "show-pointer", type: "bool", label: "Show pointer" },
|
|
||||||
{ name: "write-to-disk", type: "bool", label: "Save to disk" }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -841,7 +838,7 @@ function getActionType(action) {
|
|||||||
return "compositor";
|
return "compositor";
|
||||||
if (action.startsWith("spawn dms ipc call "))
|
if (action.startsWith("spawn dms ipc call "))
|
||||||
return "dms";
|
return "dms";
|
||||||
if (action.startsWith("spawn sh -c ") || action.startsWith("spawn bash -c ") || action.startsWith("spawn_shell "))
|
if (/^spawn \w+ -c /.test(action) || action.startsWith("spawn_shell "))
|
||||||
return "shell";
|
return "shell";
|
||||||
if (action.startsWith("spawn "))
|
if (action.startsWith("spawn "))
|
||||||
return "spawn";
|
return "spawn";
|
||||||
@@ -888,12 +885,13 @@ function buildSpawnAction(command, args) {
|
|||||||
return "spawn " + parts.join(" ");
|
return "spawn " + parts.join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildShellAction(compositor, shellCmd) {
|
function buildShellAction(compositor, shellCmd, shell) {
|
||||||
if (!shellCmd)
|
if (!shellCmd)
|
||||||
return "";
|
return "";
|
||||||
if (compositor === "mangowc")
|
if (compositor === "mangowc")
|
||||||
return "spawn_shell " + shellCmd;
|
return "spawn_shell " + shellCmd;
|
||||||
return "spawn sh -c \"" + shellCmd.replace(/"/g, "\\\"") + "\"";
|
var shellBin = shell || "sh";
|
||||||
|
return "spawn " + shellBin + " -c \"" + shellCmd.replace(/"/g, "\\\"") + "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSpawnCommand(action) {
|
function parseSpawnCommand(action) {
|
||||||
@@ -910,8 +908,9 @@ function parseSpawnCommand(action) {
|
|||||||
function parseShellCommand(action) {
|
function parseShellCommand(action) {
|
||||||
if (!action)
|
if (!action)
|
||||||
return "";
|
return "";
|
||||||
if (action.startsWith("spawn sh -c ")) {
|
var match = action.match(/^spawn (\w+) -c (.+)$/);
|
||||||
var content = action.slice(12);
|
if (match) {
|
||||||
|
var content = match[2];
|
||||||
if ((content.startsWith('"') && content.endsWith('"')) || (content.startsWith("'") && content.endsWith("'")))
|
if ((content.startsWith('"') && content.endsWith('"')) || (content.startsWith("'") && content.endsWith("'")))
|
||||||
content = content.slice(1, -1);
|
content = content.slice(1, -1);
|
||||||
return content.replace(/\\"/g, "\"");
|
return content.replace(/\\"/g, "\"");
|
||||||
@@ -921,6 +920,13 @@ function parseShellCommand(action) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getShellFromAction(action) {
|
||||||
|
if (!action)
|
||||||
|
return "sh";
|
||||||
|
var match = action.match(/^spawn (\w+) -c /);
|
||||||
|
return match ? match[1] : "sh";
|
||||||
|
}
|
||||||
|
|
||||||
function getActionArgConfig(compositor, action) {
|
function getActionArgConfig(compositor, action) {
|
||||||
if (!action)
|
if (!action)
|
||||||
return null;
|
return null;
|
||||||
@@ -1107,12 +1113,27 @@ function buildCompositorAction(compositor, base, args) {
|
|||||||
parts.push("focus=false");
|
parts.push("focus=false");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (base.startsWith("screenshot")) {
|
switch (base) {
|
||||||
|
case "screenshot":
|
||||||
if (args["show-pointer"] === true)
|
if (args["show-pointer"] === true)
|
||||||
parts.push("show-pointer=true");
|
parts.push("show-pointer=true");
|
||||||
|
else if (args["show-pointer"] === false)
|
||||||
|
parts.push("show-pointer=false");
|
||||||
|
break;
|
||||||
|
case "screenshot-screen":
|
||||||
|
if (args["show-pointer"] === true)
|
||||||
|
parts.push("show-pointer=true");
|
||||||
|
else if (args["show-pointer"] === false)
|
||||||
|
parts.push("show-pointer=false");
|
||||||
if (args["write-to-disk"] === true)
|
if (args["write-to-disk"] === true)
|
||||||
parts.push("write-to-disk=true");
|
parts.push("write-to-disk=true");
|
||||||
} else if (args.value) {
|
break;
|
||||||
|
case "screenshot-window":
|
||||||
|
if (args["write-to-disk"] === true)
|
||||||
|
parts.push("write-to-disk=true");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (args.value) {
|
||||||
parts.push(args.value);
|
parts.push(args.value);
|
||||||
} else if (args.index) {
|
} else if (args.index) {
|
||||||
parts.push(args.index);
|
parts.push(args.index);
|
||||||
|
|||||||
@@ -13,17 +13,16 @@ Singleton {
|
|||||||
property var currentModalsByScreen: ({})
|
property var currentModalsByScreen: ({})
|
||||||
|
|
||||||
function openModal(modal) {
|
function openModal(modal) {
|
||||||
if (!modal.allowStacking) {
|
|
||||||
closeAllModalsExcept(modal);
|
|
||||||
}
|
|
||||||
if (!modal.keepPopoutsOpen) {
|
|
||||||
PopoutManager.closeAllPopouts();
|
|
||||||
}
|
|
||||||
TrayMenuManager.closeAllMenus();
|
|
||||||
|
|
||||||
const screenName = modal.effectiveScreen?.name ?? "unknown";
|
const screenName = modal.effectiveScreen?.name ?? "unknown";
|
||||||
currentModalsByScreen[screenName] = modal;
|
currentModalsByScreen[screenName] = modal;
|
||||||
modalChanged();
|
modalChanged();
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (!modal.allowStacking)
|
||||||
|
closeAllModalsExcept(modal);
|
||||||
|
if (!modal.keepPopoutsOpen)
|
||||||
|
PopoutManager.closeAllPopouts();
|
||||||
|
TrayMenuManager.closeAllMenus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeModal(modal) {
|
function closeModal(modal) {
|
||||||
|
|||||||
@@ -45,20 +45,28 @@ Singleton {
|
|||||||
Quickshell.execDetached(["cp", strip(from), strip(to)]);
|
Quickshell.execDetached(["cp", strip(from), strip(to)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSteamApp(appId: string): bool {
|
||||||
|
return appId && /^steam_app_\d+$/.test(appId);
|
||||||
|
}
|
||||||
|
|
||||||
function moddedAppId(appId: string): string {
|
function moddedAppId(appId: string): string {
|
||||||
if (appId === "Spotify")
|
const subs = SettingsData.appIdSubstitutions || [];
|
||||||
return "spotify";
|
for (let i = 0; i < subs.length; i++) {
|
||||||
if (appId === "beepertexts")
|
const sub = subs[i];
|
||||||
return "beeper";
|
if (sub.type === "exact" && appId === sub.pattern) {
|
||||||
if (appId === "home assistant desktop")
|
return sub.replacement;
|
||||||
return "homeassistant-desktop";
|
} else if (sub.type === "contains" && appId.includes(sub.pattern)) {
|
||||||
if (appId.includes("com.transmissionbt.transmission")) {
|
return sub.replacement;
|
||||||
if (DesktopEntries.heuristicLookup("transmission-gtk"))
|
} else if (sub.type === "regex") {
|
||||||
return "transmission-gtk";
|
const match = appId.match(new RegExp(sub.pattern));
|
||||||
if (DesktopEntries.heuristicLookup("transmission"))
|
if (match) {
|
||||||
return "transmission";
|
return sub.replacement.replace(/\$(\d+)/g, (_, n) => match[n] || "");
|
||||||
return "transmission-gtk";
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const steamMatch = appId.match(/^steam_app_(\d+)$/);
|
||||||
|
if (steamMatch)
|
||||||
|
return `steam_icon_${steamMatch[1]}`;
|
||||||
return appId;
|
return appId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,8 +76,8 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const moddedId = moddedAppId(appId);
|
const moddedId = moddedAppId(appId);
|
||||||
if (moddedId.toLowerCase().includes("steam_app")) {
|
if (moddedId !== appId) {
|
||||||
return "";
|
return Quickshell.iconPath(moddedId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return desktopEntry && desktopEntry.icon ? Quickshell.iconPath(desktopEntry.icon, true) : "";
|
return desktopEntry && desktopEntry.icon ? Quickshell.iconPath(desktopEntry.icon, true) : "";
|
||||||
|
|||||||
@@ -82,15 +82,19 @@ Singleton {
|
|||||||
popoutOpening();
|
popoutOpening();
|
||||||
}
|
}
|
||||||
|
|
||||||
let justClosedSamePopout = false;
|
let movedFromOtherScreen = false;
|
||||||
for (const otherScreenName in currentPopoutsByScreen) {
|
for (const otherScreenName in currentPopoutsByScreen) {
|
||||||
if (otherScreenName === screenName)
|
if (otherScreenName === screenName)
|
||||||
continue;
|
continue;
|
||||||
const otherPopout = currentPopoutsByScreen[otherScreenName];
|
const otherPopout = currentPopoutsByScreen[otherScreenName];
|
||||||
if (!otherPopout)
|
if (!otherPopout)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (otherPopout === popout) {
|
if (otherPopout === popout) {
|
||||||
justClosedSamePopout = true;
|
movedFromOtherScreen = true;
|
||||||
|
currentPopoutsByScreen[otherScreenName] = null;
|
||||||
|
currentPopoutTriggers[otherScreenName] = null;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otherPopout.dashVisible !== undefined) {
|
if (otherPopout.dashVisible !== undefined) {
|
||||||
@@ -112,7 +116,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentPopout === popout && popout.shouldBeVisible) {
|
if (currentPopout === popout && popout.shouldBeVisible && !movedFromOtherScreen) {
|
||||||
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
|
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId) {
|
||||||
if (popout.dashVisible !== undefined) {
|
if (popout.dashVisible !== undefined) {
|
||||||
popout.dashVisible = false;
|
popout.dashVisible = false;
|
||||||
@@ -139,6 +143,7 @@ Singleton {
|
|||||||
popout.currentTabIndex = tabIndex;
|
popout.currentTabIndex = tabIndex;
|
||||||
}
|
}
|
||||||
currentPopoutTriggers[screenName] = triggerId;
|
currentPopoutTriggers[screenName] = triggerId;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPopoutTriggers[screenName] = triggerId;
|
currentPopoutTriggers[screenName] = triggerId;
|
||||||
@@ -153,16 +158,8 @@ Singleton {
|
|||||||
ModalManager.closeAllModalsExcept(null);
|
ModalManager.closeAllModalsExcept(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (justClosedSamePopout) {
|
if (movedFromOtherScreen) {
|
||||||
Qt.callLater(() => {
|
popout.open();
|
||||||
if (popout.dashVisible !== undefined) {
|
|
||||||
popout.dashVisible = true;
|
|
||||||
} else if (popout.notificationHistoryVisible !== undefined) {
|
|
||||||
popout.notificationHistoryVisible = true;
|
|
||||||
} else {
|
|
||||||
popout.open();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (popout.dashVisible !== undefined) {
|
if (popout.dashVisible !== undefined) {
|
||||||
popout.dashVisible = true;
|
popout.dashVisible = true;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -145,6 +145,7 @@ Singleton {
|
|||||||
property bool controlCenterShowMicPercent: true
|
property bool controlCenterShowMicPercent: true
|
||||||
property bool controlCenterShowBatteryIcon: false
|
property bool controlCenterShowBatteryIcon: false
|
||||||
property bool controlCenterShowPrinterIcon: false
|
property bool controlCenterShowPrinterIcon: false
|
||||||
|
property bool controlCenterShowScreenSharingIcon: true
|
||||||
property bool showPrivacyButton: true
|
property bool showPrivacyButton: true
|
||||||
property bool privacyShowMicIcon: false
|
property bool privacyShowMicIcon: false
|
||||||
property bool privacyShowCameraIcon: false
|
property bool privacyShowCameraIcon: false
|
||||||
@@ -200,10 +201,16 @@ Singleton {
|
|||||||
property bool showWorkspaceApps: false
|
property bool showWorkspaceApps: false
|
||||||
property bool groupWorkspaceApps: true
|
property bool groupWorkspaceApps: true
|
||||||
property int maxWorkspaceIcons: 3
|
property int maxWorkspaceIcons: 3
|
||||||
property bool workspacesPerMonitor: true
|
property bool workspaceFollowFocus: false
|
||||||
property bool showOccupiedWorkspacesOnly: false
|
property bool showOccupiedWorkspacesOnly: false
|
||||||
property bool reverseScrolling: false
|
property bool reverseScrolling: false
|
||||||
property bool dwlShowAllTags: false
|
property bool dwlShowAllTags: false
|
||||||
|
property string workspaceColorMode: "default"
|
||||||
|
property string workspaceUnfocusedColorMode: "default"
|
||||||
|
property string workspaceUrgentColorMode: "default"
|
||||||
|
property bool workspaceFocusedBorderEnabled: false
|
||||||
|
property string workspaceFocusedBorderColor: "primary"
|
||||||
|
property int workspaceFocusedBorderThickness: 2
|
||||||
property var workspaceNameIcons: ({})
|
property var workspaceNameIcons: ({})
|
||||||
property bool waveProgressEnabled: true
|
property bool waveProgressEnabled: true
|
||||||
property bool scrollTitleEnabled: true
|
property bool scrollTitleEnabled: true
|
||||||
@@ -215,6 +222,7 @@ Singleton {
|
|||||||
property bool keyboardLayoutNameCompactMode: false
|
property bool keyboardLayoutNameCompactMode: false
|
||||||
property bool runningAppsCurrentWorkspace: false
|
property bool runningAppsCurrentWorkspace: false
|
||||||
property bool runningAppsGroupByApp: false
|
property bool runningAppsGroupByApp: false
|
||||||
|
property var appIdSubstitutions: []
|
||||||
property string centeringMode: "index"
|
property string centeringMode: "index"
|
||||||
property string clockDateFormat: ""
|
property string clockDateFormat: ""
|
||||||
property string lockDateFormat: ""
|
property string lockDateFormat: ""
|
||||||
@@ -397,6 +405,7 @@ Singleton {
|
|||||||
property int notificationTimeoutLow: 5000
|
property int notificationTimeoutLow: 5000
|
||||||
property int notificationTimeoutNormal: 5000
|
property int notificationTimeoutNormal: 5000
|
||||||
property int notificationTimeoutCritical: 0
|
property int notificationTimeoutCritical: 0
|
||||||
|
property bool notificationCompactMode: false
|
||||||
property int notificationPopupPosition: SettingsData.Position.Top
|
property int notificationPopupPosition: SettingsData.Position.Top
|
||||||
property bool notificationHistoryEnabled: true
|
property bool notificationHistoryEnabled: true
|
||||||
property int notificationHistoryMaxCount: 50
|
property int notificationHistoryMaxCount: 50
|
||||||
@@ -530,6 +539,7 @@ Singleton {
|
|||||||
property var desktopWidgetPositions: ({})
|
property var desktopWidgetPositions: ({})
|
||||||
property var desktopWidgetGridSettings: ({})
|
property var desktopWidgetGridSettings: ({})
|
||||||
property var desktopWidgetInstances: []
|
property var desktopWidgetInstances: []
|
||||||
|
property var desktopWidgetGroups: []
|
||||||
|
|
||||||
function getDesktopWidgetGridSetting(screenKey, property, defaultValue) {
|
function getDesktopWidgetGridSetting(screenKey, property, defaultValue) {
|
||||||
const val = desktopWidgetGridSettings?.[screenKey]?.[property];
|
const val = desktopWidgetGridSettings?.[screenKey]?.[property];
|
||||||
@@ -681,6 +691,38 @@ Singleton {
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncDesktopWidgetPositionToAllScreens(instanceId) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (idx === -1)
|
||||||
|
return;
|
||||||
|
const positions = instances[idx].positions || {};
|
||||||
|
const screenKeys = Object.keys(positions).filter(k => k !== "_synced");
|
||||||
|
if (screenKeys.length === 0)
|
||||||
|
return;
|
||||||
|
const sourceKey = screenKeys[0];
|
||||||
|
const sourcePos = positions[sourceKey];
|
||||||
|
if (!sourcePos)
|
||||||
|
return;
|
||||||
|
const screen = Array.from(Quickshell.screens.values()).find(s => getScreenDisplayName(s) === sourceKey);
|
||||||
|
if (!screen)
|
||||||
|
return;
|
||||||
|
const screenW = screen.width;
|
||||||
|
const screenH = screen.height;
|
||||||
|
const synced = {};
|
||||||
|
if (sourcePos.x !== undefined)
|
||||||
|
synced.x = sourcePos.x / screenW;
|
||||||
|
if (sourcePos.y !== undefined)
|
||||||
|
synced.y = sourcePos.y / screenH;
|
||||||
|
if (sourcePos.width !== undefined)
|
||||||
|
synced.width = sourcePos.width;
|
||||||
|
if (sourcePos.height !== undefined)
|
||||||
|
synced.height = sourcePos.height;
|
||||||
|
instances[idx].positions["_synced"] = synced;
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
function duplicateDesktopWidgetInstance(instanceId) {
|
function duplicateDesktopWidgetInstance(instanceId) {
|
||||||
const source = getDesktopWidgetInstance(instanceId);
|
const source = getDesktopWidgetInstance(instanceId);
|
||||||
if (!source)
|
if (!source)
|
||||||
@@ -713,6 +755,110 @@ Singleton {
|
|||||||
return (desktopWidgetInstances || []).filter(inst => inst.enabled);
|
return (desktopWidgetInstances || []).filter(inst => inst.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveDesktopWidgetInstance(instanceId, direction) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (idx === -1)
|
||||||
|
return false;
|
||||||
|
const targetIdx = direction === "up" ? idx - 1 : idx + 1;
|
||||||
|
if (targetIdx < 0 || targetIdx >= instances.length)
|
||||||
|
return false;
|
||||||
|
const temp = instances[idx];
|
||||||
|
instances[idx] = instances[targetIdx];
|
||||||
|
instances[targetIdx] = temp;
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reorderDesktopWidgetInstance(instanceId, newIndex) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const idx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (idx === -1 || newIndex < 0 || newIndex >= instances.length)
|
||||||
|
return false;
|
||||||
|
const [item] = instances.splice(idx, 1);
|
||||||
|
instances.splice(newIndex, 0, item);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reorderDesktopWidgetInstanceInGroup(instanceId, groupId, newIndexInGroup) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
const groups = desktopWidgetGroups || [];
|
||||||
|
const groupMatches = inst => {
|
||||||
|
if (groupId === null)
|
||||||
|
return !inst.group || !groups.some(g => g.id === inst.group);
|
||||||
|
return inst.group === groupId;
|
||||||
|
};
|
||||||
|
const groupInstances = instances.filter(groupMatches);
|
||||||
|
const currentGroupIdx = groupInstances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (currentGroupIdx === -1 || currentGroupIdx === newIndexInGroup)
|
||||||
|
return false;
|
||||||
|
if (newIndexInGroup < 0 || newIndexInGroup >= groupInstances.length)
|
||||||
|
return false;
|
||||||
|
const globalIdx = instances.findIndex(inst => inst.id === instanceId);
|
||||||
|
if (globalIdx === -1)
|
||||||
|
return false;
|
||||||
|
const [item] = instances.splice(globalIdx, 1);
|
||||||
|
const targetInstance = groupInstances[newIndexInGroup];
|
||||||
|
let targetGlobalIdx = instances.findIndex(inst => inst.id === targetInstance.id);
|
||||||
|
if (newIndexInGroup > currentGroupIdx)
|
||||||
|
targetGlobalIdx++;
|
||||||
|
instances.splice(targetGlobalIdx, 0, item);
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
saveSettings();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDesktopWidgetGroup(name) {
|
||||||
|
const id = "dwg_" + Date.now() + "_" + Math.random().toString(36).substr(2, 9);
|
||||||
|
const group = {
|
||||||
|
id: id,
|
||||||
|
name: name,
|
||||||
|
collapsed: false
|
||||||
|
};
|
||||||
|
const groups = JSON.parse(JSON.stringify(desktopWidgetGroups || []));
|
||||||
|
groups.push(group);
|
||||||
|
desktopWidgetGroups = groups;
|
||||||
|
saveSettings();
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDesktopWidgetGroup(groupId, updates) {
|
||||||
|
const groups = JSON.parse(JSON.stringify(desktopWidgetGroups || []));
|
||||||
|
const idx = groups.findIndex(g => g.id === groupId);
|
||||||
|
if (idx === -1)
|
||||||
|
return;
|
||||||
|
Object.assign(groups[idx], updates);
|
||||||
|
desktopWidgetGroups = groups;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDesktopWidgetGroup(groupId) {
|
||||||
|
const instances = JSON.parse(JSON.stringify(desktopWidgetInstances || []));
|
||||||
|
for (let i = 0; i < instances.length; i++) {
|
||||||
|
if (instances[i].group === groupId)
|
||||||
|
instances[i].group = null;
|
||||||
|
}
|
||||||
|
desktopWidgetInstances = instances;
|
||||||
|
const groups = (desktopWidgetGroups || []).filter(g => g.id !== groupId);
|
||||||
|
desktopWidgetGroups = groups;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDesktopWidgetGroup(groupId) {
|
||||||
|
return (desktopWidgetGroups || []).find(g => g.id === groupId) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDesktopWidgetInstancesByGroup(groupId) {
|
||||||
|
return (desktopWidgetInstances || []).filter(inst => inst.group === groupId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUngroupedDesktopWidgetInstances() {
|
||||||
|
return (desktopWidgetInstances || []).filter(inst => !inst.group);
|
||||||
|
}
|
||||||
|
|
||||||
signal forceDankBarLayoutRefresh
|
signal forceDankBarLayoutRefresh
|
||||||
signal forceDockLayoutRefresh
|
signal forceDockLayoutRefresh
|
||||||
signal widgetDataChanged
|
signal widgetDataChanged
|
||||||
@@ -1836,6 +1982,48 @@ Singleton {
|
|||||||
return workspaceNameIcons[workspaceName] || null;
|
return workspaceNameIcons[workspaceName] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addAppIdSubstitution(pattern, replacement, type) {
|
||||||
|
var subs = JSON.parse(JSON.stringify(appIdSubstitutions));
|
||||||
|
subs.push({
|
||||||
|
pattern: pattern,
|
||||||
|
replacement: replacement,
|
||||||
|
type: type
|
||||||
|
});
|
||||||
|
appIdSubstitutions = subs;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAppIdSubstitution(index, pattern, replacement, type) {
|
||||||
|
var subs = JSON.parse(JSON.stringify(appIdSubstitutions));
|
||||||
|
if (index < 0 || index >= subs.length)
|
||||||
|
return;
|
||||||
|
subs[index] = {
|
||||||
|
pattern: pattern,
|
||||||
|
replacement: replacement,
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
appIdSubstitutions = subs;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeAppIdSubstitution(index) {
|
||||||
|
var subs = JSON.parse(JSON.stringify(appIdSubstitutions));
|
||||||
|
if (index < 0 || index >= subs.length)
|
||||||
|
return;
|
||||||
|
subs.splice(index, 1);
|
||||||
|
appIdSubstitutions = subs;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDefaultAppIdSubstitutions() {
|
||||||
|
return Spec.SPEC.appIdSubstitutions.def;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetAppIdSubstitutions() {
|
||||||
|
appIdSubstitutions = JSON.parse(JSON.stringify(Spec.SPEC.appIdSubstitutions.def));
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
function getRegistryThemeVariant(themeId, defaultVariant) {
|
function getRegistryThemeVariant(themeId, defaultVariant) {
|
||||||
var stored = registryThemeVariants[themeId];
|
var stored = registryThemeVariants[themeId];
|
||||||
if (typeof stored === "string")
|
if (typeof stored === "string")
|
||||||
|
|||||||
@@ -904,7 +904,7 @@ Singleton {
|
|||||||
if (typeof SettingsData !== "undefined") {
|
if (typeof SettingsData !== "undefined") {
|
||||||
const skipTemplates = [];
|
const skipTemplates = [];
|
||||||
if (!SettingsData.runDmsMatugenTemplates) {
|
if (!SettingsData.runDmsMatugenTemplates) {
|
||||||
skipTemplates.push("gtk", "neovim", "niri", "qt5ct", "qt6ct", "firefox", "pywalfox", "zenbrowser", "vesktop", "equibop", "ghostty", "kitty", "foot", "alacritty", "wezterm", "dgop", "kcolorscheme", "vscode");
|
skipTemplates.push("gtk", "nvim", "niri", "qt5ct", "qt6ct", "firefox", "pywalfox", "zenbrowser", "vesktop", "equibop", "ghostty", "kitty", "foot", "alacritty", "wezterm", "dgop", "kcolorscheme", "vscode");
|
||||||
} else {
|
} else {
|
||||||
if (!SettingsData.matugenTemplateGtk)
|
if (!SettingsData.matugenTemplateGtk)
|
||||||
skipTemplates.push("gtk");
|
skipTemplates.push("gtk");
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ Singleton {
|
|||||||
showMicIcon: false,
|
showMicIcon: false,
|
||||||
showMicPercent: true,
|
showMicPercent: true,
|
||||||
showBatteryIcon: false,
|
showBatteryIcon: false,
|
||||||
showPrinterIcon: false
|
showPrinterIcon: false,
|
||||||
|
showScreenSharingIcon: true
|
||||||
};
|
};
|
||||||
leftModel.append(dummy);
|
leftModel.append(dummy);
|
||||||
centerModel.append(dummy);
|
centerModel.append(dummy);
|
||||||
@@ -84,6 +85,8 @@ Singleton {
|
|||||||
item.showBatteryIcon = order[i].showBatteryIcon;
|
item.showBatteryIcon = order[i].showBatteryIcon;
|
||||||
if (isObj && order[i].showPrinterIcon !== undefined)
|
if (isObj && order[i].showPrinterIcon !== undefined)
|
||||||
item.showPrinterIcon = order[i].showPrinterIcon;
|
item.showPrinterIcon = order[i].showPrinterIcon;
|
||||||
|
if (isObj && order[i].showScreenSharingIcon !== undefined)
|
||||||
|
item.showScreenSharingIcon = order[i].showScreenSharingIcon;
|
||||||
|
|
||||||
model.append(item);
|
model.append(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ var SPEC = {
|
|||||||
controlCenterShowMicPercent: { def: false },
|
controlCenterShowMicPercent: { def: false },
|
||||||
controlCenterShowBatteryIcon: { def: false },
|
controlCenterShowBatteryIcon: { def: false },
|
||||||
controlCenterShowPrinterIcon: { def: false },
|
controlCenterShowPrinterIcon: { def: false },
|
||||||
|
controlCenterShowScreenSharingIcon: { def: true },
|
||||||
|
|
||||||
showPrivacyButton: { def: true },
|
showPrivacyButton: { def: true },
|
||||||
privacyShowMicIcon: { def: false },
|
privacyShowMicIcon: { def: false },
|
||||||
@@ -94,10 +95,16 @@ var SPEC = {
|
|||||||
showWorkspaceApps: { def: false },
|
showWorkspaceApps: { def: false },
|
||||||
maxWorkspaceIcons: { def: 3 },
|
maxWorkspaceIcons: { def: 3 },
|
||||||
groupWorkspaceApps: { def: true },
|
groupWorkspaceApps: { def: true },
|
||||||
workspacesPerMonitor: { def: true },
|
workspaceFollowFocus: { def: false },
|
||||||
showOccupiedWorkspacesOnly: { def: false },
|
showOccupiedWorkspacesOnly: { def: false },
|
||||||
reverseScrolling: { def: false },
|
reverseScrolling: { def: false },
|
||||||
dwlShowAllTags: { def: false },
|
dwlShowAllTags: { def: false },
|
||||||
|
workspaceColorMode: { def: "default" },
|
||||||
|
workspaceUnfocusedColorMode: { def: "default" },
|
||||||
|
workspaceUrgentColorMode: { def: "default" },
|
||||||
|
workspaceFocusedBorderEnabled: { def: false },
|
||||||
|
workspaceFocusedBorderColor: { def: "primary" },
|
||||||
|
workspaceFocusedBorderThickness: { def: 2 },
|
||||||
workspaceNameIcons: { def: {} },
|
workspaceNameIcons: { def: {} },
|
||||||
waveProgressEnabled: { def: true },
|
waveProgressEnabled: { def: true },
|
||||||
scrollTitleEnabled: { def: true },
|
scrollTitleEnabled: { def: true },
|
||||||
@@ -109,6 +116,13 @@ var SPEC = {
|
|||||||
keyboardLayoutNameCompactMode: { def: false },
|
keyboardLayoutNameCompactMode: { def: false },
|
||||||
runningAppsCurrentWorkspace: { def: false },
|
runningAppsCurrentWorkspace: { def: false },
|
||||||
runningAppsGroupByApp: { def: false },
|
runningAppsGroupByApp: { def: false },
|
||||||
|
appIdSubstitutions: { def: [
|
||||||
|
{ pattern: "Spotify", replacement: "spotify", type: "exact" },
|
||||||
|
{ pattern: "beepertexts", replacement: "beeper", type: "exact" },
|
||||||
|
{ pattern: "home assistant desktop", replacement: "homeassistant-desktop", type: "exact" },
|
||||||
|
{ pattern: "com.transmissionbt.transmission", replacement: "transmission-gtk", type: "contains" },
|
||||||
|
{ pattern: "^steam_app_(\\d+)$", replacement: "steam_icon_$1", type: "regex" }
|
||||||
|
]},
|
||||||
centeringMode: { def: "index" },
|
centeringMode: { def: "index" },
|
||||||
clockDateFormat: { def: "" },
|
clockDateFormat: { def: "" },
|
||||||
lockDateFormat: { def: "" },
|
lockDateFormat: { def: "" },
|
||||||
@@ -255,6 +269,7 @@ var SPEC = {
|
|||||||
notificationTimeoutLow: { def: 5000 },
|
notificationTimeoutLow: { def: 5000 },
|
||||||
notificationTimeoutNormal: { def: 5000 },
|
notificationTimeoutNormal: { def: 5000 },
|
||||||
notificationTimeoutCritical: { def: 0 },
|
notificationTimeoutCritical: { def: 0 },
|
||||||
|
notificationCompactMode: { def: false },
|
||||||
notificationPopupPosition: { def: 0 },
|
notificationPopupPosition: { def: 0 },
|
||||||
notificationHistoryEnabled: { def: true },
|
notificationHistoryEnabled: { def: true },
|
||||||
notificationHistoryMaxCount: { def: 50 },
|
notificationHistoryMaxCount: { def: 50 },
|
||||||
@@ -388,6 +403,8 @@ var SPEC = {
|
|||||||
|
|
||||||
desktopWidgetInstances: { def: [] },
|
desktopWidgetInstances: { def: [] },
|
||||||
|
|
||||||
|
desktopWidgetGroups: { def: [] },
|
||||||
|
|
||||||
builtInPluginSettings: { def: {} }
|
builtInPluginSettings: { def: {} }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ Item {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
dockRecreateDebounce.start();
|
dockRecreateDebounce.start();
|
||||||
|
// Force PolkitService singleton to initialize
|
||||||
|
PolkitService.polkitAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -315,19 +317,44 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WifiPasswordModal {
|
LazyLoader {
|
||||||
id: wifiPasswordModal
|
id: wifiPasswordModalLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
PopoutService.wifiPasswordModal = wifiPasswordModal;
|
PopoutService.wifiPasswordModalLoader = wifiPasswordModalLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
WifiPasswordModal {
|
||||||
|
id: wifiPasswordModalItem
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
PopoutService.wifiPasswordModal = wifiPasswordModalItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PolkitAuthModal {
|
LazyLoader {
|
||||||
id: polkitAuthModal
|
id: polkitAuthModalLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
Component.onCompleted: {
|
PolkitAuthModal {
|
||||||
PopoutService.polkitAuthModal = polkitAuthModal;
|
id: polkitAuthModal
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
PopoutService.polkitAuthModal = polkitAuthModal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: PolkitService.agent
|
||||||
|
enabled: PolkitService.polkitAvailable
|
||||||
|
|
||||||
|
function onAuthenticationRequestStarted() {
|
||||||
|
polkitAuthModalLoader.active = true;
|
||||||
|
if (polkitAuthModalLoader.item)
|
||||||
|
polkitAuthModalLoader.item.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,17 +376,21 @@ Item {
|
|||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const timeSinceLastPrompt = now - lastCredentialsTime;
|
const timeSinceLastPrompt = now - lastCredentialsTime;
|
||||||
|
|
||||||
if (wifiPasswordModal.visible && timeSinceLastPrompt < 1000) {
|
wifiPasswordModalLoader.active = true;
|
||||||
|
if (!wifiPasswordModalLoader.item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (wifiPasswordModalLoader.item.visible && timeSinceLastPrompt < 1000) {
|
||||||
NetworkService.cancelCredentials(lastCredentialsToken);
|
NetworkService.cancelCredentials(lastCredentialsToken);
|
||||||
lastCredentialsToken = token;
|
lastCredentialsToken = token;
|
||||||
lastCredentialsTime = now;
|
lastCredentialsTime = now;
|
||||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
|
wifiPasswordModalLoader.item.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastCredentialsToken = token;
|
lastCredentialsToken = token;
|
||||||
lastCredentialsTime = now;
|
lastCredentialsTime = now;
|
||||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
|
wifiPasswordModalLoader.item.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService, fieldsInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,17 +473,15 @@ Item {
|
|||||||
PopoutService.settingsModalLoader = settingsModalLoader;
|
PopoutService.settingsModalLoader = settingsModalLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
onActiveChanged: {
|
|
||||||
if (active && item) {
|
|
||||||
PopoutService.settingsModal = item;
|
|
||||||
PopoutService._onSettingsModalLoaded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingsModal {
|
SettingsModal {
|
||||||
id: settingsModal
|
id: settingsModal
|
||||||
property bool wasShown: false
|
property bool wasShown: false
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
PopoutService.settingsModal = settingsModal;
|
||||||
|
PopoutService._onSettingsModalLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
wasShown = true;
|
wasShown = true;
|
||||||
|
|||||||
@@ -132,8 +132,11 @@ Item {
|
|||||||
case "media":
|
case "media":
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = 1;
|
root.dankDashPopoutLoader.item.currentTabIndex = 1;
|
||||||
break;
|
break;
|
||||||
|
case "wallpaper":
|
||||||
|
root.dankDashPopoutLoader.item.currentTabIndex = 2;
|
||||||
|
break;
|
||||||
case "weather":
|
case "weather":
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0;
|
root.dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 3 : 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
root.dankDashPopoutLoader.item.currentTabIndex = 0;
|
root.dankDashPopoutLoader.item.currentTabIndex = 0;
|
||||||
@@ -599,6 +602,39 @@ Item {
|
|||||||
return barConfig.autoHide ? "BAR_MANUAL_HIDE_SUCCESS" : "BAR_AUTO_HIDE_SUCCESS";
|
return barConfig.autoHide ? "BAR_MANUAL_HIDE_SUCCESS" : "BAR_AUTO_HIDE_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPosition(selector: string, value: string): string {
|
||||||
|
const {
|
||||||
|
barConfig,
|
||||||
|
error
|
||||||
|
} = getBarConfig(selector, value);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
const positions = ["top", "bottom", "left", "right"];
|
||||||
|
return positions[barConfig.position] || "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPosition(selector: string, value: string, position: string): string {
|
||||||
|
const {
|
||||||
|
barConfig,
|
||||||
|
error
|
||||||
|
} = getBarConfig(selector, value);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
const positionMap = {
|
||||||
|
"top": SettingsData.Position.Top,
|
||||||
|
"bottom": SettingsData.Position.Bottom,
|
||||||
|
"left": SettingsData.Position.Left,
|
||||||
|
"right": SettingsData.Position.Right
|
||||||
|
};
|
||||||
|
const posValue = positionMap[position.toLowerCase()];
|
||||||
|
if (posValue === undefined)
|
||||||
|
return "BAR_INVALID_POSITION";
|
||||||
|
SettingsData.updateBarConfig(barConfig.id, {
|
||||||
|
position: posValue
|
||||||
|
});
|
||||||
|
return "BAR_POSITION_SET_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
target: "bar"
|
target: "bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -764,11 +800,9 @@ Item {
|
|||||||
const modal = PopoutService.settingsModal;
|
const modal = PopoutService.settingsModal;
|
||||||
if (modal) {
|
if (modal) {
|
||||||
if (type === "wallpaper") {
|
if (type === "wallpaper") {
|
||||||
modal.wallpaperBrowser.allowStacking = false;
|
modal.openWallpaperBrowser(false);
|
||||||
modal.wallpaperBrowser.open();
|
|
||||||
} else if (type === "profile") {
|
} else if (type === "profile") {
|
||||||
modal.profileBrowser.allowStacking = false;
|
modal.openProfileBrowser(false);
|
||||||
modal.profileBrowser.open();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PopoutService.openSettings();
|
PopoutService.openSettings();
|
||||||
@@ -1035,7 +1069,7 @@ Item {
|
|||||||
const instances = SettingsData.desktopWidgetInstances || [];
|
const instances = SettingsData.desktopWidgetInstances || [];
|
||||||
if (instances.length === 0)
|
if (instances.length === 0)
|
||||||
return "No desktop widgets configured";
|
return "No desktop widgets configured";
|
||||||
return instances.map(i => `${i.id} [${i.widgetType}] ${i.name || i.widgetType}`).join("\n");
|
return instances.map(i => `${i.id} [${i.widgetType}] ${i.name || i.widgetType} ${i.enabled ? "[enabled]" : "[disabled]"}`).join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
function status(instanceId: string): string {
|
function status(instanceId: string): string {
|
||||||
@@ -1046,9 +1080,115 @@ Item {
|
|||||||
if (!instance)
|
if (!instance)
|
||||||
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
const enabled = instance.enabled ?? true;
|
||||||
const overlay = instance.config?.showOnOverlay ?? false;
|
const overlay = instance.config?.showOnOverlay ?? false;
|
||||||
const overview = instance.config?.showOnOverview ?? false;
|
const overview = instance.config?.showOnOverview ?? false;
|
||||||
return `overlay: ${overlay}, overview: ${overview}`;
|
const clickThrough = instance.config?.clickThrough ?? false;
|
||||||
|
const syncPosition = instance.config?.syncPositionAcrossScreens ?? false;
|
||||||
|
return `enabled: ${enabled}, overlay: ${overlay}, overview: ${overview}, clickThrough: ${clickThrough}, syncPosition: ${syncPosition}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enable(instanceId: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
SettingsData.updateDesktopWidgetInstance(instanceId, {
|
||||||
|
enabled: true
|
||||||
|
});
|
||||||
|
return `DESKTOP_WIDGET_ENABLED: ${instanceId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function disable(instanceId: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
SettingsData.updateDesktopWidgetInstance(instanceId, {
|
||||||
|
enabled: false
|
||||||
|
});
|
||||||
|
return `DESKTOP_WIDGET_DISABLED: ${instanceId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleEnabled(instanceId: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
const currentValue = instance.enabled ?? true;
|
||||||
|
SettingsData.updateDesktopWidgetInstance(instanceId, {
|
||||||
|
enabled: !currentValue
|
||||||
|
});
|
||||||
|
return !currentValue ? `DESKTOP_WIDGET_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_DISABLED: ${instanceId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleClickThrough(instanceId: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
const currentValue = instance.config?.clickThrough ?? false;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
||||||
|
clickThrough: !currentValue
|
||||||
|
});
|
||||||
|
return !currentValue ? `DESKTOP_WIDGET_CLICK_THROUGH_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_CLICK_THROUGH_DISABLED: ${instanceId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setClickThrough(instanceId: string, enabled: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
const enabledBool = enabled === "true" || enabled === "1";
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
||||||
|
clickThrough: enabledBool
|
||||||
|
});
|
||||||
|
return enabledBool ? `DESKTOP_WIDGET_CLICK_THROUGH_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_CLICK_THROUGH_DISABLED: ${instanceId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSyncPosition(instanceId: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
const currentValue = instance.config?.syncPositionAcrossScreens ?? false;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
||||||
|
syncPositionAcrossScreens: !currentValue
|
||||||
|
});
|
||||||
|
return !currentValue ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSyncPosition(instanceId: string, enabled: string): string {
|
||||||
|
if (!instanceId)
|
||||||
|
return "ERROR: No instance ID specified";
|
||||||
|
|
||||||
|
const instance = SettingsData.getDesktopWidgetInstance(instanceId);
|
||||||
|
if (!instance)
|
||||||
|
return `DESKTOP_WIDGET_NOT_FOUND: ${instanceId}`;
|
||||||
|
|
||||||
|
const enabledBool = enabled === "true" || enabled === "1";
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(instanceId, {
|
||||||
|
syncPositionAcrossScreens: enabledBool
|
||||||
|
});
|
||||||
|
return enabledBool ? `DESKTOP_WIDGET_SYNC_POSITION_ENABLED: ${instanceId}` : `DESKTOP_WIDGET_SYNC_POSITION_DISABLED: ${instanceId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
target: "desktopWidget"
|
target: "desktopWidget"
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ FloatingWindow {
|
|||||||
iconName: "open_in_new"
|
iconName: "open_in_new"
|
||||||
backgroundColor: Theme.surfaceContainerHighest
|
backgroundColor: Theme.surfaceContainerHighest
|
||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
onClicked: Qt.openUrlExternally("https://danklinux.com/blog/dms-1-2-spicy-miso")
|
onClicked: Qt.openUrlExternally("https://danklinux.com/blog/v1-2-release")
|
||||||
}
|
}
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ Item {
|
|||||||
readonly property alias clickCatcher: clickCatcher
|
readonly property alias clickCatcher: clickCatcher
|
||||||
readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab
|
readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab
|
||||||
readonly property bool useBackground: showBackground && SettingsData.modalDarkenBackground
|
readonly property bool useBackground: showBackground && SettingsData.modalDarkenBackground
|
||||||
readonly property bool useSingleWindow: useHyprlandFocusGrab || useBackground
|
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackground
|
||||||
|
|
||||||
signal opened
|
signal opened
|
||||||
signal dialogClosed
|
signal dialogClosed
|
||||||
@@ -58,7 +58,6 @@ Item {
|
|||||||
property bool animationsEnabled: true
|
property bool animationsEnabled: true
|
||||||
|
|
||||||
function open() {
|
function open() {
|
||||||
ModalManager.openModal(root);
|
|
||||||
closeTimer.stop();
|
closeTimer.stop();
|
||||||
const focusedScreen = CompositorService.getFocusedScreen();
|
const focusedScreen = CompositorService.getFocusedScreen();
|
||||||
if (focusedScreen) {
|
if (focusedScreen) {
|
||||||
@@ -66,6 +65,7 @@ Item {
|
|||||||
if (!useSingleWindow)
|
if (!useSingleWindow)
|
||||||
clickCatcher.screen = focusedScreen;
|
clickCatcher.screen = focusedScreen;
|
||||||
}
|
}
|
||||||
|
ModalManager.openModal(root);
|
||||||
shouldBeVisible = true;
|
shouldBeVisible = true;
|
||||||
if (!useSingleWindow)
|
if (!useSingleWindow)
|
||||||
clickCatcher.visible = true;
|
clickCatcher.visible = true;
|
||||||
@@ -302,7 +302,7 @@ Item {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
enabled: root.useSingleWindow
|
enabled: root.useSingleWindow && root.shouldBeVisible
|
||||||
hoverEnabled: false
|
hoverEnabled: false
|
||||||
acceptedButtons: Qt.AllButtons
|
acceptedButtons: Qt.AllButtons
|
||||||
onPressed: mouse.accepted = true
|
onPressed: mouse.accepted = true
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ FloatingWindow {
|
|||||||
property var currentFlow: PolkitService.agent?.flow
|
property var currentFlow: PolkitService.agent?.flow
|
||||||
property bool isLoading: false
|
property bool isLoading: false
|
||||||
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
||||||
property int calculatedHeight: Math.max(240, headerRow.implicitHeight + mainColumn.implicitHeight + Theme.spacingM * 3)
|
|
||||||
|
|
||||||
function focusPasswordField() {
|
function focusPasswordField() {
|
||||||
passwordField.forceActiveFocus();
|
passwordField.forceActiveFocus();
|
||||||
@@ -37,15 +36,19 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cancelAuth() {
|
function cancelAuth() {
|
||||||
if (!currentFlow || isLoading)
|
if (isLoading)
|
||||||
return;
|
return;
|
||||||
currentFlow.cancelAuthenticationRequest();
|
if (currentFlow) {
|
||||||
|
currentFlow.cancelAuthenticationRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
objectName: "polkitAuthModal"
|
objectName: "polkitAuthModal"
|
||||||
title: I18n.tr("Authentication")
|
title: I18n.tr("Authentication")
|
||||||
minimumSize: Qt.size(420, calculatedHeight)
|
minimumSize: Qt.size(460, 220)
|
||||||
maximumSize: Qt.size(420, calculatedHeight)
|
maximumSize: Qt.size(460, 220)
|
||||||
color: Theme.surfaceContainer
|
color: Theme.surfaceContainer
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
@@ -108,29 +111,24 @@ FloatingWindow {
|
|||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
height: headerRow.height + Theme.spacingM
|
|
||||||
onPressed: windowControls.tryStartMove()
|
|
||||||
onDoubleClicked: windowControls.tryToggleMaximize()
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: headerRow
|
id: headerSection
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.margins: Theme.spacingM
|
||||||
anchors.rightMargin: Theme.spacingM
|
height: Math.max(titleColumn.implicitHeight, windowButtonRow.implicitHeight)
|
||||||
anchors.topMargin: Theme.spacingM
|
|
||||||
height: Math.max(titleColumn.height, buttonRow.height)
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onPressed: windowControls.tryStartMove()
|
||||||
|
onDoubleClicked: windowControls.tryToggleMaximize()
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: titleColumn
|
id: titleColumn
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: buttonRow.left
|
anchors.right: windowButtonRow.left
|
||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: Theme.spacingM
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
@@ -141,33 +139,34 @@ FloatingWindow {
|
|||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
StyledText {
|
||||||
|
text: currentFlow?.message ?? ""
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceTextMedium
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingXS
|
wrapMode: Text.Wrap
|
||||||
|
maximumLineCount: 2
|
||||||
|
elide: Text.ElideRight
|
||||||
|
visible: text !== ""
|
||||||
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: currentFlow?.message ?? ""
|
text: currentFlow?.supplementaryMessage ?? ""
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceTextMedium
|
color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium
|
||||||
width: parent.width
|
width: parent.width
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
}
|
maximumLineCount: 2
|
||||||
|
elide: Text.ElideRight
|
||||||
StyledText {
|
opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8
|
||||||
visible: (currentFlow?.supplementaryMessage ?? "") !== ""
|
visible: text !== ""
|
||||||
text: currentFlow?.supplementaryMessage ?? ""
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: (currentFlow?.supplementaryIsError ?? false) ? Theme.error : Theme.surfaceTextMedium
|
|
||||||
width: parent.width
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
opacity: (currentFlow?.supplementaryIsError ?? false) ? 1 : 0.8
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: buttonRow
|
id: windowButtonRow
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
DankActionButton {
|
DankActionButton {
|
||||||
@@ -190,21 +189,19 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: mainColumn
|
id: bottomSection
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.margins: Theme.spacingM
|
||||||
anchors.rightMargin: Theme.spacingM
|
spacing: Theme.spacingS
|
||||||
anchors.bottomMargin: Theme.spacingM
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: currentFlow?.inputPrompt ?? ""
|
text: currentFlow?.inputPrompt ?? ""
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: (currentFlow?.inputPrompt ?? "") !== ""
|
visible: text !== ""
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -229,7 +226,8 @@ FloatingWindow {
|
|||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
text: passwordInput
|
text: passwordInput
|
||||||
echoMode: (currentFlow?.responseVisible ?? false) ? TextInput.Normal : TextInput.Password
|
showPasswordToggle: !(currentFlow?.responseVisible ?? false)
|
||||||
|
echoMode: (currentFlow?.responseVisible ?? false) || passwordVisible ? TextInput.Normal : TextInput.Password
|
||||||
placeholderText: ""
|
placeholderText: ""
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
enabled: !isLoading
|
enabled: !isLoading
|
||||||
@@ -238,38 +236,17 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
StyledText {
|
||||||
|
text: I18n.tr("Authentication failed, please try again")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.error
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: (currentFlow?.failed ?? false) ? failedText.implicitHeight : 0
|
visible: currentFlow?.failed ?? false
|
||||||
visible: height > 0
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: failedText
|
|
||||||
text: I18n.tr("Authentication failed, please try again")
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.error
|
|
||||||
width: parent.width
|
|
||||||
opacity: (currentFlow?.failed ?? false) ? 1 : 0
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on height {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 40
|
height: 36
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
|
|||||||
@@ -74,9 +74,7 @@ Rectangle {
|
|||||||
if (root.parentModal) {
|
if (root.parentModal) {
|
||||||
root.parentModal.allowFocusOverride = true;
|
root.parentModal.allowFocusOverride = true;
|
||||||
root.parentModal.shouldHaveFocus = false;
|
root.parentModal.shouldHaveFocus = false;
|
||||||
if (root.parentModal.profileBrowser) {
|
root.parentModal.openProfileBrowser();
|
||||||
root.parentModal.profileBrowser.open();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,26 @@ import qs.Widgets
|
|||||||
FloatingWindow {
|
FloatingWindow {
|
||||||
id: settingsModal
|
id: settingsModal
|
||||||
|
|
||||||
property alias profileBrowser: profileBrowser
|
property var profileBrowser: profileBrowserLoader.item
|
||||||
property alias wallpaperBrowser: wallpaperBrowser
|
property var wallpaperBrowser: wallpaperBrowserLoader.item
|
||||||
|
|
||||||
|
function openProfileBrowser(allowStacking) {
|
||||||
|
profileBrowserLoader.active = true;
|
||||||
|
if (!profileBrowserLoader.item)
|
||||||
|
return;
|
||||||
|
if (allowStacking !== undefined)
|
||||||
|
profileBrowserLoader.item.allowStacking = allowStacking;
|
||||||
|
profileBrowserLoader.item.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openWallpaperBrowser(allowStacking) {
|
||||||
|
wallpaperBrowserLoader.active = true;
|
||||||
|
if (!wallpaperBrowserLoader.item)
|
||||||
|
return;
|
||||||
|
if (allowStacking !== undefined)
|
||||||
|
wallpaperBrowserLoader.item.allowStacking = allowStacking;
|
||||||
|
wallpaperBrowserLoader.item.open();
|
||||||
|
}
|
||||||
property alias sidebar: sidebar
|
property alias sidebar: sidebar
|
||||||
property int currentTabIndex: 0
|
property int currentTabIndex: 0
|
||||||
property bool shouldHaveFocus: visible
|
property bool shouldHaveFocus: visible
|
||||||
@@ -96,41 +114,51 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserModal {
|
LazyLoader {
|
||||||
id: profileBrowser
|
id: profileBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
allowStacking: true
|
FileBrowserModal {
|
||||||
parentModal: settingsModal
|
id: profileBrowserItem
|
||||||
browserTitle: I18n.tr("Select Profile Image", "profile image file browser title")
|
|
||||||
browserIcon: "person"
|
allowStacking: true
|
||||||
browserType: "profile"
|
parentModal: settingsModal
|
||||||
showHiddenFiles: true
|
browserTitle: I18n.tr("Select Profile Image", "profile image file browser title")
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
browserIcon: "person"
|
||||||
onFileSelected: path => {
|
browserType: "profile"
|
||||||
PortalService.setProfileImage(path);
|
showHiddenFiles: true
|
||||||
close();
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
}
|
onFileSelected: path => {
|
||||||
onDialogClosed: () => {
|
PortalService.setProfileImage(path);
|
||||||
allowStacking = true;
|
close();
|
||||||
|
}
|
||||||
|
onDialogClosed: () => {
|
||||||
|
allowStacking = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserModal {
|
LazyLoader {
|
||||||
id: wallpaperBrowser
|
id: wallpaperBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
allowStacking: true
|
FileBrowserModal {
|
||||||
parentModal: settingsModal
|
id: wallpaperBrowserItem
|
||||||
browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title")
|
|
||||||
browserIcon: "wallpaper"
|
allowStacking: true
|
||||||
browserType: "wallpaper"
|
parentModal: settingsModal
|
||||||
showHiddenFiles: true
|
browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title")
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
browserIcon: "wallpaper"
|
||||||
onFileSelected: path => {
|
browserType: "wallpaper"
|
||||||
SessionData.setWallpaper(path);
|
showHiddenFiles: true
|
||||||
close();
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
}
|
onFileSelected: path => {
|
||||||
onDialogClosed: () => {
|
SessionData.setWallpaper(path);
|
||||||
allowStacking = true;
|
close();
|
||||||
|
}
|
||||||
|
onDialogClosed: () => {
|
||||||
|
allowStacking = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,8 +347,8 @@ FloatingWindow {
|
|||||||
visible: settingsModal.isCompactMode ? settingsModal.menuVisible : true
|
visible: settingsModal.isCompactMode ? settingsModal.menuVisible : true
|
||||||
parentModal: settingsModal
|
parentModal: settingsModal
|
||||||
currentIndex: settingsModal.currentTabIndex
|
currentIndex: settingsModal.currentTabIndex
|
||||||
onCurrentIndexChanged: {
|
onTabChangeRequested: tabIndex => {
|
||||||
settingsModal.currentTabIndex = currentIndex;
|
settingsModal.currentTabIndex = tabIndex;
|
||||||
if (settingsModal.isCompactMode) {
|
if (settingsModal.isCompactMode) {
|
||||||
settingsModal.enableAnimations = true;
|
settingsModal.enableAnimations = true;
|
||||||
settingsModal.menuVisible = false;
|
settingsModal.menuVisible = false;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ Rectangle {
|
|||||||
|
|
||||||
property int currentIndex: 0
|
property int currentIndex: 0
|
||||||
property var parentModal: null
|
property var parentModal: null
|
||||||
|
|
||||||
|
signal tabChangeRequested(int tabIndex)
|
||||||
property var expandedCategories: ({})
|
property var expandedCategories: ({})
|
||||||
property var autoExpandedCategories: ({})
|
property var autoExpandedCategories: ({})
|
||||||
property bool searchActive: searchField.text.length > 0
|
property bool searchActive: searchField.text.length > 0
|
||||||
@@ -55,8 +57,9 @@ Rectangle {
|
|||||||
if (keyboardHighlightIndex < 0)
|
if (keyboardHighlightIndex < 0)
|
||||||
return;
|
return;
|
||||||
var oldIndex = currentIndex;
|
var oldIndex = currentIndex;
|
||||||
currentIndex = keyboardHighlightIndex;
|
var newIndex = keyboardHighlightIndex;
|
||||||
autoCollapseIfNeeded(oldIndex, currentIndex);
|
tabChangeRequested(newIndex);
|
||||||
|
autoCollapseIfNeeded(oldIndex, newIndex);
|
||||||
keyboardHighlightIndex = -1;
|
keyboardHighlightIndex = -1;
|
||||||
Qt.callLater(searchField.forceActiveFocus);
|
Qt.callLater(searchField.forceActiveFocus);
|
||||||
}
|
}
|
||||||
@@ -398,28 +401,32 @@ Rectangle {
|
|||||||
var flatItems = getFlatNavigableItems();
|
var flatItems = getFlatNavigableItems();
|
||||||
var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex);
|
var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex);
|
||||||
var oldIndex = currentIndex;
|
var oldIndex = currentIndex;
|
||||||
|
var newIndex;
|
||||||
if (currentPos === -1) {
|
if (currentPos === -1) {
|
||||||
currentIndex = flatItems[0]?.tabIndex ?? 0;
|
newIndex = flatItems[0]?.tabIndex ?? 0;
|
||||||
} else {
|
} else {
|
||||||
var nextPos = (currentPos + 1) % flatItems.length;
|
var nextPos = (currentPos + 1) % flatItems.length;
|
||||||
currentIndex = flatItems[nextPos].tabIndex;
|
newIndex = flatItems[nextPos].tabIndex;
|
||||||
}
|
}
|
||||||
autoCollapseIfNeeded(oldIndex, currentIndex);
|
tabChangeRequested(newIndex);
|
||||||
autoExpandForTab(currentIndex);
|
autoCollapseIfNeeded(oldIndex, newIndex);
|
||||||
|
autoExpandForTab(newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function navigatePrevious() {
|
function navigatePrevious() {
|
||||||
var flatItems = getFlatNavigableItems();
|
var flatItems = getFlatNavigableItems();
|
||||||
var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex);
|
var currentPos = flatItems.findIndex(item => item.tabIndex === currentIndex);
|
||||||
var oldIndex = currentIndex;
|
var oldIndex = currentIndex;
|
||||||
|
var newIndex;
|
||||||
if (currentPos === -1) {
|
if (currentPos === -1) {
|
||||||
currentIndex = flatItems[0]?.tabIndex ?? 0;
|
newIndex = flatItems[0]?.tabIndex ?? 0;
|
||||||
} else {
|
} else {
|
||||||
var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length;
|
var prevPos = (currentPos - 1 + flatItems.length) % flatItems.length;
|
||||||
currentIndex = flatItems[prevPos].tabIndex;
|
newIndex = flatItems[prevPos].tabIndex;
|
||||||
}
|
}
|
||||||
autoCollapseIfNeeded(oldIndex, currentIndex);
|
tabChangeRequested(newIndex);
|
||||||
autoExpandForTab(currentIndex);
|
autoCollapseIfNeeded(oldIndex, newIndex);
|
||||||
|
autoExpandForTab(newIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFlatNavigableItems() {
|
function getFlatNavigableItems() {
|
||||||
@@ -488,7 +495,7 @@ Rectangle {
|
|||||||
SettingsSearchService.navigateToSection(result.section);
|
SettingsSearchService.navigateToSection(result.section);
|
||||||
}
|
}
|
||||||
var oldIndex = root.currentIndex;
|
var oldIndex = root.currentIndex;
|
||||||
root.currentIndex = result.tabIndex;
|
tabChangeRequested(result.tabIndex);
|
||||||
autoCollapseIfNeeded(oldIndex, result.tabIndex);
|
autoCollapseIfNeeded(oldIndex, result.tabIndex);
|
||||||
autoExpandForTab(result.tabIndex);
|
autoExpandForTab(result.tabIndex);
|
||||||
searchField.text = "";
|
searchField.text = "";
|
||||||
@@ -807,7 +814,7 @@ Rectangle {
|
|||||||
if (categoryDelegate.modelData.children) {
|
if (categoryDelegate.modelData.children) {
|
||||||
root.toggleCategory(categoryDelegate.modelData.id);
|
root.toggleCategory(categoryDelegate.modelData.id);
|
||||||
} else if (categoryDelegate.modelData.tabIndex !== undefined) {
|
} else if (categoryDelegate.modelData.tabIndex !== undefined) {
|
||||||
root.currentIndex = categoryDelegate.modelData.tabIndex;
|
root.tabChangeRequested(categoryDelegate.modelData.tabIndex);
|
||||||
}
|
}
|
||||||
Qt.callLater(searchField.forceActiveFocus);
|
Qt.callLater(searchField.forceActiveFocus);
|
||||||
}
|
}
|
||||||
@@ -882,7 +889,7 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.keyboardHighlightIndex = -1;
|
root.keyboardHighlightIndex = -1;
|
||||||
root.currentIndex = childDelegate.modelData.tabIndex;
|
root.tabChangeRequested(childDelegate.modelData.tabIndex);
|
||||||
Qt.callLater(searchField.forceActiveFocus);
|
Qt.callLater(searchField.forceActiveFocus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,10 @@ DankModal {
|
|||||||
isClosing = false;
|
isClosing = false;
|
||||||
resetContent();
|
resetContent();
|
||||||
spotlightOpen = true;
|
spotlightOpen = true;
|
||||||
if (spotlightContent?.appLauncher)
|
|
||||||
spotlightContent.appLauncher.ensureInitialized();
|
|
||||||
open();
|
open();
|
||||||
|
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
|
if (spotlightContent?.appLauncher)
|
||||||
|
spotlightContent.appLauncher.ensureInitialized();
|
||||||
if (spotlightContent?.searchField)
|
if (spotlightContent?.searchField)
|
||||||
spotlightContent.searchField.forceActiveFocus();
|
spotlightContent.searchField.forceActiveFocus();
|
||||||
});
|
});
|
||||||
@@ -53,15 +52,14 @@ DankModal {
|
|||||||
isClosing = false;
|
isClosing = false;
|
||||||
resetContent();
|
resetContent();
|
||||||
spotlightOpen = true;
|
spotlightOpen = true;
|
||||||
if (spotlightContent?.appLauncher) {
|
|
||||||
spotlightContent.appLauncher.ensureInitialized();
|
|
||||||
spotlightContent.appLauncher.searchQuery = query;
|
|
||||||
}
|
|
||||||
if (spotlightContent?.searchField)
|
if (spotlightContent?.searchField)
|
||||||
spotlightContent.searchField.text = query;
|
spotlightContent.searchField.text = query;
|
||||||
open();
|
open();
|
||||||
|
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
|
if (spotlightContent?.appLauncher) {
|
||||||
|
spotlightContent.appLauncher.ensureInitialized();
|
||||||
|
spotlightContent.appLauncher.searchQuery = query;
|
||||||
|
}
|
||||||
if (spotlightContent?.searchField)
|
if (spotlightContent?.searchField)
|
||||||
spotlightContent.searchField.forceActiveFocus();
|
spotlightContent.searchField.forceActiveFocus();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ FloatingWindow {
|
|||||||
readonly property bool showPasswordField: fieldsInfo.length === 0
|
readonly property bool showPasswordField: fieldsInfo.length === 0
|
||||||
readonly property bool showAnonField: requiresEnterprise && !isVpnPrompt
|
readonly property bool showAnonField: requiresEnterprise && !isVpnPrompt
|
||||||
readonly property bool showDomainField: requiresEnterprise && !isVpnPrompt
|
readonly property bool showDomainField: requiresEnterprise && !isVpnPrompt
|
||||||
readonly property bool showShowPasswordCheckbox: fieldsInfo.length === 0
|
|
||||||
readonly property bool showSavePasswordCheckbox: (isVpnPrompt || fieldsInfo.length > 0) && promptReason !== "pkcs11"
|
readonly property bool showSavePasswordCheckbox: (isVpnPrompt || fieldsInfo.length > 0) && promptReason !== "pkcs11"
|
||||||
|
|
||||||
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
||||||
@@ -55,8 +54,6 @@ FloatingWindow {
|
|||||||
h += inputFieldWithSpacing;
|
h += inputFieldWithSpacing;
|
||||||
if (showDomainField)
|
if (showDomainField)
|
||||||
h += inputFieldWithSpacing;
|
h += inputFieldWithSpacing;
|
||||||
if (showShowPasswordCheckbox)
|
|
||||||
h += checkboxRowHeight;
|
|
||||||
if (showSavePasswordCheckbox)
|
if (showSavePasswordCheckbox)
|
||||||
h += checkboxRowHeight;
|
h += checkboxRowHeight;
|
||||||
return h;
|
return h;
|
||||||
@@ -447,7 +444,8 @@ FloatingWindow {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
echoMode: modelData.isSecret ? TextInput.Password : TextInput.Normal
|
showPasswordToggle: modelData.isSecret
|
||||||
|
echoMode: modelData.isSecret && !passwordVisible ? TextInput.Password : TextInput.Normal
|
||||||
placeholderText: getFieldLabel(modelData.name)
|
placeholderText: getFieldLabel(modelData.name)
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
enabled: root.visible
|
enabled: root.visible
|
||||||
@@ -549,7 +547,8 @@ FloatingWindow {
|
|||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
textColor: Theme.surfaceText
|
textColor: Theme.surfaceText
|
||||||
text: wifiPasswordInput
|
text: wifiPasswordInput
|
||||||
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
|
showPasswordToggle: true
|
||||||
|
echoMode: passwordVisible ? TextInput.Normal : TextInput.Password
|
||||||
placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : ""
|
placeholderText: (requiresEnterprise && !isVpnPrompt) ? I18n.tr("Password") : ""
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
enabled: root.visible
|
enabled: root.visible
|
||||||
@@ -628,88 +627,43 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Row {
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
width: parent.width
|
visible: showSavePasswordCheckbox
|
||||||
|
|
||||||
Row {
|
Rectangle {
|
||||||
spacing: Theme.spacingS
|
id: savePasswordCheckbox
|
||||||
visible: showShowPasswordCheckbox
|
|
||||||
|
|
||||||
Rectangle {
|
property bool checked: true
|
||||||
id: showPasswordCheckbox
|
|
||||||
|
|
||||||
property bool checked: false
|
width: 20
|
||||||
|
height: 20
|
||||||
|
radius: 4
|
||||||
|
color: checked ? Theme.primary : "transparent"
|
||||||
|
border.color: checked ? Theme.primary : Theme.outlineButton
|
||||||
|
border.width: 2
|
||||||
|
|
||||||
width: 20
|
DankIcon {
|
||||||
height: 20
|
anchors.centerIn: parent
|
||||||
radius: 4
|
name: "check"
|
||||||
color: checked ? Theme.primary : "transparent"
|
size: 12
|
||||||
border.color: checked ? Theme.primary : Theme.outlineButton
|
color: Theme.background
|
||||||
border.width: 2
|
visible: parent.checked
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "check"
|
|
||||||
size: 12
|
|
||||||
color: Theme.background
|
|
||||||
visible: parent.checked
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: showPasswordCheckbox.checked = !showPasswordCheckbox.checked
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
MouseArea {
|
||||||
text: I18n.tr("Show password")
|
anchors.fill: parent
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
hoverEnabled: true
|
||||||
color: Theme.surfaceText
|
cursorShape: Qt.PointingHandCursor
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
StyledText {
|
||||||
spacing: Theme.spacingS
|
text: I18n.tr("Save password")
|
||||||
visible: showSavePasswordCheckbox
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
Rectangle {
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
id: savePasswordCheckbox
|
|
||||||
|
|
||||||
property bool checked: false
|
|
||||||
|
|
||||||
width: 20
|
|
||||||
height: 20
|
|
||||||
radius: 4
|
|
||||||
color: checked ? Theme.primary : "transparent"
|
|
||||||
border.color: checked ? Theme.primary : Theme.outlineButton
|
|
||||||
border.width: 2
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "check"
|
|
||||||
size: 12
|
|
||||||
color: Theme.background
|
|
||||||
visible: parent.checked
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: savePasswordCheckbox.checked = !savePasswordCheckbox.checked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: I18n.tr("Save password")
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,21 @@ Rectangle {
|
|||||||
contentHeight: audioColumn.height
|
contentHeight: audioColumn.height
|
||||||
clip: true
|
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 {
|
Column {
|
||||||
id: audioColumn
|
id: audioColumn
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -133,16 +148,20 @@ Rectangle {
|
|||||||
const nodes = Pipewire.nodes.values.filter(node => {
|
const nodes = Pipewire.nodes.values.filter(node => {
|
||||||
return node.audio && !node.isSink && !node.isStream;
|
return node.audio && !node.isSink && !node.isStream;
|
||||||
});
|
});
|
||||||
const pins = SettingsData.audioInputDevicePins || {};
|
const pinnedList = audioContent.getPinnedInputs();
|
||||||
const pinnedName = pins["preferredInput"];
|
|
||||||
|
|
||||||
let sorted = [...nodes];
|
let sorted = [...nodes];
|
||||||
sorted.sort((a, b) => {
|
sorted.sort((a, b) => {
|
||||||
// Pinned device first
|
// Pinned device first
|
||||||
if (a.name === pinnedName && b.name !== pinnedName)
|
const aPinnedIndex = pinnedList.indexOf(a.name)
|
||||||
return -1;
|
const bPinnedIndex = pinnedList.indexOf(b.name)
|
||||||
if (b.name === pinnedName && a.name !== pinnedName)
|
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||||
return 1;
|
if (aPinnedIndex === -1)
|
||||||
|
return 1
|
||||||
|
if (bPinnedIndex === -1)
|
||||||
|
return -1
|
||||||
|
return aPinnedIndex - bPinnedIndex
|
||||||
|
}
|
||||||
// Then active device
|
// Then active device
|
||||||
if (a === AudioService.source && b !== AudioService.source)
|
if (a === AudioService.source && b !== AudioService.source)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -224,7 +243,7 @@ Rectangle {
|
|||||||
height: 28
|
height: 28
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +256,7 @@ Rectangle {
|
|||||||
name: "push_pin"
|
name: "push_pin"
|
||||||
size: 16
|
size: 16
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -245,12 +264,12 @@ Rectangle {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
|
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.audioInputDevicePins || {})["preferredInput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedInputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -261,16 +280,24 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}));
|
const pins = JSON.parse(JSON.stringify(SettingsData.audioInputDevicePins || {}))
|
||||||
const isCurrentlyPinned = pins["preferredInput"] === modelData.name;
|
let pinnedList = audioContent.normalizePinList(pins["preferredInput"])
|
||||||
|
const pinIndex = pinnedList.indexOf(modelData.name)
|
||||||
|
|
||||||
if (isCurrentlyPinned) {
|
if (pinIndex !== -1) {
|
||||||
delete pins["preferredInput"];
|
pinnedList.splice(pinIndex, 1)
|
||||||
} else {
|
} else {
|
||||||
pins["preferredInput"] = modelData.name;
|
pinnedList.unshift(modelData.name)
|
||||||
|
if (pinnedList.length > audioContent.maxPinnedInputs)
|
||||||
|
pinnedList = pinnedList.slice(0, audioContent.maxPinnedInputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsData.set("audioInputDevicePins", pins);
|
if (pinnedList.length > 0)
|
||||||
|
pins["preferredInput"] = pinnedList
|
||||||
|
else
|
||||||
|
delete pins["preferredInput"]
|
||||||
|
|
||||||
|
SettingsData.set("audioInputDevicePins", pins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,21 @@ Rectangle {
|
|||||||
contentHeight: audioColumn.height
|
contentHeight: audioColumn.height
|
||||||
clip: true
|
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 {
|
Column {
|
||||||
id: audioColumn
|
id: audioColumn
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -143,16 +158,20 @@ Rectangle {
|
|||||||
const nodes = Pipewire.nodes.values.filter(node => {
|
const nodes = Pipewire.nodes.values.filter(node => {
|
||||||
return node.audio && node.isSink && !node.isStream;
|
return node.audio && node.isSink && !node.isStream;
|
||||||
});
|
});
|
||||||
const pins = SettingsData.audioOutputDevicePins || {};
|
const pinnedList = audioContent.getPinnedOutputs();
|
||||||
const pinnedName = pins["preferredOutput"];
|
|
||||||
|
|
||||||
let sorted = [...nodes];
|
let sorted = [...nodes];
|
||||||
sorted.sort((a, b) => {
|
sorted.sort((a, b) => {
|
||||||
// Pinned device first
|
// Pinned device first
|
||||||
if (a.name === pinnedName && b.name !== pinnedName)
|
const aPinnedIndex = pinnedList.indexOf(a.name)
|
||||||
return -1;
|
const bPinnedIndex = pinnedList.indexOf(b.name)
|
||||||
if (b.name === pinnedName && a.name !== pinnedName)
|
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||||
return 1;
|
if (aPinnedIndex === -1)
|
||||||
|
return 1
|
||||||
|
if (bPinnedIndex === -1)
|
||||||
|
return -1
|
||||||
|
return aPinnedIndex - bPinnedIndex
|
||||||
|
}
|
||||||
// Then active device
|
// Then active device
|
||||||
if (a === AudioService.sink && b !== AudioService.sink)
|
if (a === AudioService.sink && b !== AudioService.sink)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -236,7 +255,7 @@ Rectangle {
|
|||||||
height: 28
|
height: 28
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +268,7 @@ Rectangle {
|
|||||||
name: "push_pin"
|
name: "push_pin"
|
||||||
size: 16
|
size: 16
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -257,12 +276,12 @@ Rectangle {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
|
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin");
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
const isThisDevicePinned = audioContent.getPinnedOutputs().includes(modelData.name);
|
||||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -273,16 +292,24 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}));
|
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}))
|
||||||
const isCurrentlyPinned = pins["preferredOutput"] === modelData.name;
|
let pinnedList = audioContent.normalizePinList(pins["preferredOutput"])
|
||||||
|
const pinIndex = pinnedList.indexOf(modelData.name)
|
||||||
|
|
||||||
if (isCurrentlyPinned) {
|
if (pinIndex !== -1) {
|
||||||
delete pins["preferredOutput"];
|
pinnedList.splice(pinIndex, 1)
|
||||||
} else {
|
} else {
|
||||||
pins["preferredOutput"] = modelData.name;
|
pinnedList.unshift(modelData.name)
|
||||||
|
if (pinnedList.length > audioContent.maxPinnedOutputs)
|
||||||
|
pinnedList = pinnedList.slice(0, audioContent.maxPinnedOutputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsData.set("audioOutputDevicePins", pins);
|
if (pinnedList.length > 0)
|
||||||
|
pins["preferredOutput"] = pinnedList
|
||||||
|
else
|
||||||
|
delete pins["preferredOutput"]
|
||||||
|
|
||||||
|
SettingsData.set("audioOutputDevicePins", pins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,21 @@ Rectangle {
|
|||||||
contentHeight: bluetoothColumn.height
|
contentHeight: bluetoothColumn.height
|
||||||
clip: true
|
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 {
|
Column {
|
||||||
id: bluetoothColumn
|
id: bluetoothColumn
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -162,14 +177,18 @@ Rectangle {
|
|||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
const pins = SettingsData.bluetoothDevicePins || {}
|
const pinnedList = bluetoothContent.getPinnedDevices()
|
||||||
const pinnedAddr = pins["preferredDevice"]
|
|
||||||
|
|
||||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
||||||
devices.sort((a, b) => {
|
devices.sort((a, b) => {
|
||||||
// Pinned device first
|
// Pinned device first
|
||||||
if (a.address === pinnedAddr && b.address !== pinnedAddr) return -1
|
const aPinnedIndex = pinnedList.indexOf(a.address)
|
||||||
if (b.address === pinnedAddr && a.address !== pinnedAddr) return 1
|
const bPinnedIndex = pinnedList.indexOf(b.address)
|
||||||
|
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||||
|
if (aPinnedIndex === -1) return 1
|
||||||
|
if (bPinnedIndex === -1) return -1
|
||||||
|
return aPinnedIndex - bPinnedIndex
|
||||||
|
}
|
||||||
// Then connected devices
|
// Then connected devices
|
||||||
if (a.connected && !b.connected) return -1
|
if (a.connected && !b.connected) return -1
|
||||||
if (!a.connected && b.connected) return 1
|
if (!a.connected && b.connected) return 1
|
||||||
@@ -302,7 +321,7 @@ Rectangle {
|
|||||||
height: 28
|
height: 28
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
|
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
|
||||||
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05)
|
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +334,7 @@ Rectangle {
|
|||||||
name: "push_pin"
|
name: "push_pin"
|
||||||
size: 16
|
size: 16
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
|
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
|
||||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
|
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -323,12 +342,12 @@ Rectangle {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
|
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
|
||||||
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin")
|
return isThisDevicePinned ? I18n.tr("Pinned") : I18n.tr("Pin")
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: {
|
color: {
|
||||||
const isThisDevicePinned = (SettingsData.bluetoothDevicePins || {})["preferredDevice"] === modelData.address
|
const isThisDevicePinned = bluetoothContent.getPinnedDevices().includes(modelData.address)
|
||||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
|
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -340,14 +359,22 @@ Rectangle {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const pins = JSON.parse(JSON.stringify(SettingsData.bluetoothDevicePins || {}))
|
const pins = JSON.parse(JSON.stringify(SettingsData.bluetoothDevicePins || {}))
|
||||||
const isCurrentlyPinned = pins["preferredDevice"] === modelData.address
|
let pinnedList = bluetoothContent.normalizePinList(pins["preferredDevice"])
|
||||||
|
const pinIndex = pinnedList.indexOf(modelData.address)
|
||||||
|
|
||||||
if (isCurrentlyPinned) {
|
if (pinIndex !== -1) {
|
||||||
delete pins["preferredDevice"]
|
pinnedList.splice(pinIndex, 1)
|
||||||
} else {
|
} else {
|
||||||
pins["preferredDevice"] = modelData.address
|
pinnedList.unshift(modelData.address)
|
||||||
|
if (pinnedList.length > bluetoothContent.maxPinnedDevices)
|
||||||
|
pinnedList = pinnedList.slice(0, bluetoothContent.maxPinnedDevices)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pinnedList.length > 0)
|
||||||
|
pins["preferredDevice"] = pinnedList
|
||||||
|
else
|
||||||
|
delete pins["preferredDevice"]
|
||||||
|
|
||||||
SettingsData.set("bluetoothDevicePins", pins)
|
SettingsData.set("bluetoothDevicePins", pins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ Rectangle {
|
|||||||
NetworkService.removeRef();
|
NetworkService.removeRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property bool hasEthernetAvailable: (NetworkService.ethernetDevices?.length ?? 0) > 0
|
||||||
|
property bool hasWifiAvailable: (NetworkService.wifiDevices?.length ?? 0) > 0
|
||||||
|
property bool hasBothConnectionTypes: hasEthernetAvailable && hasWifiAvailable
|
||||||
|
|
||||||
property int currentPreferenceIndex: {
|
property int currentPreferenceIndex: {
|
||||||
if (DMSService.apiVersion < 5) {
|
if (DMSService.apiVersion < 5) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -46,19 +50,24 @@ Rectangle {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pref = NetworkService.userPreference;
|
if (!hasEthernetAvailable) {
|
||||||
const status = NetworkService.networkStatus;
|
return 1;
|
||||||
let index = 1;
|
|
||||||
|
|
||||||
if (pref === "ethernet") {
|
|
||||||
index = 0;
|
|
||||||
} else if (pref === "wifi") {
|
|
||||||
index = 1;
|
|
||||||
} else {
|
|
||||||
index = status === "ethernet" ? 0 : 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
if (!hasWifiAvailable) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pref = NetworkService.userPreference;
|
||||||
|
const status = NetworkService.networkStatus;
|
||||||
|
|
||||||
|
if (pref === "ethernet") {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (pref === "wifi") {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return status === "ethernet" ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
@@ -117,7 +126,7 @@ Rectangle {
|
|||||||
DankButtonGroup {
|
DankButtonGroup {
|
||||||
id: preferenceControls
|
id: preferenceControls
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10
|
visible: hasBothConnectionTypes && NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10
|
||||||
buttonHeight: 28
|
buttonHeight: 28
|
||||||
textSize: Theme.fontSizeSmall
|
textSize: Theme.fontSizeSmall
|
||||||
|
|
||||||
@@ -454,20 +463,39 @@ Rectangle {
|
|||||||
contentHeight: wifiColumn.height
|
contentHeight: wifiColumn.height
|
||||||
clip: true
|
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 var frozenNetworks: []
|
||||||
property bool menuOpen: false
|
property bool menuOpen: false
|
||||||
property var sortedNetworks: {
|
property var sortedNetworks: {
|
||||||
const ssid = NetworkService.currentWifiSSID;
|
const ssid = NetworkService.currentWifiSSID;
|
||||||
const networks = NetworkService.wifiNetworks;
|
const networks = NetworkService.wifiNetworks;
|
||||||
const pins = SettingsData.wifiNetworkPins || {};
|
const pinnedList = getPinnedNetworks()
|
||||||
const pinnedSSID = pins["preferredWifi"];
|
|
||||||
|
|
||||||
let sorted = [...networks];
|
let sorted = [...networks];
|
||||||
sorted.sort((a, b) => {
|
sorted.sort((a, b) => {
|
||||||
if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID)
|
const aPinnedIndex = pinnedList.indexOf(a.ssid)
|
||||||
return -1;
|
const bPinnedIndex = pinnedList.indexOf(b.ssid)
|
||||||
if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID)
|
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||||
return 1;
|
if (aPinnedIndex === -1)
|
||||||
|
return 1
|
||||||
|
if (bPinnedIndex === -1)
|
||||||
|
return -1
|
||||||
|
return aPinnedIndex - bPinnedIndex
|
||||||
|
}
|
||||||
if (a.ssid === ssid)
|
if (a.ssid === ssid)
|
||||||
return -1;
|
return -1;
|
||||||
if (b.ssid === ssid)
|
if (b.ssid === ssid)
|
||||||
@@ -616,7 +644,7 @@ Rectangle {
|
|||||||
height: 28
|
height: 28
|
||||||
radius: height / 2
|
radius: height / 2
|
||||||
color: {
|
color: {
|
||||||
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
|
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
|
||||||
return isThisNetworkPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
return isThisNetworkPinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +657,7 @@ Rectangle {
|
|||||||
name: "push_pin"
|
name: "push_pin"
|
||||||
size: 16
|
size: 16
|
||||||
color: {
|
color: {
|
||||||
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
|
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
|
||||||
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
|
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -637,12 +665,12 @@ Rectangle {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
|
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
|
||||||
return isThisNetworkPinned ? I18n.tr("Pinned") : I18n.tr("Pin");
|
return isThisNetworkPinned ? I18n.tr("Pinned") : I18n.tr("Pin");
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: {
|
color: {
|
||||||
const isThisNetworkPinned = (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid;
|
const isThisNetworkPinned = wifiContent.getPinnedNetworks().includes(modelData.ssid);
|
||||||
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
|
return isThisNetworkPinned ? Theme.primary : Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -653,16 +681,24 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
|
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}))
|
||||||
const isCurrentlyPinned = pins["preferredWifi"] === modelData.ssid;
|
let pinnedList = wifiContent.normalizePinList(pins["preferredWifi"])
|
||||||
|
const pinIndex = pinnedList.indexOf(modelData.ssid)
|
||||||
|
|
||||||
if (isCurrentlyPinned) {
|
if (pinIndex !== -1) {
|
||||||
delete pins["preferredWifi"];
|
pinnedList.splice(pinIndex, 1)
|
||||||
} else {
|
} else {
|
||||||
pins["preferredWifi"] = modelData.ssid;
|
pinnedList.unshift(modelData.ssid)
|
||||||
|
if (pinnedList.length > wifiContent.maxPinnedNetworks)
|
||||||
|
pinnedList = pinnedList.slice(0, wifiContent.maxPinnedNetworks)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsData.set("wifiNetworkPins", pins);
|
if (pinnedList.length > 0)
|
||||||
|
pins["preferredWifi"] = pinnedList
|
||||||
|
else
|
||||||
|
delete pins["preferredWifi"]
|
||||||
|
|
||||||
|
SettingsData.set("wifiNetworkPins", pins)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -678,8 +714,8 @@ Rectangle {
|
|||||||
if (modelData.secured && !modelData.saved) {
|
if (modelData.secured && !modelData.saved) {
|
||||||
if (DMSService.apiVersion >= 7) {
|
if (DMSService.apiVersion >= 7) {
|
||||||
NetworkService.connectToWifi(modelData.ssid);
|
NetworkService.connectToWifi(modelData.ssid);
|
||||||
} else if (PopoutService.wifiPasswordModal) {
|
} else {
|
||||||
PopoutService.wifiPasswordModal.show(modelData.ssid);
|
PopoutService.showWifiPasswordModal(modelData.ssid);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NetworkService.connectToWifi(modelData.ssid);
|
NetworkService.connectToWifi(modelData.ssid);
|
||||||
@@ -740,8 +776,8 @@ Rectangle {
|
|||||||
if (networkContextMenu.currentSecured && !networkContextMenu.currentSaved) {
|
if (networkContextMenu.currentSecured && !networkContextMenu.currentSaved) {
|
||||||
if (DMSService.apiVersion >= 7) {
|
if (DMSService.apiVersion >= 7) {
|
||||||
NetworkService.connectToWifi(networkContextMenu.currentSSID);
|
NetworkService.connectToWifi(networkContextMenu.currentSSID);
|
||||||
} else if (PopoutService.wifiPasswordModal) {
|
} else {
|
||||||
PopoutService.wifiPasswordModal.show(networkContextMenu.currentSSID);
|
PopoutService.showWifiPasswordModal(networkContextMenu.currentSSID);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NetworkService.connectToWifi(networkContextMenu.currentSSID);
|
NetworkService.connectToWifi(networkContextMenu.currentSSID);
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Item {
|
|||||||
|
|
||||||
function getRealWorkspaces() {
|
function getRealWorkspaces() {
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return NiriService.getCurrentOutputWorkspaceNumbers();
|
return NiriService.getCurrentOutputWorkspaceNumbers();
|
||||||
}
|
}
|
||||||
const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName).map(ws => ws.idx + 1);
|
const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName).map(ws => ws.idx + 1);
|
||||||
@@ -47,7 +47,7 @@ Item {
|
|||||||
} else if (CompositorService.isHyprland) {
|
} else if (CompositorService.isHyprland) {
|
||||||
const workspaces = Hyprland.workspaces?.values || [];
|
const workspaces = Hyprland.workspaces?.values || [];
|
||||||
|
|
||||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
const sorted = workspaces.slice().sort((a, b) => a.id - b.id);
|
const sorted = workspaces.slice().sort((a, b) => a.id - b.id);
|
||||||
const filtered = sorted.filter(ws => ws.id > -1);
|
const filtered = sorted.filter(ws => ws.id > -1);
|
||||||
return filtered.length > 0 ? filtered : [
|
return filtered.length > 0 ? filtered : [
|
||||||
@@ -91,7 +91,7 @@ Item {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return workspaces.slice().sort((a, b) => a.num - b.num);
|
return workspaces.slice().sort((a, b) => a.num - b.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ Item {
|
|||||||
|
|
||||||
function getCurrentWorkspace() {
|
function getCurrentWorkspace() {
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return NiriService.getCurrentWorkspaceNumber();
|
return NiriService.getCurrentWorkspaceNumber();
|
||||||
}
|
}
|
||||||
const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active);
|
const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active);
|
||||||
@@ -125,7 +125,7 @@ Item {
|
|||||||
const activeTags = DwlService.getActiveTags(barWindow.screenName);
|
const activeTags = DwlService.getActiveTags(barWindow.screenName);
|
||||||
return activeTags.length > 0 ? activeTags[0] : 0;
|
return activeTags.length > 0 ? activeTags[0] : 0;
|
||||||
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
} else if (CompositorService.isSway || CompositorService.isScroll) {
|
||||||
if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!barWindow.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
return focusedWs ? focusedWs.num : 1;
|
return focusedWs ? focusedWs.num : 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ BasePill {
|
|||||||
property bool showMicPercent: widgetData?.showMicPercent !== undefined ? widgetData.showMicPercent : SettingsData.controlCenterShowMicPercent
|
property bool showMicPercent: widgetData?.showMicPercent !== undefined ? widgetData.showMicPercent : SettingsData.controlCenterShowMicPercent
|
||||||
property bool showBatteryIcon: widgetData?.showBatteryIcon !== undefined ? widgetData.showBatteryIcon : SettingsData.controlCenterShowBatteryIcon
|
property bool showBatteryIcon: widgetData?.showBatteryIcon !== undefined ? widgetData.showBatteryIcon : SettingsData.controlCenterShowBatteryIcon
|
||||||
property bool showPrinterIcon: widgetData?.showPrinterIcon !== undefined ? widgetData.showPrinterIcon : SettingsData.controlCenterShowPrinterIcon
|
property bool showPrinterIcon: widgetData?.showPrinterIcon !== undefined ? widgetData.showPrinterIcon : SettingsData.controlCenterShowPrinterIcon
|
||||||
|
property bool showScreenSharingIcon: widgetData?.showScreenSharingIcon !== undefined ? widgetData.showScreenSharingIcon : SettingsData.controlCenterShowScreenSharingIcon
|
||||||
property real touchpadThreshold: 100
|
property real touchpadThreshold: 100
|
||||||
property real micAccumulator: 0
|
property real micAccumulator: 0
|
||||||
property real volumeAccumulator: 0
|
property real volumeAccumulator: 0
|
||||||
property real brightnessAccumulator: 0
|
property real brightnessAccumulator: 0
|
||||||
|
readonly property real vIconSize: Theme.barIconSize(root.barThickness, -4)
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: root.showPrinterIcon
|
active: root.showPrinterIcon
|
||||||
@@ -213,7 +215,25 @@ BasePill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hasNoVisibleIcons() {
|
function hasNoVisibleIcons() {
|
||||||
return !root.showNetworkIcon && !root.showBluetoothIcon && !root.showAudioIcon && !root.showVpnIcon && !root.showBrightnessIcon && !root.showMicIcon && !root.showBatteryIcon && !root.showPrinterIcon;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
content: Component {
|
content: Component {
|
||||||
@@ -224,48 +244,74 @@ BasePill {
|
|||||||
Column {
|
Column {
|
||||||
id: controlColumn
|
id: controlColumn
|
||||||
visible: root.isVerticalOrientation
|
visible: root.isVerticalOrientation
|
||||||
anchors.centerIn: parent
|
width: root.vIconSize
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
name: root.getNetworkIconName()
|
width: root.vIconSize
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
height: root.vIconSize
|
||||||
color: root.getNetworkIconColor()
|
visible: root.showScreenSharingIcon && NiriService.hasCasts
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
DankIcon {
|
||||||
|
name: "screen_record"
|
||||||
|
size: root.vIconSize
|
||||||
|
color: NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: root.vIconSize
|
||||||
|
height: root.vIconSize
|
||||||
visible: root.showNetworkIcon && NetworkService.networkAvailable
|
visible: root.showNetworkIcon && NetworkService.networkAvailable
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: root.getNetworkIconName()
|
||||||
|
size: root.vIconSize
|
||||||
|
color: root.getNetworkIconColor()
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
name: "vpn_lock"
|
width: root.vIconSize
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
height: root.vIconSize
|
||||||
color: NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
|
visible: root.showVpnIcon && NetworkService.vpnAvailable && NetworkService.vpnConnected
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "vpn_lock"
|
||||||
|
size: root.vIconSize
|
||||||
|
color: NetworkService.vpnConnected ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
name: "bluetooth"
|
width: root.vIconSize
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
height: root.vIconSize
|
||||||
color: BluetoothService.connected ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled
|
visible: root.showBluetoothIcon && BluetoothService.available && BluetoothService.enabled
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "bluetooth"
|
||||||
|
size: root.vIconSize
|
||||||
|
color: BluetoothService.connected ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
width: audioIconV.implicitWidth + 4
|
width: root.vIconSize
|
||||||
height: audioIconV.implicitHeight + (root.showAudioPercent ? audioPercentV.implicitHeight : 0) + 4
|
height: root.vIconSize + (root.showAudioPercent ? audioPercentV.implicitHeight + 2 : 0)
|
||||||
color: "transparent"
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showAudioIcon
|
visible: root.showAudioIcon
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
id: audioIconV
|
id: audioIconV
|
||||||
name: root.getVolumeIconName()
|
name: root.getVolumeIconName()
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
size: root.vIconSize
|
||||||
color: Theme.widgetIconColor
|
color: Theme.widgetIconColor
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -292,21 +338,18 @@ BasePill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
width: micIconV.implicitWidth + 4
|
width: root.vIconSize
|
||||||
height: micIconV.implicitHeight + (root.showAudioPercent ? micPercentV.implicitHeight : 0) + 4
|
height: root.vIconSize + (root.showMicPercent ? micPercentV.implicitHeight + 2 : 0)
|
||||||
color: "transparent"
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showMicIcon
|
visible: root.showMicIcon
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
id: micIconV
|
id: micIconV
|
||||||
name: root.getMicIconName()
|
name: root.getMicIconName()
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
size: root.vIconSize
|
||||||
color: root.getMicIconColor()
|
color: root.getMicIconColor()
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -333,21 +376,18 @@ BasePill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Item {
|
||||||
width: brightnessIconV.implicitWidth + 4
|
width: root.vIconSize
|
||||||
height: brightnessIconV.implicitHeight + (root.showBrightnessPercent ? brightnessPercentV.implicitHeight : 0) + 4
|
height: root.vIconSize + (root.showBrightnessPercent ? brightnessPercentV.implicitHeight + 2 : 0)
|
||||||
color: "transparent"
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
|
visible: root.showBrightnessIcon && DisplayService.brightnessAvailable && root.hasPinnedBrightnessDevice()
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
id: brightnessIconV
|
id: brightnessIconV
|
||||||
name: root.getBrightnessIconName()
|
name: root.getBrightnessIconName()
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
size: root.vIconSize
|
||||||
color: Theme.widgetIconColor
|
color: Theme.widgetIconColor
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -371,28 +411,43 @@ BasePill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
width: root.vIconSize
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
height: root.vIconSize
|
||||||
color: root.getBatteryIconColor()
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showBatteryIcon && BatteryService.batteryAvailable
|
visible: root.showBatteryIcon && BatteryService.batteryAvailable
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
||||||
|
size: root.vIconSize
|
||||||
|
color: root.getBatteryIconColor()
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
name: "print"
|
width: root.vIconSize
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
height: root.vIconSize
|
||||||
color: Theme.primary
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
|
visible: root.showPrinterIcon && CupsService.cupsAvailable && root.hasPrintJobs()
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "print"
|
||||||
|
size: root.vIconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
Item {
|
||||||
name: "settings"
|
width: root.vIconSize
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
height: root.vIconSize
|
||||||
color: root.isActive ? Theme.primary : Theme.widgetIconColor
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: root.hasNoVisibleIcons()
|
visible: root.hasNoVisibleIcons()
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "settings"
|
||||||
|
size: root.vIconSize
|
||||||
|
color: root.isActive ? Theme.primary : Theme.widgetIconColor
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,6 +457,14 @@ BasePill {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "screen_record"
|
||||||
|
size: Theme.barIconSize(root.barThickness, -4)
|
||||||
|
color: NiriService.hasActiveCast ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: root.showScreenSharingIcon && NiriService.hasCasts
|
||||||
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
id: networkIcon
|
id: networkIcon
|
||||||
name: root.getNetworkIconName()
|
name: root.getNetworkIconName()
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ BasePill {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onAppIdSubstitutionsChanged() {
|
||||||
|
root.updateDesktopEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateDesktopEntry() {
|
function updateDesktopEntry() {
|
||||||
if (activeWindow && activeWindow.appId) {
|
if (activeWindow && activeWindow.appId) {
|
||||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
||||||
@@ -153,24 +160,12 @@ BasePill {
|
|||||||
size: 18
|
size: 18
|
||||||
name: "sports_esports"
|
name: "sports_esports"
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
visible: {
|
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && Paths.isSteamApp(activeWindow.appId)
|
||||||
if (!root.isVerticalOrientation || !activeWindow || !activeWindow.appId)
|
|
||||||
return false;
|
|
||||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
|
||||||
return moddedId.toLowerCase().includes("steam_app");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: {
|
visible: root.isVerticalOrientation && activeWindow && activeWindow.appId && appIcon.status !== Image.Ready && !Paths.isSteamApp(activeWindow.appId)
|
||||||
if (!root.isVerticalOrientation || !activeWindow || !activeWindow.appId)
|
|
||||||
return false;
|
|
||||||
if (appIcon.status === Image.Ready)
|
|
||||||
return false;
|
|
||||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
|
||||||
return !moddedId.toLowerCase().includes("steam_app");
|
|
||||||
}
|
|
||||||
text: {
|
text: {
|
||||||
if (!activeWindow || !activeWindow.appId)
|
if (!activeWindow || !activeWindow.appId)
|
||||||
return "?";
|
return "?";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ BasePill {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
|
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
|
||||||
size: Theme.barIconSize(root.barThickness, -4)
|
size: Theme.barIconSize(root.barThickness, -4)
|
||||||
color: SessionData.doNotDisturb ? Theme.error : (root.isActive ? Theme.primary : Theme.widgetIconColor)
|
color: SessionData.doNotDisturb ? Theme.primary : (root.isActive ? Theme.primary : Theme.widgetIconColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -35,6 +35,6 @@ BasePill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
SessionData.setDoNotDisturb(!SessionData.doNotDisturb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ Item {
|
|||||||
|
|
||||||
property int _desktopEntriesUpdateTrigger: 0
|
property int _desktopEntriesUpdateTrigger: 0
|
||||||
property int _toplevelsUpdateTrigger: 0
|
property int _toplevelsUpdateTrigger: 0
|
||||||
|
property int _appIdSubstitutionsTrigger: 0
|
||||||
|
|
||||||
readonly property var sortedToplevels: {
|
readonly property var sortedToplevels: {
|
||||||
_toplevelsUpdateTrigger;
|
_toplevelsUpdateTrigger;
|
||||||
@@ -95,6 +96,13 @@ Item {
|
|||||||
_desktopEntriesUpdateTrigger++;
|
_desktopEntriesUpdateTrigger++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onAppIdSubstitutionsChanged() {
|
||||||
|
_appIdSubstitutionsTrigger++;
|
||||||
|
}
|
||||||
|
}
|
||||||
readonly property var groupedWindows: {
|
readonly property var groupedWindows: {
|
||||||
if (!SettingsData.runningAppsGroupByApp) {
|
if (!SettingsData.runningAppsGroupByApp) {
|
||||||
return [];
|
return [];
|
||||||
@@ -364,6 +372,7 @@ Item {
|
|||||||
height: Theme.barIconSize(root.barThickness)
|
height: Theme.barIconSize(root.barThickness)
|
||||||
source: {
|
source: {
|
||||||
root._desktopEntriesUpdateTrigger;
|
root._desktopEntriesUpdateTrigger;
|
||||||
|
root._appIdSubstitutionsTrigger;
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return "";
|
return "";
|
||||||
const moddedId = Paths.moddedAppId(appId);
|
const moddedId = Paths.moddedAppId(appId);
|
||||||
@@ -391,20 +400,12 @@ Item {
|
|||||||
size: Theme.barIconSize(root.barThickness)
|
size: Theme.barIconSize(root.barThickness)
|
||||||
name: "sports_esports"
|
name: "sports_esports"
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
visible: {
|
visible: !iconImg.visible && Paths.isSteamApp(appId)
|
||||||
const moddedId = Paths.moddedAppId(appId);
|
|
||||||
return moddedId.toLowerCase().includes("steam_app");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback text if no icon found
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: {
|
visible: !iconImg.visible && !Paths.isSteamApp(appId)
|
||||||
const moddedId = Paths.moddedAppId(appId);
|
|
||||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app");
|
|
||||||
return !iconImg.visible && !isSteamApp;
|
|
||||||
}
|
|
||||||
text: {
|
text: {
|
||||||
root._desktopEntriesUpdateTrigger;
|
root._desktopEntriesUpdateTrigger;
|
||||||
if (!appId)
|
if (!appId)
|
||||||
@@ -502,8 +503,10 @@ Item {
|
|||||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
|
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
|
||||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||||
const relativeX = globalPos.x - screenX;
|
const relativeX = globalPos.x - screenX;
|
||||||
const yPos = root.barThickness + root.barSpacing - 7;
|
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height;
|
||||||
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top");
|
const isBottom = root.axis?.edge === "bottom";
|
||||||
|
const yPos = isBottom ? (screenHeight - root.barThickness - root.barSpacing - 32 - Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS);
|
||||||
|
windowContextMenuLoader.item.showAt(relativeX, yPos, false, root.axis?.edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (mouse.button === Qt.MiddleButton) {
|
} else if (mouse.button === Qt.MiddleButton) {
|
||||||
@@ -614,6 +617,7 @@ Item {
|
|||||||
height: Theme.barIconSize(root.barThickness)
|
height: Theme.barIconSize(root.barThickness)
|
||||||
source: {
|
source: {
|
||||||
root._desktopEntriesUpdateTrigger;
|
root._desktopEntriesUpdateTrigger;
|
||||||
|
root._appIdSubstitutionsTrigger;
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return "";
|
return "";
|
||||||
const moddedId = Paths.moddedAppId(appId);
|
const moddedId = Paths.moddedAppId(appId);
|
||||||
@@ -641,19 +645,12 @@ Item {
|
|||||||
size: Theme.barIconSize(root.barThickness)
|
size: Theme.barIconSize(root.barThickness)
|
||||||
name: "sports_esports"
|
name: "sports_esports"
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
visible: {
|
visible: !iconImg.visible && Paths.isSteamApp(appId)
|
||||||
const moddedId = Paths.moddedAppId(appId);
|
|
||||||
return moddedId.toLowerCase().includes("steam_app");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: {
|
visible: !iconImg.visible && !Paths.isSteamApp(appId)
|
||||||
const moddedId = Paths.moddedAppId(appId);
|
|
||||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app");
|
|
||||||
return !iconImg.visible && !isSteamApp;
|
|
||||||
}
|
|
||||||
text: {
|
text: {
|
||||||
root._desktopEntriesUpdateTrigger;
|
root._desktopEntriesUpdateTrigger;
|
||||||
if (!appId)
|
if (!appId)
|
||||||
@@ -751,8 +748,10 @@ Item {
|
|||||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
|
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
|
||||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||||
const relativeX = globalPos.x - screenX;
|
const relativeX = globalPos.x - screenX;
|
||||||
const yPos = root.barThickness + root.barSpacing - 7;
|
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height;
|
||||||
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top");
|
const isBottom = root.axis?.edge === "bottom";
|
||||||
|
const yPos = isBottom ? (screenHeight - root.barThickness - root.barSpacing - 32 - Theme.spacingXS) : (root.barThickness + root.barSpacing + Theme.spacingXS);
|
||||||
|
windowContextMenuLoader.item.showAt(relativeX, yPos, false, root.axis?.edge);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1208,7 +1208,7 @@ Item {
|
|||||||
visible: entryStack.count === 0
|
visible: entryStack.count === 0
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 28
|
height: 28
|
||||||
radius: 0
|
radius: Theme.cornerRadius
|
||||||
color: visibilityToggleArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.withAlpha(Theme.surfaceContainer, 0)
|
color: visibilityToggleArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.withAlpha(Theme.surfaceContainer, 0)
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -1261,7 +1261,7 @@ Item {
|
|||||||
visible: entryStack.count > 0
|
visible: entryStack.count > 0
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 28
|
height: 28
|
||||||
radius: 0
|
radius: Theme.cornerRadius
|
||||||
color: backArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.withAlpha(Theme.surfaceContainer, 0)
|
color: backArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.withAlpha(Theme.surfaceContainer, 0)
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
@@ -1309,11 +1309,10 @@ Item {
|
|||||||
|
|
||||||
width: menuColumn.width
|
width: menuColumn.width
|
||||||
height: menuEntry?.isSeparator ? 1 : 28
|
height: menuEntry?.isSeparator ? 1 : 28
|
||||||
radius: 0
|
radius: menuEntry?.isSeparator ? 0 : Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (menuEntry?.isSeparator) {
|
if (menuEntry?.isSeparator)
|
||||||
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2);
|
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2);
|
||||||
}
|
|
||||||
return itemArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.withAlpha(Theme.surfaceContainer, 0);
|
return itemArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.withAlpha(Theme.surfaceContainer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,26 @@ Item {
|
|||||||
return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName);
|
return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, screenName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property string effectiveScreenName: {
|
||||||
|
if (!SettingsData.workspaceFollowFocus)
|
||||||
|
return root.screenName;
|
||||||
|
|
||||||
|
switch (CompositorService.compositor) {
|
||||||
|
case "niri":
|
||||||
|
return NiriService.currentOutput || root.screenName;
|
||||||
|
case "hyprland":
|
||||||
|
return Hyprland.focusedWorkspace?.monitor?.name || root.screenName;
|
||||||
|
case "dwl":
|
||||||
|
return DwlService.activeOutput || root.screenName;
|
||||||
|
case "sway":
|
||||||
|
case "scroll":
|
||||||
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
|
return focusedWs?.monitor?.name || root.screenName;
|
||||||
|
default:
|
||||||
|
return root.screenName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && ExtWorkspaceService.extWorkspaceAvailable)
|
readonly property bool useExtWorkspace: DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && ExtWorkspaceService.extWorkspaceAvailable)
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -94,7 +114,7 @@ Item {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return workspaces.slice().sort((a, b) => a.num - b.num);
|
return workspaces.slice().sort((a, b) => a.num - b.num);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +127,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getSwayActiveWorkspace() {
|
function getSwayActiveWorkspace() {
|
||||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
return focusedWs ? focusedWs.num : 1;
|
return focusedWs ? focusedWs.num : 1;
|
||||||
}
|
}
|
||||||
@@ -137,7 +157,7 @@ Item {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
filtered = filtered.slice().sort((a, b) => a.id - b.id);
|
filtered = filtered.slice().sort((a, b) => a.id - b.id);
|
||||||
} else {
|
} else {
|
||||||
const monitorWorkspaces = filtered.filter(ws => ws.monitor?.name === root.screenName);
|
const monitorWorkspaces = filtered.filter(ws => ws.monitor?.name === root.screenName);
|
||||||
@@ -163,7 +183,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getHyprlandActiveWorkspace() {
|
function getHyprlandActiveWorkspace() {
|
||||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return Hyprland.focusedWorkspace?.id || 1;
|
return Hyprland.focusedWorkspace?.id || 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +203,7 @@ Item {
|
|||||||
if (wsNumber <= 0) {
|
if (wsNumber <= 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNumber && w.output === root.screenName);
|
const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNumber && w.output === root.effectiveScreenName);
|
||||||
if (!workspace) {
|
if (!workspace) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -211,7 +231,7 @@ Item {
|
|||||||
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true);
|
||||||
isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false;
|
isActiveWs = focusedWs ? (focusedWs.num === targetWorkspaceId) : false;
|
||||||
} else if (CompositorService.isDwl) {
|
} else if (CompositorService.isDwl) {
|
||||||
const output = DwlService.getOutputState(root.screenName);
|
const output = DwlService.getOutputState(root.effectiveScreenName);
|
||||||
if (output && output.tags) {
|
if (output && output.tags) {
|
||||||
const tag = output.tags.find(t => t.tag === targetWorkspaceId);
|
const tag = output.tags.find(t => t.tag === targetWorkspaceId);
|
||||||
isActiveWs = tag ? (tag.state === 1) : false;
|
isActiveWs = tag ? (tag.state === 1) : false;
|
||||||
@@ -244,16 +264,16 @@ Item {
|
|||||||
const key = isActiveWs || !SettingsData.groupWorkspaceApps ? `${keyBase}_${i}` : keyBase;
|
const key = isActiveWs || !SettingsData.groupWorkspaceApps ? `${keyBase}_${i}` : keyBase;
|
||||||
|
|
||||||
if (!byApp[key]) {
|
if (!byApp[key]) {
|
||||||
const moddedId = Paths.moddedAppId(keyBase);
|
|
||||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app");
|
|
||||||
const isQuickshell = keyBase === "org.quickshell";
|
const isQuickshell = keyBase === "org.quickshell";
|
||||||
const desktopEntry = DesktopEntries.heuristicLookup(keyBase);
|
const isSteamApp = Paths.isSteamApp(keyBase);
|
||||||
const icon = isSteamApp ? "" : Paths.getAppIcon(keyBase, desktopEntry);
|
const moddedId = Paths.moddedAppId(keyBase);
|
||||||
|
const desktopEntry = DesktopEntries.heuristicLookup(moddedId);
|
||||||
|
const icon = Paths.getAppIcon(keyBase, desktopEntry);
|
||||||
byApp[key] = {
|
byApp[key] = {
|
||||||
"type": "icon",
|
"type": "icon",
|
||||||
"icon": icon,
|
"icon": icon,
|
||||||
"isSteamApp": isSteamApp,
|
|
||||||
"isQuickshell": isQuickshell,
|
"isQuickshell": isQuickshell,
|
||||||
|
"isSteamApp": isSteamApp,
|
||||||
"active": !!((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)),
|
"active": !!((w.activated || w.is_focused) || (CompositorService.isNiri && w.is_focused)),
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"windowId": w.address || w.id,
|
"windowId": w.address || w.id,
|
||||||
@@ -308,7 +328,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let workspaces;
|
let workspaces;
|
||||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
workspaces = NiriService.getCurrentOutputWorkspaceNumbers();
|
workspaces = NiriService.getCurrentOutputWorkspaceNumbers();
|
||||||
} else {
|
} else {
|
||||||
const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName).map(ws => ws.idx + 1);
|
const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName).map(ws => ws.idx + 1);
|
||||||
@@ -320,7 +340,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return workspaces.filter(wsNum => {
|
return workspaces.filter(wsNum => {
|
||||||
const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNum && w.output === root.screenName);
|
const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNum && w.output === root.effectiveScreenName);
|
||||||
if (!workspace)
|
if (!workspace)
|
||||||
return false;
|
return false;
|
||||||
if (workspace.is_active)
|
if (workspace.is_active)
|
||||||
@@ -334,7 +354,7 @@ Item {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
if (!root.screenName || SettingsData.workspaceFollowFocus) {
|
||||||
return NiriService.getCurrentWorkspaceNumber();
|
return NiriService.getCurrentWorkspaceNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,14 +363,13 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDwlTags() {
|
function getDwlTags() {
|
||||||
if (!DwlService.dwlAvailable) {
|
if (!DwlService.dwlAvailable)
|
||||||
return [];
|
return [];
|
||||||
}
|
|
||||||
|
|
||||||
const output = DwlService.getOutputState(root.screenName);
|
const targetScreen = root.effectiveScreenName;
|
||||||
if (!output || !output.tags || output.tags.length === 0) {
|
const output = DwlService.getOutputState(targetScreen);
|
||||||
|
if (!output || !output.tags || output.tags.length === 0)
|
||||||
return [];
|
return [];
|
||||||
}
|
|
||||||
|
|
||||||
if (SettingsData.dwlShowAllTags) {
|
if (SettingsData.dwlShowAllTags) {
|
||||||
return output.tags.map(tag => ({
|
return output.tags.map(tag => ({
|
||||||
@@ -361,7 +380,7 @@ Item {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const visibleTagIndices = DwlService.getVisibleTags(root.screenName);
|
const visibleTagIndices = DwlService.getVisibleTags(targetScreen);
|
||||||
return visibleTagIndices.map(tagIndex => {
|
return visibleTagIndices.map(tagIndex => {
|
||||||
const tagData = output.tags.find(t => t.tag === tagIndex);
|
const tagData = output.tags.find(t => t.tag === tagIndex);
|
||||||
return {
|
return {
|
||||||
@@ -374,12 +393,10 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDwlActiveTags() {
|
function getDwlActiveTags() {
|
||||||
if (!DwlService.dwlAvailable) {
|
if (!DwlService.dwlAvailable)
|
||||||
return [];
|
return [];
|
||||||
}
|
|
||||||
|
|
||||||
const activeTags = DwlService.getActiveTags(root.screenName);
|
return DwlService.getActiveTags(root.effectiveScreenName);
|
||||||
return activeTags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExtWorkspaceWorkspaces() {
|
function getExtWorkspaceWorkspaces() {
|
||||||
@@ -790,6 +807,68 @@ Item {
|
|||||||
readonly property real visualWidth: baseWidth + iconsExtraWidth
|
readonly property real visualWidth: baseWidth + iconsExtraWidth
|
||||||
readonly property real visualHeight: baseHeight + iconsExtraHeight
|
readonly property real visualHeight: baseHeight + iconsExtraHeight
|
||||||
|
|
||||||
|
readonly property color unfocusedColor: {
|
||||||
|
switch (SettingsData.workspaceUnfocusedColorMode) {
|
||||||
|
case "s":
|
||||||
|
return Theme.surface;
|
||||||
|
case "sc":
|
||||||
|
return Theme.surfaceContainer;
|
||||||
|
case "sch":
|
||||||
|
return Theme.surfaceContainerHigh;
|
||||||
|
default:
|
||||||
|
return Theme.surfaceTextAlpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color activeColor: {
|
||||||
|
switch (SettingsData.workspaceColorMode) {
|
||||||
|
case "s":
|
||||||
|
return Theme.surface;
|
||||||
|
case "sc":
|
||||||
|
return Theme.surfaceContainer;
|
||||||
|
case "sch":
|
||||||
|
return Theme.surfaceContainerHigh;
|
||||||
|
case "none":
|
||||||
|
return unfocusedColor;
|
||||||
|
default:
|
||||||
|
return Theme.primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color urgentColor: {
|
||||||
|
switch (SettingsData.workspaceUrgentColorMode) {
|
||||||
|
case "primary":
|
||||||
|
return Theme.primary;
|
||||||
|
case "secondary":
|
||||||
|
return Theme.secondary;
|
||||||
|
case "s":
|
||||||
|
return Theme.surface;
|
||||||
|
case "sc":
|
||||||
|
return Theme.surfaceContainer;
|
||||||
|
default:
|
||||||
|
return Theme.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color focusedBorderColor: {
|
||||||
|
switch (SettingsData.workspaceFocusedBorderColor) {
|
||||||
|
case "surfaceText":
|
||||||
|
return Theme.surfaceText;
|
||||||
|
case "secondary":
|
||||||
|
return Theme.secondary;
|
||||||
|
default:
|
||||||
|
return Theme.primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getContrastingIconColor(bgColor) {
|
||||||
|
const luminance = 0.299 * bgColor.r + 0.587 * bgColor.g + 0.114 * bgColor.b;
|
||||||
|
return luminance > 0.4 ? Qt.rgba(0.15, 0.15, 0.15, 1) : Qt.rgba(0.8, 0.8, 0.8, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color quickshellIconActiveColor: getContrastingIconColor(activeColor)
|
||||||
|
readonly property color quickshellIconInactiveColor: getContrastingIconColor(unfocusedColor)
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -850,7 +929,7 @@ Item {
|
|||||||
if (root.useExtWorkspace) {
|
if (root.useExtWorkspace) {
|
||||||
wsData = modelData;
|
wsData = modelData;
|
||||||
} else if (CompositorService.isNiri) {
|
} else if (CompositorService.isNiri) {
|
||||||
wsData = NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.screenName) || null;
|
wsData = NiriService.allWorkspaces.find(ws => ws.idx + 1 === modelData && ws.output === root.effectiveScreenName) || null;
|
||||||
} else if (CompositorService.isHyprland) {
|
} else if (CompositorService.isHyprland) {
|
||||||
wsData = modelData;
|
wsData = modelData;
|
||||||
} else if (CompositorService.isDwl) {
|
} else if (CompositorService.isDwl) {
|
||||||
@@ -892,16 +971,61 @@ Item {
|
|||||||
width: root.isVertical ? root.barThickness : visualWidth
|
width: root.isVertical ? root.barThickness : visualWidth
|
||||||
height: root.isVertical ? visualHeight : root.barThickness
|
height: root.isVertical ? visualHeight : root.barThickness
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: focusedBorderRing
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: {
|
||||||
|
const borderWidth = (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0;
|
||||||
|
return delegateRoot.visualWidth + borderWidth * 2;
|
||||||
|
}
|
||||||
|
height: {
|
||||||
|
const borderWidth = (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0;
|
||||||
|
return delegateRoot.visualHeight + borderWidth * 2;
|
||||||
|
}
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: "transparent"
|
||||||
|
border.width: (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? SettingsData.workspaceFocusedBorderThickness : 0
|
||||||
|
border.color: (SettingsData.workspaceFocusedBorderEnabled && isActive && !isPlaceholder) ? focusedBorderColor : "transparent"
|
||||||
|
|
||||||
|
Behavior on width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on border.width {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: visualContent
|
id: visualContent
|
||||||
width: delegateRoot.visualWidth
|
width: delegateRoot.visualWidth
|
||||||
height: delegateRoot.visualHeight
|
height: delegateRoot.visualHeight
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: isActive ? Theme.primary : isUrgent ? Theme.error : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.withAlpha(Theme.surfaceText, 0.45) : Theme.surfaceTextAlpha
|
color: isActive ? activeColor : isUrgent ? urgentColor : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.withAlpha(unfocusedColor, 0.7) : unfocusedColor
|
||||||
|
|
||||||
border.width: isUrgent ? 2 : 0
|
border.width: isUrgent ? 2 : 0
|
||||||
border.color: isUrgent ? Theme.error : Theme.withAlpha(Theme.error, 0)
|
border.color: isUrgent ? urgentColor : "transparent"
|
||||||
|
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -1013,7 +1137,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: modelData.icon
|
source: modelData.icon
|
||||||
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
|
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
visible: !modelData.isSteamApp && !modelData.isQuickshell
|
visible: !modelData.isQuickshell && !modelData.isSteamApp
|
||||||
}
|
}
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
@@ -1025,17 +1149,24 @@ Item {
|
|||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
saturation: 0
|
saturation: 0
|
||||||
colorization: 1
|
colorization: 1
|
||||||
colorizationColor: isActive ? Theme.primaryContainer : Theme.primary
|
colorizationColor: isActive ? quickshellIconActiveColor : quickshellIconInactiveColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: modelData.icon
|
||||||
|
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
|
visible: modelData.isSteamApp && modelData.icon
|
||||||
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
size: root.appIconSize
|
size: root.appIconSize
|
||||||
name: "sports_esports"
|
name: "sports_esports"
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
|
opacity: modelData.active ? 1.0 : rowAppMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
visible: modelData.isSteamApp
|
visible: modelData.isSteamApp && !modelData.icon
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -1116,7 +1247,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: modelData.icon
|
source: modelData.icon
|
||||||
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
|
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
visible: !modelData.isSteamApp && !modelData.isQuickshell
|
visible: !modelData.isQuickshell && !modelData.isSteamApp
|
||||||
}
|
}
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
@@ -1128,17 +1259,24 @@ Item {
|
|||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
saturation: 0
|
saturation: 0
|
||||||
colorization: 1
|
colorization: 1
|
||||||
colorizationColor: isActive ? Theme.primaryContainer : Theme.primary
|
colorizationColor: isActive ? quickshellIconActiveColor : quickshellIconInactiveColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: modelData.icon
|
||||||
|
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
|
visible: modelData.isSteamApp && modelData.icon
|
||||||
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
size: root.appIconSize
|
size: root.appIconSize
|
||||||
name: "sports_esports"
|
name: "sports_esports"
|
||||||
color: Theme.widgetTextColor
|
color: Theme.widgetTextColor
|
||||||
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
|
opacity: modelData.active ? 1.0 : colAppMouseArea.containsMouse ? 0.8 : 0.6
|
||||||
visible: modelData.isSteamApp
|
visible: modelData.isSteamApp && !modelData.icon
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -1264,6 +1402,9 @@ Item {
|
|||||||
function onWorkspaceNameIconsChanged() {
|
function onWorkspaceNameIconsChanged() {
|
||||||
delegateRoot.updateAllData();
|
delegateRoot.updateAllData();
|
||||||
}
|
}
|
||||||
|
function onAppIdSubstitutionsChanged() {
|
||||||
|
delegateRoot.updateAllData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Connections {
|
Connections {
|
||||||
target: DwlService
|
target: DwlService
|
||||||
|
|||||||
@@ -327,11 +327,12 @@ Item {
|
|||||||
clip: false
|
clip: false
|
||||||
visible: !_noneAvailable && (!showNoPlayerNow)
|
visible: !_noneAvailable && (!showNoPlayerNow)
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
x: 72
|
|
||||||
y: 20
|
|
||||||
width: 484
|
width: 484
|
||||||
height: 370
|
height: 370
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 20
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@@ -20,7 +20,19 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string dateText: (daily ? root.forecastData?.day : root.forecastData?.time) ?? "--"
|
readonly property string dateText: {
|
||||||
|
if (daily)
|
||||||
|
return root.forecastData?.day ?? "--";
|
||||||
|
if (!root.forecastData?.rawTime)
|
||||||
|
return root.forecastData?.time ?? "--";
|
||||||
|
try {
|
||||||
|
const date = new Date(root.forecastData.rawTime);
|
||||||
|
const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP";
|
||||||
|
return date.toLocaleTimeString(Qt.locale(), format);
|
||||||
|
} catch (e) {
|
||||||
|
return root.forecastData?.time ?? "--";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly property var minTemp: WeatherService.formatTemp(root.forecastData?.tempMin)
|
readonly property var minTemp: WeatherService.formatTemp(root.forecastData?.tempMin)
|
||||||
readonly property var maxTemp: WeatherService.formatTemp(root.forecastData?.tempMax)
|
readonly property var maxTemp: WeatherService.formatTemp(root.forecastData?.tempMax)
|
||||||
@@ -4,7 +4,6 @@ import QtQuick.Shapes
|
|||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.DankBar.Widgets
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -261,7 +260,17 @@ Item {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: sunriseText
|
id: sunriseText
|
||||||
text: WeatherService.weather.sunrise || ""
|
text: {
|
||||||
|
if (!WeatherService.weather.rawSunrise)
|
||||||
|
return WeatherService.weather.sunrise || "";
|
||||||
|
try {
|
||||||
|
const date = new Date(WeatherService.weather.rawSunrise);
|
||||||
|
const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP";
|
||||||
|
return date.toLocaleTimeString(Qt.locale(), format);
|
||||||
|
} catch (e) {
|
||||||
|
return WeatherService.weather.sunrise || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
anchors.left: sunriseIcon.right
|
anchors.left: sunriseIcon.right
|
||||||
@@ -285,7 +294,17 @@ Item {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: sunsetText
|
id: sunsetText
|
||||||
text: WeatherService.weather.sunset || ""
|
text: {
|
||||||
|
if (!WeatherService.weather.rawSunset)
|
||||||
|
return WeatherService.weather.sunset || "";
|
||||||
|
try {
|
||||||
|
const date = new Date(WeatherService.weather.rawSunset);
|
||||||
|
const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP";
|
||||||
|
return date.toLocaleTimeString(Qt.locale(), format);
|
||||||
|
} catch (e) {
|
||||||
|
return WeatherService.weather.sunset || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
anchors.left: sunsetIcon.right
|
anchors.left: sunsetIcon.right
|
||||||
@@ -324,14 +343,14 @@ Item {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
readonly property var splitDate: Qt.formatDateTime(dateStepper.currentDate, "yyyy.MM.dd.hh.mm.AP").split('.')
|
readonly property var splitDate: Qt.formatDateTime(dateStepper.currentDate, SettingsData.use24HourClock ? "yyyy.MM.dd.HH.mm" : "yyyy.MM.dd.hh.mm.AP").split('.')
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: dateStepperInner
|
id: dateStepperInner
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
readonly property var space: Theme.spacingXS
|
readonly property var space: Theme.spacingXS
|
||||||
width: yearStepper.width + monthStepper.width + dayStepper.width + hourStepper.width + minuteStepper.width + suffix.width + 10.5 * space + 2 * dateStepperInnerPadding.width
|
width: yearStepper.width + monthStepper.width + dayStepper.width + hourStepper.width + minuteStepper.width + (suffix.visible ? suffix.width : 0) + 10.5 * space + 2 * dateStepperInnerPadding.width
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: dateStepperInnerPadding
|
id: dateStepperInnerPadding
|
||||||
@@ -420,13 +439,14 @@ Item {
|
|||||||
}
|
}
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: suffix
|
id: suffix
|
||||||
|
visible: !SettingsData.use24HourClock
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: minuteStepper.right
|
anchors.left: minuteStepper.right
|
||||||
anchors.leftMargin: 2 * parent.space
|
anchors.leftMargin: 2 * parent.space
|
||||||
StyledText {
|
StyledText {
|
||||||
isMonospace: true
|
isMonospace: true
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: dateStepper.splitDate[5]
|
text: dateStepper.splitDate[5] ?? ""
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
x: -Theme.fontSizeSmall / 2
|
x: -Theme.fontSizeSmall / 2
|
||||||
y: -Theme.fontSizeSmall / 2
|
y: -Theme.fontSizeSmall / 2
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ Item {
|
|||||||
updateDesktopEntry();
|
updateDesktopEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onAppIdSubstitutionsChanged() {
|
||||||
|
updateDesktopEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
property bool isWindowFocused: {
|
property bool isWindowFocused: {
|
||||||
if (!appData) {
|
if (!appData) {
|
||||||
return false;
|
return false;
|
||||||
@@ -392,25 +399,11 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
size: actualIconSize
|
|
||||||
name: "sports_esports"
|
|
||||||
color: Theme.surfaceText
|
|
||||||
visible: {
|
|
||||||
if (!appData || !appData.appId || appData.appId === "__SEPARATOR__") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const moddedId = Paths.moddedAppId(appData.appId);
|
|
||||||
return moddedId.toLowerCase().includes("steam_app");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: actualIconSize
|
width: actualIconSize
|
||||||
height: actualIconSize
|
height: actualIconSize
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: iconImg.status !== Image.Ready
|
visible: iconImg.status !== Image.Ready && appData && appData.appId && !Paths.isSteamApp(appData.appId)
|
||||||
color: Theme.surfaceLight
|
color: Theme.surfaceLight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
border.width: 1
|
border.width: 1
|
||||||
@@ -432,6 +425,14 @@ 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 {
|
Loader {
|
||||||
anchors.horizontalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.horizontalCenter
|
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
|
anchors.verticalCenter: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? parent.verticalCenter : undefined
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
export WLR_DRM_DEVICES=/dev/dri/card1
|
|
||||||
|
|
||||||
COMPOSITOR=""
|
COMPOSITOR=""
|
||||||
COMPOSITOR_CONFIG=""
|
COMPOSITOR_CONFIG=""
|
||||||
DMS_PATH="dms-greeter"
|
DMS_PATH="dms-greeter"
|
||||||
@@ -16,7 +14,7 @@ dms-greeter - DankMaterialShell greeter launcher
|
|||||||
Usage: dms-greeter --command COMPOSITOR [OPTIONS]
|
Usage: dms-greeter --command COMPOSITOR [OPTIONS]
|
||||||
|
|
||||||
Required:
|
Required:
|
||||||
--command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll or mangowc)
|
--command COMPOSITOR Compositor to use (niri, hyprland, sway, scroll, mangowc, or labwc)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-C, --config PATH Custom compositor config file
|
-C, --config PATH Custom compositor config file
|
||||||
@@ -33,6 +31,7 @@ Examples:
|
|||||||
dms-greeter --command scroll -p /home/user/.config/quickshell/custom-dms
|
dms-greeter --command scroll -p /home/user/.config/quickshell/custom-dms
|
||||||
dms-greeter --command niri --cache-dir /tmp/dmsgreeter
|
dms-greeter --command niri --cache-dir /tmp/dmsgreeter
|
||||||
dms-greeter --command mangowc
|
dms-greeter --command mangowc
|
||||||
|
dms-greeter --command labwc
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +230,15 @@ SCROLL_EOF
|
|||||||
exec scroll -c "$COMPOSITOR_CONFIG"
|
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)
|
mangowc)
|
||||||
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
||||||
exec mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit"
|
exec mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit"
|
||||||
@@ -241,7 +249,7 @@ SCROLL_EOF
|
|||||||
|
|
||||||
*)
|
*)
|
||||||
echo "Error: Unsupported compositor: $COMPOSITOR" >&2
|
echo "Error: Unsupported compositor: $COMPOSITOR" >&2
|
||||||
echo "Supported compositors: niri, hyprland, sway, mangowc" >&2
|
echo "Supported compositors: niri, hyprland, sway, scroll, mangowc, labwc" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -12,37 +12,54 @@ Scope {
|
|||||||
|
|
||||||
property string sharedPasswordBuffer: ""
|
property string sharedPasswordBuffer: ""
|
||||||
property bool shouldLock: false
|
property bool shouldLock: false
|
||||||
property bool processingExternalEvent: false
|
property bool lockInitiatedLocally: false
|
||||||
|
property bool pendingLock: false
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
IdleService.lockComponent = this;
|
IdleService.lockComponent = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function notifyLoginctl(lockAction: bool) {
|
||||||
|
if (!SettingsData.loginctlLockIntegration || !DMSService.isConnected)
|
||||||
|
return;
|
||||||
|
if (lockAction)
|
||||||
|
DMSService.lockSession(() => {});
|
||||||
|
else
|
||||||
|
DMSService.unlockSession(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
function lock() {
|
function lock() {
|
||||||
if (SettingsData.customPowerActionLock && SettingsData.customPowerActionLock.length > 0) {
|
if (SettingsData.customPowerActionLock?.length > 0) {
|
||||||
Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]);
|
Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
shouldLock = true;
|
if (shouldLock || pendingLock)
|
||||||
if (!processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
|
return;
|
||||||
DMSService.lockSession(response => {
|
|
||||||
if (response.error)
|
lockInitiatedLocally = true;
|
||||||
console.warn("Lock: loginctl.lock failed:", response.error);
|
|
||||||
});
|
if (!SessionService.active && SessionService.loginctlAvailable) {
|
||||||
|
pendingLock = true;
|
||||||
|
notifyLoginctl(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldLock = true;
|
||||||
|
notifyLoginctl(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unlock() {
|
function unlock() {
|
||||||
if (!processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
|
if (!shouldLock)
|
||||||
DMSService.unlockSession(response => {
|
return;
|
||||||
if (response.error) {
|
lockInitiatedLocally = false;
|
||||||
console.warn("Lock: Failed to call loginctl.unlock:", response.error);
|
notifyLoginctl(false);
|
||||||
shouldLock = false;
|
shouldLock = false;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
function forceReset() {
|
||||||
shouldLock = false;
|
lockInitiatedLocally = false;
|
||||||
}
|
pendingLock = false;
|
||||||
|
shouldLock = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function activate() {
|
function activate() {
|
||||||
@@ -53,15 +70,39 @@ Scope {
|
|||||||
target: SessionService
|
target: SessionService
|
||||||
|
|
||||||
function onSessionLocked() {
|
function onSessionLocked() {
|
||||||
processingExternalEvent = true;
|
if (shouldLock || pendingLock)
|
||||||
|
return;
|
||||||
|
if (!SessionService.active && SessionService.loginctlAvailable) {
|
||||||
|
pendingLock = true;
|
||||||
|
lockInitiatedLocally = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lockInitiatedLocally = false;
|
||||||
shouldLock = true;
|
shouldLock = true;
|
||||||
processingExternalEvent = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSessionUnlocked() {
|
function onSessionUnlocked() {
|
||||||
processingExternalEvent = true;
|
if (pendingLock) {
|
||||||
|
pendingLock = false;
|
||||||
|
lockInitiatedLocally = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!shouldLock || lockInitiatedLocally)
|
||||||
|
return;
|
||||||
shouldLock = false;
|
shouldLock = false;
|
||||||
processingExternalEvent = false;
|
}
|
||||||
|
|
||||||
|
function onLoginctlStateChanged() {
|
||||||
|
if (SessionService.active && pendingLock) {
|
||||||
|
pendingLock = false;
|
||||||
|
lockInitiatedLocally = true;
|
||||||
|
shouldLock = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (SessionService.locked && !shouldLock && !pendingLock) {
|
||||||
|
lockInitiatedLocally = false;
|
||||||
|
shouldLock = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +120,10 @@ Scope {
|
|||||||
locked: shouldLock
|
locked: shouldLock
|
||||||
|
|
||||||
onLockedChanged: {
|
onLockedChanged: {
|
||||||
if (locked)
|
if (locked) {
|
||||||
|
pendingLock = false;
|
||||||
dpmsReapplyTimer.start();
|
dpmsReapplyTimer.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WlSessionLockSurface {
|
WlSessionLockSurface {
|
||||||
@@ -104,9 +147,7 @@ Scope {
|
|||||||
sharedPasswordBuffer: root.sharedPasswordBuffer
|
sharedPasswordBuffer: root.sharedPasswordBuffer
|
||||||
screenName: lockSurface.currentScreenName
|
screenName: lockSurface.currentScreenName
|
||||||
isLocked: shouldLock
|
isLocked: shouldLock
|
||||||
onUnlockRequested: {
|
onUnlockRequested: root.unlock()
|
||||||
root.unlock();
|
|
||||||
}
|
|
||||||
onPasswordChanged: newPassword => {
|
onPasswordChanged: newPassword => {
|
||||||
root.sharedPasswordBuffer = newPassword;
|
root.sharedPasswordBuffer = newPassword;
|
||||||
}
|
}
|
||||||
@@ -122,13 +163,15 @@ Scope {
|
|||||||
target: "lock"
|
target: "lock"
|
||||||
|
|
||||||
function lock() {
|
function lock() {
|
||||||
root.shouldLock = true;
|
root.lock();
|
||||||
if (SettingsData.loginctlLockIntegration && DMSService.isConnected) {
|
}
|
||||||
DMSService.lockSession(response => {
|
|
||||||
if (response.error)
|
function unlock() {
|
||||||
console.warn("Lock: loginctl.lock failed:", response.error);
|
root.unlock();
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
function forceReset() {
|
||||||
|
root.forceReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
function demo() {
|
function demo() {
|
||||||
@@ -138,6 +181,17 @@ Scope {
|
|||||||
function isLocked(): bool {
|
function isLocked(): bool {
|
||||||
return sessionLock.locked;
|
return sessionLock.locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function status(): string {
|
||||||
|
return JSON.stringify({
|
||||||
|
shouldLock: root.shouldLock,
|
||||||
|
sessionLockLocked: sessionLock.locked,
|
||||||
|
lockInitiatedLocally: root.lockInitiatedLocally,
|
||||||
|
pendingLock: root.pendingLock,
|
||||||
|
loginctlLocked: SessionService.locked,
|
||||||
|
loginctlActive: SessionService.active
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ Item {
|
|||||||
|
|
||||||
signal unlockRequested
|
signal unlockRequested
|
||||||
|
|
||||||
|
function resetLockState() {
|
||||||
|
lockerReadySent = false;
|
||||||
|
lockerReadyArmed = true;
|
||||||
|
unlocking = false;
|
||||||
|
pamState = "";
|
||||||
|
}
|
||||||
|
|
||||||
function pickRandomFact() {
|
function pickRandomFact() {
|
||||||
randomFact = Facts.getRandomFact();
|
randomFact = Facts.getRandomFact();
|
||||||
}
|
}
|
||||||
@@ -1399,6 +1406,14 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: NetworkService.networkAvailable || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio)
|
visible: NetworkService.networkAvailable || (BluetoothService.available && BluetoothService.enabled) || (AudioService.sink && AudioService.sink.audio)
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "screen_record"
|
||||||
|
size: Theme.iconSize - 2
|
||||||
|
color: NiriService.hasActiveCast ? "white" : Qt.rgba(255, 255, 255, 0.5)
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: NiriService.hasCasts
|
||||||
|
}
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: {
|
name: {
|
||||||
if (NetworkService.wifiToggling)
|
if (NetworkService.wifiToggling)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ pragma ComponentBehavior: Bound
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Common
|
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
@@ -26,13 +25,13 @@ PanelWindow {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
function showDemo(): void {
|
function showDemo(): void {
|
||||||
console.log("Showing lock screen demo")
|
console.log("Showing lock screen demo");
|
||||||
demoActive = true
|
demoActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideDemo(): void {
|
function hideDemo(): void {
|
||||||
console.log("Hiding lock screen demo")
|
console.log("Hiding lock screen demo");
|
||||||
demoActive = false
|
demoActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
|||||||
@@ -32,8 +32,10 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onIsLockedChanged: {
|
onIsLockedChanged: {
|
||||||
if (!isLocked) {
|
if (isLocked) {
|
||||||
lockContent.unlocking = false;
|
lockContent.resetLockState();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
lockContent.unlocking = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,17 @@ Rectangle {
|
|||||||
required property var historyItem
|
required property var historyItem
|
||||||
property bool isSelected: false
|
property bool isSelected: false
|
||||||
property bool keyboardNavigationActive: false
|
property bool keyboardNavigationActive: false
|
||||||
|
property bool descriptionExpanded: NotificationService.expandedMessages[historyItem?.id ? (historyItem.id + "_hist") : ""] || false
|
||||||
|
|
||||||
|
readonly property bool compactMode: SettingsData.notificationCompactMode
|
||||||
|
readonly property real cardPadding: compactMode ? Theme.spacingS : Theme.spacingM
|
||||||
|
readonly property real iconSize: compactMode ? 48 : 63
|
||||||
|
readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS
|
||||||
|
readonly property real collapsedContentHeight: iconSize + cardPadding
|
||||||
|
readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight
|
||||||
|
|
||||||
width: parent ? parent.width : 400
|
width: parent ? parent.width : 400
|
||||||
height: 116
|
height: baseCardHeight + contentItem.extraHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
@@ -65,23 +73,28 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
id: contentItem
|
||||||
|
|
||||||
|
readonly property real expandedTextHeight: descriptionText.contentHeight
|
||||||
|
readonly property real twoLineHeight: descriptionText.font.pixelSize * 1.2 * 2
|
||||||
|
readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > twoLineHeight + 2) ? (expandedTextHeight - twoLineHeight) : 0
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: cardPadding
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: Theme.spacingL
|
||||||
anchors.rightMargin: 56
|
anchors.rightMargin: Theme.spacingL + (compactMode ? 32 : 40)
|
||||||
height: 92
|
height: collapsedContentHeight + extraHeight
|
||||||
|
|
||||||
DankCircularImage {
|
DankCircularImage {
|
||||||
id: iconContainer
|
id: iconContainer
|
||||||
readonly property bool hasNotificationImage: historyItem.image && historyItem.image !== ""
|
readonly property bool hasNotificationImage: historyItem.image && historyItem.image !== ""
|
||||||
|
|
||||||
width: 63
|
width: iconSize
|
||||||
height: 63
|
height: iconSize
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 14
|
|
||||||
|
|
||||||
imageSource: {
|
imageSource: {
|
||||||
if (hasNotificationImage)
|
if (hasNotificationImage)
|
||||||
@@ -116,60 +129,79 @@ Rectangle {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.left: iconContainer.right
|
anchors.left: iconContainer.right
|
||||||
anchors.leftMargin: 12
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Item {
|
Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: -2
|
spacing: compactMode ? 1 : 2
|
||||||
|
|
||||||
Column {
|
StyledText {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: 2
|
text: {
|
||||||
|
const timeStr = NotificationService.formatHistoryTime(historyItem.timestamp);
|
||||||
|
const appName = historyItem.appName || "";
|
||||||
|
return timeStr.length > 0 ? `${appName} • ${timeStr}` : appName;
|
||||||
|
}
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
width: parent.width
|
text: historyItem.summary || ""
|
||||||
text: {
|
color: Theme.surfaceText
|
||||||
const timeStr = NotificationService.formatHistoryTime(historyItem.timestamp);
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
const appName = historyItem.appName || "";
|
font.weight: Font.Medium
|
||||||
return timeStr.length > 0 ? `${appName} • ${timeStr}` : appName;
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: descriptionText
|
||||||
|
property bool hasMoreText: truncated
|
||||||
|
|
||||||
|
text: historyItem.htmlBody || historyItem.body || ""
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
width: parent.width
|
||||||
|
elide: descriptionExpanded ? Text.ElideNone : Text.ElideRight
|
||||||
|
maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2)
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
visible: text.length > 0
|
||||||
|
linkColor: Theme.primary
|
||||||
|
onLinkActivated: link => Qt.openUrlExternally(link)
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
|
onClicked: mouse => {
|
||||||
|
if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) {
|
||||||
|
const messageId = historyItem?.id ? (historyItem.id + "_hist") : "";
|
||||||
|
NotificationService.toggleMessageExpansion(messageId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
propagateComposedEvents: true
|
||||||
text: historyItem.summary || ""
|
onPressed: mouse => {
|
||||||
color: Theme.surfaceText
|
if (parent.hoveredLink)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
mouse.accepted = false;
|
||||||
font.weight: Font.Medium
|
}
|
||||||
width: parent.width
|
onReleased: mouse => {
|
||||||
elide: Text.ElideRight
|
if (parent.hoveredLink)
|
||||||
maximumLineCount: 1
|
mouse.accepted = false;
|
||||||
visible: text.length > 0
|
}
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: descriptionText
|
|
||||||
text: historyItem.htmlBody || historyItem.body || ""
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
width: parent.width
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 2
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
visible: text.length > 0
|
|
||||||
linkColor: Theme.primary
|
|
||||||
onLinkActivated: link => Qt.openUrlExternally(link)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,11 +211,11 @@ Rectangle {
|
|||||||
DankActionButton {
|
DankActionButton {
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: cardPadding
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: Theme.spacingL
|
||||||
iconName: "close"
|
iconName: "close"
|
||||||
iconSize: 18
|
iconSize: compactMode ? 16 : 18
|
||||||
buttonSize: 28
|
buttonSize: compactMode ? 24 : 28
|
||||||
onClicked: NotificationService.removeFromHistory(historyItem.id)
|
onClicked: NotificationService.removeFromHistory(historyItem.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,23 +83,54 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readonly property var allFilters: [
|
readonly property var allFilters: [
|
||||||
{ label: I18n.tr("All", "notification history filter"), key: "all", maxDays: 0 },
|
{
|
||||||
{ label: I18n.tr("Last hour", "notification history filter"), key: "1h", maxDays: 1 },
|
label: I18n.tr("All", "notification history filter"),
|
||||||
{ label: I18n.tr("Today", "notification history filter"), key: "today", maxDays: 1 },
|
key: "all",
|
||||||
{ label: I18n.tr("Yesterday", "notification history filter"), key: "yesterday", maxDays: 2 },
|
maxDays: 0
|
||||||
{ label: I18n.tr("7 days", "notification history filter"), key: "7d", maxDays: 7 },
|
},
|
||||||
{ label: I18n.tr("30 days", "notification history filter"), key: "30d", maxDays: 30 },
|
{
|
||||||
{ label: I18n.tr("Older", "notification history filter for content older than other filters"), key: "older", maxDays: 0 }
|
label: I18n.tr("Last hour", "notification history filter"),
|
||||||
|
key: "1h",
|
||||||
|
maxDays: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: I18n.tr("Today", "notification history filter"),
|
||||||
|
key: "today",
|
||||||
|
maxDays: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: I18n.tr("Yesterday", "notification history filter"),
|
||||||
|
key: "yesterday",
|
||||||
|
maxDays: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: I18n.tr("7 days", "notification history filter"),
|
||||||
|
key: "7d",
|
||||||
|
maxDays: 7
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: I18n.tr("30 days", "notification history filter"),
|
||||||
|
key: "30d",
|
||||||
|
maxDays: 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: I18n.tr("Older", "notification history filter for content older than other filters"),
|
||||||
|
key: "older",
|
||||||
|
maxDays: 0
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
function filterRelevantForRetention(filter) {
|
function filterRelevantForRetention(filter) {
|
||||||
const retention = SettingsData.notificationHistoryMaxAgeDays;
|
const retention = SettingsData.notificationHistoryMaxAgeDays;
|
||||||
if (filter.key === "older") {
|
if (filter.key === "older") {
|
||||||
if (retention === 0) return true;
|
if (retention === 0)
|
||||||
|
return true;
|
||||||
return retention > 2 && retention < 7 || retention > 30;
|
return retention > 2 && retention < 7 || retention > 30;
|
||||||
}
|
}
|
||||||
if (retention === 0) return true;
|
if (retention === 0)
|
||||||
if (filter.maxDays === 0) return true;
|
return true;
|
||||||
|
if (filter.maxDays === 0)
|
||||||
|
return true;
|
||||||
return filter.maxDays <= retention;
|
return filter.maxDays <= retention;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,10 +150,15 @@ Item {
|
|||||||
const retention = SettingsData.notificationHistoryMaxAgeDays;
|
const retention = SettingsData.notificationHistoryMaxAgeDays;
|
||||||
for (let i = 0; i < allFilters.length; i++) {
|
for (let i = 0; i < allFilters.length; i++) {
|
||||||
const f = allFilters[i];
|
const f = allFilters[i];
|
||||||
if (!filterRelevantForRetention(f)) continue;
|
if (!filterRelevantForRetention(f))
|
||||||
|
continue;
|
||||||
const count = countForFilter(f.key);
|
const count = countForFilter(f.key);
|
||||||
if (f.key === "all" || count > 0) {
|
if (f.key === "all" || count > 0) {
|
||||||
result.push({ label: f.label, key: f.key, count: count });
|
result.push({
|
||||||
|
label: f.label,
|
||||||
|
key: f.key,
|
||||||
|
count: count
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -165,6 +201,14 @@ Item {
|
|||||||
function enableAutoScroll() {
|
function enableAutoScroll() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeWithScrollPreserve(itemId) {
|
||||||
|
historyListView.savedY = historyListView.contentY;
|
||||||
|
NotificationService.removeFromHistory(itemId);
|
||||||
|
Qt.callLater(() => {
|
||||||
|
historyListView.forceLayout();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
@@ -201,14 +245,66 @@ Item {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: HistoryNotificationCard {
|
delegate: Item {
|
||||||
|
id: delegateRoot
|
||||||
required property var modelData
|
required property var modelData
|
||||||
required property int index
|
required property int index
|
||||||
|
|
||||||
|
property real swipeOffset: 0
|
||||||
|
property bool isDismissing: false
|
||||||
|
readonly property real dismissThreshold: width * 0.35
|
||||||
|
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
historyItem: modelData
|
height: historyCard.height
|
||||||
isSelected: root.keyboardActive && root.selectedIndex === index
|
clip: true
|
||||||
keyboardNavigationActive: root.keyboardActive
|
|
||||||
|
HistoryNotificationCard {
|
||||||
|
id: historyCard
|
||||||
|
width: parent.width
|
||||||
|
x: delegateRoot.swipeOffset
|
||||||
|
historyItem: modelData
|
||||||
|
isSelected: root.keyboardActive && root.selectedIndex === index
|
||||||
|
keyboardNavigationActive: root.keyboardActive
|
||||||
|
opacity: 1 - Math.abs(delegateRoot.swipeOffset) / (delegateRoot.width * 0.5)
|
||||||
|
|
||||||
|
Behavior on x {
|
||||||
|
enabled: !swipeDragHandler.active
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DragHandler {
|
||||||
|
id: swipeDragHandler
|
||||||
|
target: null
|
||||||
|
yAxis.enabled: false
|
||||||
|
xAxis.enabled: true
|
||||||
|
|
||||||
|
onActiveChanged: {
|
||||||
|
if (active || delegateRoot.isDismissing)
|
||||||
|
return;
|
||||||
|
if (Math.abs(delegateRoot.swipeOffset) > delegateRoot.dismissThreshold) {
|
||||||
|
delegateRoot.isDismissing = true;
|
||||||
|
root.removeWithScrollPreserve(delegateRoot.modelData?.id || "");
|
||||||
|
} else {
|
||||||
|
delegateRoot.swipeOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTranslationChanged: {
|
||||||
|
if (delegateRoot.isDismissing)
|
||||||
|
return;
|
||||||
|
delegateRoot.swipeOffset = translation.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,17 @@ Rectangle {
|
|||||||
property int selectedNotificationIndex: -1
|
property int selectedNotificationIndex: -1
|
||||||
property bool keyboardNavigationActive: false
|
property bool keyboardNavigationActive: false
|
||||||
|
|
||||||
|
readonly property bool compactMode: SettingsData.notificationCompactMode
|
||||||
|
readonly property real cardPadding: compactMode ? Theme.spacingS : Theme.spacingM
|
||||||
|
readonly property real iconSize: compactMode ? 48 : 63
|
||||||
|
readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS
|
||||||
|
readonly property real badgeSize: compactMode ? 16 : 18
|
||||||
|
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
||||||
|
readonly property real collapsedContentHeight: iconSize
|
||||||
|
readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing
|
||||||
|
|
||||||
width: parent ? parent.width : 400
|
width: parent ? parent.width : 400
|
||||||
height: {
|
height: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight)
|
||||||
if (expanded) {
|
|
||||||
return expandedContent.height + 28;
|
|
||||||
}
|
|
||||||
const baseHeight = 116;
|
|
||||||
if (descriptionExpanded) {
|
|
||||||
return baseHeight + descriptionText.contentHeight - (descriptionText.font.pixelSize * 1.2 * 2);
|
|
||||||
}
|
|
||||||
return baseHeight;
|
|
||||||
}
|
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
|
|
||||||
Behavior on border.color {
|
Behavior on border.color {
|
||||||
@@ -97,24 +97,28 @@ Rectangle {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: collapsedContent
|
id: collapsedContent
|
||||||
|
|
||||||
|
readonly property real expandedTextHeight: descriptionText.contentHeight
|
||||||
|
readonly property real twoLineHeight: descriptionText.font.pixelSize * 1.2 * 2
|
||||||
|
readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > twoLineHeight + 2) ? (expandedTextHeight - twoLineHeight) : 0
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: cardPadding
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: Theme.spacingL
|
||||||
anchors.rightMargin: 56
|
anchors.rightMargin: Theme.spacingL + (compactMode ? 32 : 40)
|
||||||
height: 92
|
height: collapsedContentHeight + extraHeight
|
||||||
visible: !expanded
|
visible: !expanded
|
||||||
|
|
||||||
DankCircularImage {
|
DankCircularImage {
|
||||||
id: iconContainer
|
id: iconContainer
|
||||||
readonly property bool hasNotificationImage: notificationGroup?.latestNotification?.image && notificationGroup.latestNotification.image !== ""
|
readonly property bool hasNotificationImage: notificationGroup?.latestNotification?.image && notificationGroup.latestNotification.image !== ""
|
||||||
|
|
||||||
width: 63
|
width: iconSize
|
||||||
height: 63
|
height: iconSize
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 14
|
|
||||||
|
|
||||||
imageSource: {
|
imageSource: {
|
||||||
if (hasNotificationImage)
|
if (hasNotificationImage)
|
||||||
@@ -147,9 +151,9 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: 18
|
width: badgeSize
|
||||||
height: 18
|
height: badgeSize
|
||||||
radius: 9
|
radius: badgeSize / 2
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -161,7 +165,7 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString()
|
text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString()
|
||||||
color: Theme.primaryText
|
color: Theme.primaryText
|
||||||
font.pixelSize: 9
|
font.pixelSize: compactMode ? 8 : 9
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,87 +175,79 @@ Rectangle {
|
|||||||
id: textContainer
|
id: textContainer
|
||||||
|
|
||||||
anchors.left: iconContainer.right
|
anchors.left: iconContainer.right
|
||||||
anchors.leftMargin: 12
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 0
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Item {
|
Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: -2
|
spacing: compactMode ? 1 : 2
|
||||||
|
|
||||||
Column {
|
StyledText {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: 2
|
text: {
|
||||||
|
const timeStr = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.timeStr) || "";
|
||||||
|
const appName = (notificationGroup && notificationGroup.appName) || "";
|
||||||
|
return timeStr.length > 0 ? `${appName} • ${timeStr}` : appName;
|
||||||
|
}
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
width: parent.width
|
text: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.summary) || ""
|
||||||
text: {
|
color: Theme.surfaceText
|
||||||
const timeStr = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.timeStr) || "";
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
const appName = (notificationGroup && notificationGroup.appName) || "";
|
font.weight: Font.Medium
|
||||||
return timeStr.length > 0 ? `${appName} • ${timeStr}` : appName;
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: descriptionText
|
||||||
|
property string fullText: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.htmlBody) || ""
|
||||||
|
property bool hasMoreText: truncated
|
||||||
|
|
||||||
|
text: fullText
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2)
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
visible: text.length > 0
|
||||||
|
linkColor: Theme.primary
|
||||||
|
onLinkActivated: link => Qt.openUrlExternally(link)
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
|
onClicked: mouse => {
|
||||||
|
if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) {
|
||||||
|
const messageId = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : "";
|
||||||
|
NotificationService.toggleMessageExpansion(messageId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
propagateComposedEvents: true
|
||||||
text: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.summary) || ""
|
onPressed: mouse => {
|
||||||
color: Theme.surfaceText
|
if (parent.hoveredLink)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
mouse.accepted = false;
|
||||||
font.weight: Font.Medium
|
}
|
||||||
width: parent.width
|
onReleased: mouse => {
|
||||||
elide: Text.ElideRight
|
if (parent.hoveredLink)
|
||||||
maximumLineCount: 1
|
mouse.accepted = false;
|
||||||
visible: text.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
id: descriptionText
|
|
||||||
property string fullText: (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.htmlBody) || ""
|
|
||||||
property bool hasMoreText: truncated
|
|
||||||
|
|
||||||
text: fullText
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
width: parent.width
|
|
||||||
elide: Text.ElideRight
|
|
||||||
maximumLineCount: descriptionExpanded ? -1 : 2
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
visible: text.length > 0
|
|
||||||
linkColor: Theme.primary
|
|
||||||
onLinkActivated: link => Qt.openUrlExternally(link)
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (parent.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
|
|
||||||
onClicked: mouse => {
|
|
||||||
if (!parent.hoveredLink && (parent.hasMoreText || descriptionExpanded)) {
|
|
||||||
const messageId = (notificationGroup && notificationGroup.latestNotification && notificationGroup.latestNotification.notification && notificationGroup.latestNotification.notification.id) ? (notificationGroup.latestNotification.notification.id + "_desc") : "";
|
|
||||||
NotificationService.toggleMessageExpansion(messageId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
propagateComposedEvents: true
|
|
||||||
onPressed: mouse => {
|
|
||||||
if (parent.hoveredLink) {
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onReleased: mouse => {
|
|
||||||
if (parent.hoveredLink) {
|
|
||||||
mouse.accepted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,21 +261,20 @@ Rectangle {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 14
|
anchors.topMargin: cardPadding
|
||||||
anchors.bottomMargin: 14
|
|
||||||
anchors.leftMargin: Theme.spacingL
|
anchors.leftMargin: Theme.spacingL
|
||||||
anchors.rightMargin: Theme.spacingL
|
anchors.rightMargin: Theme.spacingL
|
||||||
spacing: -1
|
spacing: compactMode ? Theme.spacingXS : Theme.spacingS
|
||||||
visible: expanded
|
visible: expanded
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 40
|
height: compactMode ? 32 : 40
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 56
|
anchors.rightMargin: Theme.spacingL + (compactMode ? 32 : 40)
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
@@ -294,9 +289,9 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: 18
|
width: badgeSize
|
||||||
height: 18
|
height: badgeSize
|
||||||
radius: 9
|
radius: badgeSize / 2
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
visible: (notificationGroup?.count || 0) > 1
|
visible: (notificationGroup?.count || 0) > 1
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -305,7 +300,7 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString()
|
text: (notificationGroup?.count || 0) > 99 ? "99+" : (notificationGroup?.count || 0).toString()
|
||||||
color: Theme.primaryText
|
color: Theme.primaryText
|
||||||
font.pixelSize: 9
|
font.pixelSize: compactMode ? 8 : 9
|
||||||
font.weight: Font.Bold
|
font.weight: Font.Bold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +309,7 @@ Rectangle {
|
|||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: 16
|
spacing: compactMode ? Theme.spacingS : Theme.spacingL
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: notificationRepeater
|
id: notificationRepeater
|
||||||
@@ -328,23 +323,23 @@ Rectangle {
|
|||||||
required property int index
|
required property int index
|
||||||
readonly property bool messageExpanded: NotificationService.expandedMessages[modelData?.notification?.id] || false
|
readonly property bool messageExpanded: NotificationService.expandedMessages[modelData?.notification?.id] || false
|
||||||
readonly property bool isSelected: root.selectedNotificationIndex === index
|
readonly property bool isSelected: root.selectedNotificationIndex === index
|
||||||
|
readonly property real expandedIconSize: compactMode ? 40 : 48
|
||||||
|
readonly property real expandedItemPadding: compactMode ? Theme.spacingS : Theme.spacingM
|
||||||
|
readonly property real expandedBaseHeight: expandedItemPadding * 2 + expandedIconSize + actionButtonHeight + contentSpacing * 2
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: {
|
height: {
|
||||||
const baseHeight = 120;
|
if (!messageExpanded)
|
||||||
if (messageExpanded) {
|
return expandedBaseHeight;
|
||||||
const twoLineHeight = bodyText.font.pixelSize * 1.2 * 2;
|
const twoLineHeight = bodyText.font.pixelSize * 1.2 * 2;
|
||||||
if (bodyText.implicitHeight > twoLineHeight + 2) {
|
if (bodyText.implicitHeight > twoLineHeight + 2)
|
||||||
const extraHeight = bodyText.implicitHeight - twoLineHeight;
|
return expandedBaseHeight + bodyText.implicitHeight - twoLineHeight;
|
||||||
return baseHeight + extraHeight;
|
return expandedBaseHeight;
|
||||||
}
|
|
||||||
}
|
|
||||||
return baseHeight;
|
|
||||||
}
|
}
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: isSelected ? Theme.primaryPressed : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
color: isSelected ? Theme.primaryPressed : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
border.color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
|
border.color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
|
||||||
border.width: isSelected ? 1 : 1
|
border.width: 1
|
||||||
|
|
||||||
Behavior on border.color {
|
Behavior on border.color {
|
||||||
ColorAnimation {
|
ColorAnimation {
|
||||||
@@ -359,19 +354,19 @@ Rectangle {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 12
|
anchors.margins: compactMode ? Theme.spacingS : Theme.spacingM
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
|
|
||||||
DankCircularImage {
|
DankCircularImage {
|
||||||
id: messageIcon
|
id: messageIcon
|
||||||
|
|
||||||
readonly property bool hasNotificationImage: modelData?.image && modelData.image !== ""
|
readonly property bool hasNotificationImage: modelData?.image && modelData.image !== ""
|
||||||
|
|
||||||
width: 48
|
width: expandedIconSize
|
||||||
height: 48
|
height: expandedIconSize
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 32
|
anchors.topMargin: compactMode ? Theme.spacingM : Theme.spacingXL
|
||||||
|
|
||||||
imageSource: {
|
imageSource: {
|
||||||
if (hasNotificationImage)
|
if (hasNotificationImage)
|
||||||
@@ -397,9 +392,9 @@ Rectangle {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.left: messageIcon.right
|
anchors.left: messageIcon.right
|
||||||
anchors.leftMargin: 12
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 12
|
anchors.rightMargin: Theme.spacingM
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
@@ -408,8 +403,8 @@ Rectangle {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: buttonArea.top
|
anchors.bottom: buttonArea.top
|
||||||
anchors.bottomMargin: 4
|
anchors.bottomMargin: contentSpacing
|
||||||
spacing: 2
|
spacing: compactMode ? 1 : 2
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -477,12 +472,12 @@ Rectangle {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
height: 30
|
height: actionButtonHeight + contentSpacing
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
spacing: 8
|
spacing: contentSpacing
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: modelData?.actions || []
|
model: modelData?.actions || []
|
||||||
@@ -490,18 +485,17 @@ Rectangle {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
property bool isHovered: false
|
property bool isHovered: false
|
||||||
|
|
||||||
width: Math.max(actionText.implicitWidth + 12, 50)
|
width: Math.max(actionText.implicitWidth + Theme.spacingM, compactMode ? 40 : 50)
|
||||||
height: 24
|
height: actionButtonHeight
|
||||||
radius: 4
|
radius: Theme.spacingXS
|
||||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: actionText
|
id: actionText
|
||||||
text: {
|
text: {
|
||||||
const baseText = modelData.text || "View";
|
const baseText = modelData.text || "View";
|
||||||
if (keyboardNavigationActive && (isGroupSelected || selectedNotificationIndex >= 0)) {
|
if (keyboardNavigationActive && (isGroupSelected || selectedNotificationIndex >= 0))
|
||||||
return `${baseText} (${index + 1})`;
|
return `${baseText} (${index + 1})`;
|
||||||
}
|
|
||||||
return baseText;
|
return baseText;
|
||||||
}
|
}
|
||||||
color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText
|
color: parent.isHovered ? Theme.primary : Theme.surfaceVariantText
|
||||||
@@ -518,9 +512,8 @@ Rectangle {
|
|||||||
onEntered: parent.isHovered = true
|
onEntered: parent.isHovered = true
|
||||||
onExited: parent.isHovered = false
|
onExited: parent.isHovered = false
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (modelData && modelData.invoke) {
|
if (modelData && modelData.invoke)
|
||||||
modelData.invoke();
|
modelData.invoke();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -529,9 +522,9 @@ Rectangle {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
property bool isHovered: false
|
property bool isHovered: false
|
||||||
|
|
||||||
width: Math.max(clearText.implicitWidth + 12, 50)
|
width: Math.max(clearText.implicitWidth + Theme.spacingM, compactMode ? 40 : 50)
|
||||||
height: 24
|
height: actionButtonHeight
|
||||||
radius: 4
|
radius: Theme.spacingXS
|
||||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -563,11 +556,11 @@ Rectangle {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
visible: !expanded
|
visible: !expanded
|
||||||
anchors.right: clearButton.left
|
anchors.right: clearButton.visible ? clearButton.left : parent.right
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: clearButton.visible ? contentSpacing : Theme.spacingL
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
spacing: 8
|
spacing: contentSpacing
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: notificationGroup?.latestNotification?.actions || []
|
model: notificationGroup?.latestNotification?.actions || []
|
||||||
@@ -575,9 +568,9 @@ Rectangle {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
property bool isHovered: false
|
property bool isHovered: false
|
||||||
|
|
||||||
width: Math.max(actionText.implicitWidth + 12, 50)
|
width: Math.max(actionText.implicitWidth + Theme.spacingM, compactMode ? 40 : 50)
|
||||||
height: 24
|
height: actionButtonHeight
|
||||||
radius: 4
|
radius: Theme.spacingXS
|
||||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -616,15 +609,16 @@ Rectangle {
|
|||||||
id: clearButton
|
id: clearButton
|
||||||
|
|
||||||
property bool isHovered: false
|
property bool isHovered: false
|
||||||
|
readonly property int actionCount: (notificationGroup?.latestNotification?.actions || []).length
|
||||||
|
|
||||||
visible: !expanded
|
visible: !expanded && actionCount < 3
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: Theme.spacingL
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
width: Math.max(clearText.implicitWidth + 12, 50)
|
width: Math.max(clearText.implicitWidth + Theme.spacingM, compactMode ? 40 : 50)
|
||||||
height: 24
|
height: actionButtonHeight
|
||||||
radius: 4
|
radius: Theme.spacingXS
|
||||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -660,18 +654,18 @@ Rectangle {
|
|||||||
id: fixedControls
|
id: fixedControls
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: cardPadding
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: Theme.spacingL
|
||||||
width: 60
|
width: compactMode ? 52 : 60
|
||||||
height: 28
|
height: compactMode ? 24 : 28
|
||||||
|
|
||||||
DankActionButton {
|
DankActionButton {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
visible: (notificationGroup?.count || 0) > 1
|
visible: (notificationGroup?.count || 0) > 1
|
||||||
iconName: expanded ? "expand_less" : "expand_more"
|
iconName: expanded ? "expand_less" : "expand_more"
|
||||||
iconSize: 18
|
iconSize: compactMode ? 16 : 18
|
||||||
buttonSize: 28
|
buttonSize: compactMode ? 24 : 28
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.userInitiatedExpansion = true;
|
root.userInitiatedExpansion = true;
|
||||||
NotificationService.toggleGroupExpansion(notificationGroup?.key || "");
|
NotificationService.toggleGroupExpansion(notificationGroup?.key || "");
|
||||||
@@ -682,8 +676,8 @@ Rectangle {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
iconName: "close"
|
iconName: "close"
|
||||||
iconSize: 18
|
iconSize: compactMode ? 16 : 18
|
||||||
buttonSize: 28
|
buttonSize: compactMode ? 24 : 28
|
||||||
onClicked: NotificationService.dismissGroup(notificationGroup?.key || "")
|
onClicked: NotificationService.dismissGroup(notificationGroup?.key || "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ PanelWindow {
|
|||||||
property bool _isDestroying: false
|
property bool _isDestroying: false
|
||||||
property bool _finalized: false
|
property bool _finalized: false
|
||||||
readonly property string clearText: I18n.tr("Dismiss")
|
readonly property string clearText: I18n.tr("Dismiss")
|
||||||
|
property bool descriptionExpanded: false
|
||||||
|
|
||||||
|
readonly property bool compactMode: SettingsData.notificationCompactMode
|
||||||
|
readonly property real cardPadding: compactMode ? Theme.spacingS : Theme.spacingM
|
||||||
|
readonly property real popupIconSize: compactMode ? 48 : 63
|
||||||
|
readonly property real contentSpacing: compactMode ? Theme.spacingXS : Theme.spacingS
|
||||||
|
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
||||||
|
readonly property real collapsedContentHeight: popupIconSize
|
||||||
|
readonly property real basePopupHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + Theme.spacingS
|
||||||
|
|
||||||
signal entered
|
signal entered
|
||||||
signal exitStarted
|
signal exitStarted
|
||||||
@@ -92,7 +101,15 @@ PanelWindow {
|
|||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
implicitWidth: 400
|
implicitWidth: 400
|
||||||
implicitHeight: 122
|
implicitHeight: {
|
||||||
|
if (!descriptionExpanded)
|
||||||
|
return basePopupHeight;
|
||||||
|
const bodyTextHeight = bodyText.contentHeight || 0;
|
||||||
|
const twoLineHeight = Theme.fontSizeSmall * 1.2 * 2;
|
||||||
|
if (bodyTextHeight > twoLineHeight + 2)
|
||||||
|
return basePopupHeight + bodyTextHeight - twoLineHeight;
|
||||||
|
return basePopupHeight;
|
||||||
|
}
|
||||||
onHasValidDataChanged: {
|
onHasValidDataChanged: {
|
||||||
if (!hasValidData && !exiting && !_isDestroying) {
|
if (!hasValidData && !exiting && !_isDestroying) {
|
||||||
forceExit();
|
forceExit();
|
||||||
@@ -352,13 +369,17 @@ PanelWindow {
|
|||||||
Item {
|
Item {
|
||||||
id: notificationContent
|
id: notificationContent
|
||||||
|
|
||||||
|
readonly property real expandedTextHeight: bodyText.contentHeight || 0
|
||||||
|
readonly property real twoLineHeight: Theme.fontSizeSmall * 1.2 * 2
|
||||||
|
readonly property real extraHeight: (descriptionExpanded && expandedTextHeight > twoLineHeight + 2) ? (expandedTextHeight - twoLineHeight) : 0
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: cardPadding
|
||||||
anchors.leftMargin: 16
|
anchors.leftMargin: Theme.spacingL
|
||||||
anchors.rightMargin: 56
|
anchors.rightMargin: Theme.spacingL + (compactMode ? 32 : 40)
|
||||||
height: 98
|
height: collapsedContentHeight + extraHeight
|
||||||
|
|
||||||
DankCircularImage {
|
DankCircularImage {
|
||||||
id: iconContainer
|
id: iconContainer
|
||||||
@@ -366,10 +387,10 @@ PanelWindow {
|
|||||||
readonly property bool hasNotificationImage: notificationData && notificationData.image && notificationData.image !== ""
|
readonly property bool hasNotificationImage: notificationData && notificationData.image && notificationData.image !== ""
|
||||||
readonly property bool needsImagePersist: hasNotificationImage && notificationData.image.startsWith("image://qsimage/") && !notificationData.persistedImagePath
|
readonly property bool needsImagePersist: hasNotificationImage && notificationData.image.startsWith("image://qsimage/") && !notificationData.persistedImagePath
|
||||||
|
|
||||||
width: 63
|
width: popupIconSize
|
||||||
height: 63
|
height: popupIconSize
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.top: parent.top
|
||||||
|
|
||||||
imageSource: {
|
imageSource: {
|
||||||
if (!notificationData)
|
if (!notificationData)
|
||||||
@@ -412,81 +433,78 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Column {
|
||||||
id: textContainer
|
id: textContainer
|
||||||
|
|
||||||
anchors.left: iconContainer.right
|
anchors.left: iconContainer.right
|
||||||
anchors.leftMargin: 12
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 0
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
spacing: compactMode ? 1 : 2
|
||||||
anchors.bottomMargin: 8
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Item {
|
StyledText {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
text: {
|
||||||
anchors.top: parent.top
|
if (!notificationData)
|
||||||
anchors.topMargin: -2
|
return "";
|
||||||
|
const appName = notificationData.appName || "";
|
||||||
|
const timeStr = notificationData.timeStr || "";
|
||||||
|
return timeStr.length > 0 ? appName + " • " + timeStr : appName;
|
||||||
|
}
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
maximumLineCount: 1
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
StyledText {
|
||||||
width: parent.width
|
text: notificationData ? (notificationData.summary || "") : ""
|
||||||
spacing: 2
|
color: Theme.surfaceText
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
maximumLineCount: 1
|
||||||
|
visible: text.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
width: parent.width
|
id: bodyText
|
||||||
text: {
|
property bool hasMoreText: truncated
|
||||||
if (!notificationData)
|
|
||||||
return "";
|
|
||||||
|
|
||||||
const appName = notificationData.appName || "";
|
text: notificationData ? (notificationData.htmlBody || "") : ""
|
||||||
const timeStr = notificationData.timeStr || "";
|
color: Theme.surfaceVariantText
|
||||||
if (timeStr.length > 0)
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
return appName + " • " + timeStr;
|
width: parent.width
|
||||||
else
|
elide: descriptionExpanded ? Text.ElideNone : Text.ElideRight
|
||||||
return appName;
|
horizontalAlignment: Text.AlignLeft
|
||||||
}
|
maximumLineCount: descriptionExpanded ? -1 : (compactMode ? 1 : 2)
|
||||||
color: Theme.surfaceVariantText
|
wrapMode: Text.WordWrap
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
visible: text.length > 0
|
||||||
font.weight: Font.Medium
|
linkColor: Theme.primary
|
||||||
elide: Text.ElideRight
|
onLinkActivated: link => Qt.openUrlExternally(link)
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
maximumLineCount: 1
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
|
onClicked: mouse => {
|
||||||
|
if (!parent.hoveredLink && (bodyText.hasMoreText || descriptionExpanded))
|
||||||
|
win.descriptionExpanded = !win.descriptionExpanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
propagateComposedEvents: true
|
||||||
text: notificationData ? (notificationData.summary || "") : ""
|
onPressed: mouse => {
|
||||||
color: Theme.surfaceText
|
if (parent.hoveredLink)
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
mouse.accepted = false;
|
||||||
font.weight: Font.Medium
|
|
||||||
width: parent.width
|
|
||||||
elide: Text.ElideRight
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
maximumLineCount: 1
|
|
||||||
visible: text.length > 0
|
|
||||||
}
|
}
|
||||||
|
onReleased: mouse => {
|
||||||
StyledText {
|
if (parent.hoveredLink)
|
||||||
text: notificationData ? (notificationData.htmlBody || "") : ""
|
mouse.accepted = false;
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
width: parent.width
|
|
||||||
elide: Text.ElideRight
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
maximumLineCount: 2
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
visible: text.length > 0
|
|
||||||
linkColor: Theme.primary
|
|
||||||
onLinkActivated: link => {
|
|
||||||
return Qt.openUrlExternally(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -498,11 +516,11 @@ PanelWindow {
|
|||||||
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 12
|
anchors.topMargin: cardPadding
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: Theme.spacingL
|
||||||
iconName: "close"
|
iconName: "close"
|
||||||
iconSize: 18
|
iconSize: compactMode ? 16 : 18
|
||||||
buttonSize: 28
|
buttonSize: compactMode ? 24 : 28
|
||||||
z: 15
|
z: 15
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (notificationData && !win.exiting)
|
if (notificationData && !win.exiting)
|
||||||
@@ -511,11 +529,11 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.right: clearButton.left
|
anchors.right: clearButton.visible ? clearButton.left : parent.right
|
||||||
anchors.rightMargin: 8
|
anchors.rightMargin: clearButton.visible ? contentSpacing : Theme.spacingL
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
spacing: 8
|
spacing: contentSpacing
|
||||||
z: 20
|
z: 20
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
@@ -524,9 +542,9 @@ PanelWindow {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
property bool isHovered: false
|
property bool isHovered: false
|
||||||
|
|
||||||
width: Math.max(actionText.implicitWidth + 12, 50)
|
width: Math.max(actionText.implicitWidth + Theme.spacingM, compactMode ? 40 : 50)
|
||||||
height: 24
|
height: actionButtonHeight
|
||||||
radius: 4
|
radius: Theme.spacingXS
|
||||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
@@ -550,7 +568,6 @@ PanelWindow {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
if (modelData && modelData.invoke)
|
if (modelData && modelData.invoke)
|
||||||
modelData.invoke();
|
modelData.invoke();
|
||||||
|
|
||||||
if (notificationData && !win.exiting)
|
if (notificationData && !win.exiting)
|
||||||
notificationData.popup = false;
|
notificationData.popup = false;
|
||||||
}
|
}
|
||||||
@@ -563,14 +580,16 @@ PanelWindow {
|
|||||||
id: clearButton
|
id: clearButton
|
||||||
|
|
||||||
property bool isHovered: false
|
property bool isHovered: false
|
||||||
|
readonly property int actionCount: notificationData ? (notificationData.actions || []).length : 0
|
||||||
|
|
||||||
|
visible: actionCount < 3
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 16
|
anchors.rightMargin: Theme.spacingL
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 8
|
anchors.bottomMargin: contentSpacing
|
||||||
width: Math.max(clearTextLabel.implicitWidth + 12, 50)
|
width: Math.max(clearTextLabel.implicitWidth + Theme.spacingM, compactMode ? 40 : 50)
|
||||||
height: 24
|
height: actionButtonHeight
|
||||||
radius: 4
|
radius: Theme.spacingXS
|
||||||
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
color: isHovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1) : "transparent"
|
||||||
z: 20
|
z: 20
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
@@ -6,7 +7,12 @@ QtObject {
|
|||||||
|
|
||||||
property var modelData
|
property var modelData
|
||||||
property int topMargin: 0
|
property int topMargin: 0
|
||||||
property int baseNotificationHeight: 120
|
readonly property bool compactMode: SettingsData.notificationCompactMode
|
||||||
|
readonly property real cardPadding: compactMode ? Theme.spacingS : Theme.spacingM
|
||||||
|
readonly property real popupIconSize: compactMode ? 48 : 63
|
||||||
|
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
||||||
|
readonly property real popupSpacing: 4
|
||||||
|
readonly property int baseNotificationHeight: cardPadding * 2 + popupIconSize + actionButtonHeight + Theme.spacingS + popupSpacing
|
||||||
property int maxTargetNotifications: 4
|
property int maxTargetNotifications: 4
|
||||||
property var popupWindows: [] // strong refs to windows (live until exitFinished)
|
property var popupWindows: [] // strong refs to windows (live until exitFinished)
|
||||||
property var destroyingWindows: new Set()
|
property var destroyingWindows: new Set()
|
||||||
|
|||||||
@@ -262,9 +262,7 @@ DankOSD {
|
|||||||
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
|
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
|
||||||
|
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!vertSlider.dragging) {
|
vertSlider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100));
|
||||||
vertSlider.value = Math.min(100, Math.round(AudioService.sink.audio.volume * 100));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ Item {
|
|||||||
readonly property bool showOnOverview: instanceData?.config?.showOnOverview ?? false
|
readonly property bool showOnOverview: instanceData?.config?.showOnOverview ?? false
|
||||||
readonly property bool showOnOverviewOnly: instanceData?.config?.showOnOverviewOnly ?? false
|
readonly property bool showOnOverviewOnly: instanceData?.config?.showOnOverviewOnly ?? false
|
||||||
readonly property bool overviewActive: CompositorService.isNiri && NiriService.inOverview
|
readonly property bool overviewActive: CompositorService.isNiri && NiriService.inOverview
|
||||||
|
readonly property bool clickThrough: instanceData?.config?.clickThrough ?? false
|
||||||
|
readonly property bool syncPositionAcrossScreens: instanceData?.config?.syncPositionAcrossScreens ?? false
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: PluginService
|
target: PluginService
|
||||||
@@ -83,6 +85,7 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
|
readonly property string screenKey: SettingsData.getScreenDisplayName(screen)
|
||||||
|
readonly property string positionKey: syncPositionAcrossScreens ? "_synced" : screenKey
|
||||||
|
|
||||||
readonly property int screenWidth: screen?.width ?? 1920
|
readonly property int screenWidth: screen?.width ?? 1920
|
||||||
readonly property int screenHeight: screen?.height ?? 1080
|
readonly property int screenHeight: screen?.height ?? 1080
|
||||||
@@ -96,53 +99,114 @@ Item {
|
|||||||
|
|
||||||
readonly property bool hasSavedPosition: {
|
readonly property bool hasSavedPosition: {
|
||||||
if (isInstance)
|
if (isInstance)
|
||||||
return instanceData?.positions?.[screenKey]?.x !== undefined;
|
return instanceData?.positions?.[positionKey]?.x !== undefined;
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopX_" + screenKey, null) !== null;
|
return pluginService.loadPluginData(pluginId, "desktopX_" + positionKey, null) !== null;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "x", null) !== null;
|
return SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "x", null) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool hasSavedSize: {
|
readonly property bool hasSavedSize: {
|
||||||
if (isInstance)
|
if (isInstance)
|
||||||
return instanceData?.positions?.[screenKey]?.width !== undefined;
|
return instanceData?.positions?.[positionKey]?.width !== undefined;
|
||||||
if (usePluginService)
|
if (usePluginService)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopWidth_" + screenKey, null) !== null;
|
return pluginService.loadPluginData(pluginId, "desktopWidth_" + positionKey, null) !== null;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "width", null) !== null;
|
return SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "width", null) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
property real savedX: {
|
property real savedX: {
|
||||||
if (isInstance)
|
if (isInstance) {
|
||||||
return instanceData?.positions?.[screenKey]?.x ?? (screenWidth / 2 - savedWidth / 2);
|
const val = instanceData?.positions?.[positionKey]?.x;
|
||||||
if (usePluginService)
|
if (val === undefined)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopX_" + screenKey, screenWidth / 2 - savedWidth / 2);
|
return screenWidth / 2 - savedWidth / 2;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "x", screenWidth / 2 - savedWidth / 2);
|
return syncPositionAcrossScreens ? val * screenWidth : val;
|
||||||
|
}
|
||||||
|
if (usePluginService) {
|
||||||
|
const val = pluginService.loadPluginData(pluginId, "desktopX_" + positionKey, null);
|
||||||
|
if (val === null)
|
||||||
|
return screenWidth / 2 - savedWidth / 2;
|
||||||
|
return syncPositionAcrossScreens ? val * screenWidth : val;
|
||||||
|
}
|
||||||
|
const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "x", null);
|
||||||
|
if (val === null)
|
||||||
|
return screenWidth / 2 - savedWidth / 2;
|
||||||
|
return syncPositionAcrossScreens ? val * screenWidth : val;
|
||||||
}
|
}
|
||||||
property real savedY: {
|
property real savedY: {
|
||||||
if (isInstance)
|
if (isInstance) {
|
||||||
return instanceData?.positions?.[screenKey]?.y ?? (screenHeight / 2 - savedHeight / 2);
|
const val = instanceData?.positions?.[positionKey]?.y;
|
||||||
if (usePluginService)
|
if (val === undefined)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopY_" + screenKey, screenHeight / 2 - savedHeight / 2);
|
return screenHeight / 2 - savedHeight / 2;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "y", screenHeight / 2 - savedHeight / 2);
|
return syncPositionAcrossScreens ? val * screenHeight : val;
|
||||||
|
}
|
||||||
|
if (usePluginService) {
|
||||||
|
const val = pluginService.loadPluginData(pluginId, "desktopY_" + positionKey, null);
|
||||||
|
if (val === null)
|
||||||
|
return screenHeight / 2 - savedHeight / 2;
|
||||||
|
return syncPositionAcrossScreens ? val * screenHeight : val;
|
||||||
|
}
|
||||||
|
const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "y", null);
|
||||||
|
if (val === null)
|
||||||
|
return screenHeight / 2 - savedHeight / 2;
|
||||||
|
return syncPositionAcrossScreens ? val * screenHeight : val;
|
||||||
}
|
}
|
||||||
property real savedWidth: {
|
property real savedWidth: {
|
||||||
if (isInstance)
|
if (isInstance) {
|
||||||
return instanceData?.positions?.[screenKey]?.width ?? 280;
|
const val = instanceData?.positions?.[positionKey]?.width;
|
||||||
if (usePluginService)
|
if (val === undefined)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopWidth_" + screenKey, 200);
|
return 280;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "width", 280);
|
return val;
|
||||||
|
}
|
||||||
|
if (usePluginService) {
|
||||||
|
const val = pluginService.loadPluginData(pluginId, "desktopWidth_" + positionKey, null);
|
||||||
|
if (val === null)
|
||||||
|
return 200;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "width", null);
|
||||||
|
if (val === null)
|
||||||
|
return 280;
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
property real savedHeight: {
|
property real savedHeight: {
|
||||||
if (isInstance)
|
if (isInstance) {
|
||||||
return instanceData?.positions?.[screenKey]?.height ?? 180;
|
const val = instanceData?.positions?.[positionKey]?.height;
|
||||||
if (usePluginService)
|
if (val === undefined)
|
||||||
return pluginService.loadPluginData(pluginId, "desktopHeight_" + screenKey, 200);
|
return forceSquare ? savedWidth : 180;
|
||||||
return SettingsData.getDesktopWidgetPosition(pluginId, screenKey, "height", 180);
|
return forceSquare ? savedWidth : val;
|
||||||
|
}
|
||||||
|
if (usePluginService) {
|
||||||
|
const val = pluginService.loadPluginData(pluginId, "desktopHeight_" + positionKey, null);
|
||||||
|
if (val === null)
|
||||||
|
return forceSquare ? savedWidth : 200;
|
||||||
|
return forceSquare ? savedWidth : val;
|
||||||
|
}
|
||||||
|
const val = SettingsData.getDesktopWidgetPosition(pluginId, positionKey, "height", null);
|
||||||
|
if (val === null)
|
||||||
|
return forceSquare ? savedWidth : 180;
|
||||||
|
return forceSquare ? savedWidth : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
property real widgetX: Math.max(0, Math.min(savedX, screenWidth - widgetWidth))
|
property real dragOverrideX: -1
|
||||||
property real widgetY: Math.max(0, Math.min(savedY, screenHeight - widgetHeight))
|
property real dragOverrideY: -1
|
||||||
property real widgetWidth: Math.max(minWidth, Math.min(savedWidth, screenWidth))
|
property real dragOverrideW: -1
|
||||||
property real widgetHeight: Math.max(minHeight, Math.min(savedHeight, screenHeight))
|
property real dragOverrideH: -1
|
||||||
|
|
||||||
|
readonly property real effectiveX: dragOverrideX >= 0 ? dragOverrideX : savedX
|
||||||
|
readonly property real effectiveY: dragOverrideY >= 0 ? dragOverrideY : savedY
|
||||||
|
readonly property real effectiveW: dragOverrideW >= 0 ? dragOverrideW : savedWidth
|
||||||
|
readonly property real effectiveH: dragOverrideH >= 0 ? dragOverrideH : savedHeight
|
||||||
|
|
||||||
|
readonly property real widgetX: Math.max(0, Math.min(effectiveX, screenWidth - widgetWidth))
|
||||||
|
readonly property real widgetY: Math.max(0, Math.min(effectiveY, screenHeight - widgetHeight))
|
||||||
|
readonly property real widgetWidth: Math.max(minWidth, Math.min(effectiveW, screenWidth))
|
||||||
|
readonly property real widgetHeight: Math.max(minHeight, Math.min(effectiveH, screenHeight))
|
||||||
|
|
||||||
|
function clearDragOverrides() {
|
||||||
|
dragOverrideX = -1;
|
||||||
|
dragOverrideY = -1;
|
||||||
|
dragOverrideW = -1;
|
||||||
|
dragOverrideH = -1;
|
||||||
|
}
|
||||||
|
|
||||||
property real minWidth: contentLoader.item?.minWidth ?? 100
|
property real minWidth: contentLoader.item?.minWidth ?? 100
|
||||||
property real minHeight: contentLoader.item?.minHeight ?? 100
|
property real minHeight: contentLoader.item?.minHeight ?? 100
|
||||||
@@ -163,41 +227,45 @@ Item {
|
|||||||
return Math.round(value / gridSize) * gridSize;
|
return Math.round(value / gridSize) * gridSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
function savePosition() {
|
function savePosition(finalX, finalY) {
|
||||||
|
const xVal = syncPositionAcrossScreens ? finalX / screenWidth : finalX;
|
||||||
|
const yVal = syncPositionAcrossScreens ? finalY / screenHeight : finalY;
|
||||||
if (isInstance && instanceData) {
|
if (isInstance && instanceData) {
|
||||||
SettingsData.updateDesktopWidgetInstancePosition(instanceId, screenKey, {
|
SettingsData.updateDesktopWidgetInstancePosition(instanceId, positionKey, {
|
||||||
x: root.widgetX,
|
x: xVal,
|
||||||
y: root.widgetY
|
y: yVal
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (usePluginService) {
|
if (usePluginService) {
|
||||||
pluginService.savePluginData(pluginId, "desktopX_" + screenKey, root.widgetX);
|
pluginService.savePluginData(pluginId, "desktopX_" + positionKey, xVal);
|
||||||
pluginService.savePluginData(pluginId, "desktopY_" + screenKey, root.widgetY);
|
pluginService.savePluginData(pluginId, "desktopY_" + positionKey, yVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SettingsData.updateDesktopWidgetPosition(pluginId, screenKey, {
|
SettingsData.updateDesktopWidgetPosition(pluginId, positionKey, {
|
||||||
x: root.widgetX,
|
x: xVal,
|
||||||
y: root.widgetY
|
y: yVal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSize() {
|
function saveSize(finalW, finalH) {
|
||||||
|
const sizeVal = forceSquare ? Math.max(finalW, finalH) : finalW;
|
||||||
|
const heightVal = forceSquare ? sizeVal : finalH;
|
||||||
if (isInstance && instanceData) {
|
if (isInstance && instanceData) {
|
||||||
SettingsData.updateDesktopWidgetInstancePosition(instanceId, screenKey, {
|
SettingsData.updateDesktopWidgetInstancePosition(instanceId, positionKey, {
|
||||||
width: root.widgetWidth,
|
width: sizeVal,
|
||||||
height: root.widgetHeight
|
height: heightVal
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (usePluginService) {
|
if (usePluginService) {
|
||||||
pluginService.savePluginData(pluginId, "desktopWidth_" + screenKey, root.widgetWidth);
|
pluginService.savePluginData(pluginId, "desktopWidth_" + positionKey, sizeVal);
|
||||||
pluginService.savePluginData(pluginId, "desktopHeight_" + screenKey, root.widgetHeight);
|
pluginService.savePluginData(pluginId, "desktopHeight_" + positionKey, heightVal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SettingsData.updateDesktopWidgetPosition(pluginId, screenKey, {
|
SettingsData.updateDesktopWidgetPosition(pluginId, positionKey, {
|
||||||
width: root.widgetWidth,
|
width: sizeVal,
|
||||||
height: root.widgetHeight
|
height: heightVal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,6 +281,12 @@ Item {
|
|||||||
}
|
}
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
Region {
|
||||||
|
id: emptyMask
|
||||||
|
}
|
||||||
|
|
||||||
|
mask: root.clickThrough ? emptyMask : null
|
||||||
|
|
||||||
WlrLayershell.namespace: "quickshell:desktop-widget:" + root.pluginId + (root.instanceId ? ":" + root.instanceId : "")
|
WlrLayershell.namespace: "quickshell:desktop-widget:" + root.pluginId + (root.instanceId ? ":" + root.instanceId : "")
|
||||||
WlrLayershell.layer: {
|
WlrLayershell.layer: {
|
||||||
if (root.isInteracting && !CompositorService.useHyprlandFocusGrab)
|
if (root.isInteracting && !CompositorService.useHyprlandFocusGrab)
|
||||||
@@ -315,12 +389,14 @@ Item {
|
|||||||
if (!root.hasSavedSize) {
|
if (!root.hasSavedSize) {
|
||||||
const defW = item.defaultWidth ?? item.widgetWidth ?? 280;
|
const defW = item.defaultWidth ?? item.widgetWidth ?? 280;
|
||||||
const defH = item.defaultHeight ?? item.widgetHeight ?? 180;
|
const defH = item.defaultHeight ?? item.widgetHeight ?? 180;
|
||||||
root.widgetWidth = Math.max(root.minWidth, Math.min(defW, root.screenWidth));
|
const finalW = Math.max(root.minWidth, Math.min(defW, root.screenWidth));
|
||||||
root.widgetHeight = Math.max(root.minHeight, Math.min(defH, root.screenHeight));
|
const finalH = Math.max(root.minHeight, Math.min(defH, root.screenHeight));
|
||||||
|
root.saveSize(finalW, finalH);
|
||||||
}
|
}
|
||||||
if (!root.hasSavedPosition) {
|
if (!root.hasSavedPosition) {
|
||||||
root.widgetX = Math.max(0, Math.min(root.screenWidth / 2 - root.widgetWidth / 2, root.screenWidth - root.widgetWidth));
|
const finalX = Math.max(0, Math.min(root.screenWidth / 2 - root.widgetWidth / 2, root.screenWidth - root.widgetWidth));
|
||||||
root.widgetY = Math.max(0, Math.min(root.screenHeight / 2 - root.widgetHeight / 2, root.screenHeight - root.widgetHeight));
|
const finalY = Math.max(0, Math.min(root.screenHeight / 2 - root.widgetHeight / 2, root.screenHeight - root.widgetHeight));
|
||||||
|
root.savePosition(finalX, finalY);
|
||||||
}
|
}
|
||||||
if (item.widgetWidth !== undefined)
|
if (item.widgetWidth !== undefined)
|
||||||
item.widgetWidth = Qt.binding(() => contentLoader.width);
|
item.widgetWidth = Qt.binding(() => contentLoader.width);
|
||||||
@@ -355,6 +431,7 @@ Item {
|
|||||||
id: dragArea
|
id: dragArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
|
enabled: !root.clickThrough
|
||||||
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.ArrowCursor
|
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
property point startPos
|
property point startPos
|
||||||
@@ -367,6 +444,8 @@ Item {
|
|||||||
startY = root.widgetY;
|
startY = root.widgetY;
|
||||||
root.previewX = root.widgetX;
|
root.previewX = root.widgetX;
|
||||||
root.previewY = root.widgetY;
|
root.previewY = root.widgetY;
|
||||||
|
root.dragOverrideX = root.widgetX;
|
||||||
|
root.dragOverrideY = root.widgetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPositionChanged: mouse => {
|
onPositionChanged: mouse => {
|
||||||
@@ -384,16 +463,15 @@ Item {
|
|||||||
root.previewY = newY;
|
root.previewY = newY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
root.widgetX = newX;
|
root.dragOverrideX = newX;
|
||||||
root.widgetY = newY;
|
root.dragOverrideY = newY;
|
||||||
}
|
}
|
||||||
|
|
||||||
onReleased: {
|
onReleased: {
|
||||||
if (root.useGhostPreview) {
|
const finalX = root.useGhostPreview ? root.previewX : root.dragOverrideX;
|
||||||
root.widgetX = root.previewX;
|
const finalY = root.useGhostPreview ? root.previewY : root.dragOverrideY;
|
||||||
root.widgetY = root.previewY;
|
root.savePosition(finalX, finalY);
|
||||||
}
|
root.clearDragOverrides();
|
||||||
root.savePosition();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +482,7 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
acceptedButtons: Qt.RightButton
|
acceptedButtons: Qt.RightButton
|
||||||
|
enabled: !root.clickThrough
|
||||||
cursorShape: pressed ? Qt.SizeFDiagCursor : Qt.ArrowCursor
|
cursorShape: pressed ? Qt.SizeFDiagCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
property point startPos
|
property point startPos
|
||||||
@@ -416,6 +495,8 @@ Item {
|
|||||||
startHeight = root.widgetHeight;
|
startHeight = root.widgetHeight;
|
||||||
root.previewWidth = root.widgetWidth;
|
root.previewWidth = root.widgetWidth;
|
||||||
root.previewHeight = root.widgetHeight;
|
root.previewHeight = root.widgetHeight;
|
||||||
|
root.dragOverrideW = root.widgetWidth;
|
||||||
|
root.dragOverrideH = root.widgetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPositionChanged: mouse => {
|
onPositionChanged: mouse => {
|
||||||
@@ -438,16 +519,15 @@ Item {
|
|||||||
root.previewHeight = newH;
|
root.previewHeight = newH;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
root.widgetWidth = newW;
|
root.dragOverrideW = newW;
|
||||||
root.widgetHeight = newH;
|
root.dragOverrideH = newH;
|
||||||
}
|
}
|
||||||
|
|
||||||
onReleased: {
|
onReleased: {
|
||||||
if (root.useGhostPreview) {
|
const finalW = root.useGhostPreview ? root.previewWidth : root.dragOverrideW;
|
||||||
root.widgetWidth = root.previewWidth;
|
const finalH = root.useGhostPreview ? root.previewHeight : root.dragOverrideH;
|
||||||
root.widgetHeight = root.previewHeight;
|
root.saveSize(finalW, finalH);
|
||||||
}
|
root.clearDragOverrides();
|
||||||
root.saveSize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,10 +177,11 @@ Item {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
if (!SystemUpdateService.shellVersion)
|
if (!SystemUpdateService.shellVersion && !DMSService.cliVersion)
|
||||||
return "dms";
|
return "dms";
|
||||||
|
|
||||||
let version = SystemUpdateService.shellVersion;
|
let version = SystemUpdateService.shellVersion || "";
|
||||||
|
let cliVersion = DMSService.cliVersion || "";
|
||||||
|
|
||||||
// Debian/Ubuntu/OpenSUSE git format: 1.0.3+git2264.c5c5ce84
|
// Debian/Ubuntu/OpenSUSE git format: 1.0.3+git2264.c5c5ce84
|
||||||
let match = version.match(/^([\d.]+)\+git(\d+)\./);
|
let match = version.match(/^([\d.]+)\+git(\d+)\./);
|
||||||
@@ -191,7 +192,25 @@ Item {
|
|||||||
// Fedora COPR git format: 0.0.git.2267.d430cae9
|
// Fedora COPR git format: 0.0.git.2267.d430cae9
|
||||||
match = version.match(/^[\d.]+\.git\.(\d+)\./);
|
match = version.match(/^[\d.]+\.git\.(\d+)\./);
|
||||||
if (match) {
|
if (match) {
|
||||||
return `dms (git) v1.0.3-${match[1]}`;
|
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]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stable release format: 1.0.3
|
// Stable release format: 1.0.3
|
||||||
@@ -200,6 +219,18 @@ Item {
|
|||||||
return `dms v${match[1]}`;
|
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}`;
|
return `dms ${version}`;
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeXLarge
|
font.pixelSize: Theme.fontSizeXLarge
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pragma ComponentBehavior
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
|||||||
@@ -63,7 +63,13 @@ SettingsCard {
|
|||||||
DankActionButton {
|
DankActionButton {
|
||||||
id: menuButton
|
id: menuButton
|
||||||
iconName: "more_vert"
|
iconName: "more_vert"
|
||||||
onClicked: actionsMenu.open()
|
onClicked: {
|
||||||
|
if (actionsMenu.opened) {
|
||||||
|
actionsMenu.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
actionsMenu.open();
|
||||||
|
}
|
||||||
|
|
||||||
Popup {
|
Popup {
|
||||||
id: actionsMenu
|
id: actionsMenu
|
||||||
@@ -71,7 +77,7 @@ SettingsCard {
|
|||||||
y: parent.height + Theme.spacingXS
|
y: parent.height + Theme.spacingXS
|
||||||
width: 160
|
width: 160
|
||||||
padding: Theme.spacingXS
|
padding: Theme.spacingXS
|
||||||
modal: true
|
modal: false
|
||||||
focus: true
|
focus: true
|
||||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
|
||||||
@@ -218,6 +224,73 @@ SettingsCard {
|
|||||||
|
|
||||||
SettingsDivider {}
|
SettingsDivider {}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: groupRow.height + Theme.spacingM * 2
|
||||||
|
visible: (SettingsData.desktopWidgetGroups || []).length > 0
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: groupRow
|
||||||
|
x: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Group")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: 80
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
DankDropdown {
|
||||||
|
id: groupDropdown
|
||||||
|
width: parent.width - 80 - Theme.spacingM
|
||||||
|
compactMode: true
|
||||||
|
|
||||||
|
property var groupsData: {
|
||||||
|
const groups = SettingsData.desktopWidgetGroups || [];
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
value: "",
|
||||||
|
label: I18n.tr("None")
|
||||||
|
}
|
||||||
|
];
|
||||||
|
for (const g of groups) {
|
||||||
|
items.push({
|
||||||
|
value: g.id,
|
||||||
|
label: g.name
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
options: groupsData.map(g => g.label)
|
||||||
|
currentValue: {
|
||||||
|
const currentGroup = root.instanceData?.group ?? "";
|
||||||
|
const item = groupsData.find(g => g.value === currentGroup);
|
||||||
|
return item?.label ?? I18n.tr("None");
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: value => {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
const item = groupsData.find(g => g.label === value);
|
||||||
|
const groupId = item?.value ?? "";
|
||||||
|
SettingsData.updateDesktopWidgetInstance(root.instanceId, {
|
||||||
|
group: groupId || null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {
|
||||||
|
visible: (SettingsData.desktopWidgetGroups || []).length > 0
|
||||||
|
}
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
text: I18n.tr("Show on Overlay")
|
text: I18n.tr("Show on Overlay")
|
||||||
checked: instanceData?.config?.showOnOverlay ?? false
|
checked: instanceData?.config?.showOnOverlay ?? false
|
||||||
@@ -266,6 +339,38 @@ SettingsCard {
|
|||||||
|
|
||||||
SettingsDivider {}
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Click Through")
|
||||||
|
description: I18n.tr("Allow clicks to pass through the widget")
|
||||||
|
checked: instanceData?.config?.clickThrough ?? false
|
||||||
|
onToggled: isChecked => {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, {
|
||||||
|
clickThrough: isChecked
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Sync Position Across Screens")
|
||||||
|
description: I18n.tr("Use the same position and size on all displays")
|
||||||
|
checked: instanceData?.config?.syncPositionAcrossScreens ?? false
|
||||||
|
onToggled: isChecked => {
|
||||||
|
if (!root.instanceId)
|
||||||
|
return;
|
||||||
|
if (isChecked)
|
||||||
|
SettingsData.syncDesktopWidgetPositionToAllScreens(root.instanceId);
|
||||||
|
SettingsData.updateDesktopWidgetInstanceConfig(root.instanceId, {
|
||||||
|
syncPositionAcrossScreens: isChecked
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsDivider {}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: ipcColumn.height + Theme.spacingM * 2
|
height: ipcColumn.height + Theme.spacingM * 2
|
||||||
|
|||||||
@@ -14,20 +14,46 @@ Item {
|
|||||||
LayoutMirroring.childrenInherit: true
|
LayoutMirroring.childrenInherit: true
|
||||||
|
|
||||||
property var expandedStates: ({})
|
property var expandedStates: ({})
|
||||||
|
property var groupCollapsedStates: ({})
|
||||||
property var parentModal: null
|
property var parentModal: null
|
||||||
|
property string editingGroupId: ""
|
||||||
|
property string newGroupName: ""
|
||||||
|
|
||||||
DesktopWidgetBrowser {
|
readonly property var allInstances: SettingsData.desktopWidgetInstances || []
|
||||||
id: widgetBrowser
|
readonly property var allGroups: SettingsData.desktopWidgetGroups || []
|
||||||
parentModal: root.parentModal
|
|
||||||
onWidgetAdded: widgetType => {
|
function showWidgetBrowser() {
|
||||||
ToastService.showInfo(I18n.tr("Widget added"));
|
widgetBrowserLoader.active = true;
|
||||||
|
if (widgetBrowserLoader.item)
|
||||||
|
widgetBrowserLoader.item.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDesktopPluginBrowser() {
|
||||||
|
desktopPluginBrowserLoader.active = true;
|
||||||
|
if (desktopPluginBrowserLoader.item)
|
||||||
|
desktopPluginBrowserLoader.item.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: widgetBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
|
DesktopWidgetBrowser {
|
||||||
|
parentModal: root.parentModal
|
||||||
|
onWidgetAdded: widgetType => {
|
||||||
|
ToastService.showInfo(I18n.tr("Widget added"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginBrowser {
|
LazyLoader {
|
||||||
id: desktopPluginBrowser
|
id: desktopPluginBrowserLoader
|
||||||
parentModal: root.parentModal
|
active: false
|
||||||
typeFilter: "desktop-widget"
|
|
||||||
|
PluginBrowser {
|
||||||
|
parentModal: root.parentModal
|
||||||
|
typeFilter: "desktop-widget"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankFlickable {
|
DankFlickable {
|
||||||
@@ -68,66 +94,512 @@ Item {
|
|||||||
DankButton {
|
DankButton {
|
||||||
text: I18n.tr("Add Widget")
|
text: I18n.tr("Add Widget")
|
||||||
iconName: "add"
|
iconName: "add"
|
||||||
onClicked: widgetBrowser.show()
|
onClicked: root.showWidgetBrowser()
|
||||||
}
|
}
|
||||||
|
|
||||||
DankButton {
|
DankButton {
|
||||||
text: I18n.tr("Browse Plugins")
|
text: I18n.tr("Browse Plugins")
|
||||||
iconName: "store"
|
iconName: "store"
|
||||||
onClicked: desktopPluginBrowser.show()
|
onClicked: root.showDesktopPluginBrowser()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
width: parent.width
|
||||||
|
iconName: "folder"
|
||||||
|
title: I18n.tr("Groups")
|
||||||
|
collapsible: true
|
||||||
|
expanded: root.allGroups.length > 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
x: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: I18n.tr("Organize widgets into collapsible groups")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: newGroupField
|
||||||
|
width: parent.width - addGroupBtn.width - Theme.spacingS
|
||||||
|
placeholderText: I18n.tr("New group name...")
|
||||||
|
text: root.newGroupName
|
||||||
|
onTextChanged: root.newGroupName = text
|
||||||
|
onAccepted: {
|
||||||
|
if (!text.trim())
|
||||||
|
return;
|
||||||
|
SettingsData.createDesktopWidgetGroup(text.trim());
|
||||||
|
root.newGroupName = "";
|
||||||
|
text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
id: addGroupBtn
|
||||||
|
iconName: "add"
|
||||||
|
text: I18n.tr("Add")
|
||||||
|
enabled: root.newGroupName.trim().length > 0
|
||||||
|
onClicked: {
|
||||||
|
SettingsData.createDesktopWidgetGroup(root.newGroupName.trim());
|
||||||
|
root.newGroupName = "";
|
||||||
|
newGroupField.text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
visible: root.allGroups.length > 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.allGroups
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: groupItem
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: 40
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: groupMouseArea.containsMouse ? Theme.surfaceHover : Theme.surfaceContainer
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "folder"
|
||||||
|
size: Theme.iconSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
active: root.editingGroupId === groupItem.modelData.id
|
||||||
|
width: active ? parent.width - Theme.iconSizeSmall - deleteGroupBtn.width - Theme.spacingS * 3 : 0
|
||||||
|
height: active ? 32 : 0
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
sourceComponent: DankTextField {
|
||||||
|
text: groupItem.modelData.name
|
||||||
|
onAccepted: {
|
||||||
|
if (!text.trim())
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetGroup(groupItem.modelData.id, {
|
||||||
|
name: text.trim()
|
||||||
|
});
|
||||||
|
root.editingGroupId = "";
|
||||||
|
}
|
||||||
|
onEditingFinished: {
|
||||||
|
if (!text.trim())
|
||||||
|
return;
|
||||||
|
SettingsData.updateDesktopWidgetGroup(groupItem.modelData.id, {
|
||||||
|
name: text.trim()
|
||||||
|
});
|
||||||
|
root.editingGroupId = "";
|
||||||
|
}
|
||||||
|
Component.onCompleted: forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
visible: root.editingGroupId !== groupItem.modelData.id
|
||||||
|
text: groupItem.modelData.name
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: parent.width - Theme.iconSizeSmall - deleteGroupBtn.width - Theme.spacingS * 3
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: deleteGroupBtn
|
||||||
|
iconName: "delete"
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: {
|
||||||
|
SettingsData.removeDesktopWidgetGroup(groupItem.modelData.id);
|
||||||
|
ToastService.showInfo(I18n.tr("Group removed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: groupMouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onDoubleClicked: root.editingGroupId = groupItem.modelData.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.allGroups
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: groupSection
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
readonly property string groupId: modelData.id
|
||||||
|
readonly property var groupInstances: root.allInstances.filter(inst => inst.group === groupId)
|
||||||
|
|
||||||
|
width: mainColumn.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
visible: groupInstances.length > 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 44
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: (root.groupCollapsedStates[groupSection.groupId] ?? false) ? "expand_more" : "expand_less"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "folder"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: groupSection.modelData.name
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "(" + groupSection.groupInstances.length + ")"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
var states = Object.assign({}, root.groupCollapsedStates);
|
||||||
|
states[groupSection.groupId] = !(states[groupSection.groupId] ?? false);
|
||||||
|
root.groupCollapsedStates = states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
visible: !(root.groupCollapsedStates[groupSection.groupId] ?? false)
|
||||||
|
leftPadding: Theme.spacingM
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
objectProp: "id"
|
||||||
|
values: groupSection.groupInstances
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: groupDelegateItem
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
property bool held: groupDragArea.pressed
|
||||||
|
property real originalY: y
|
||||||
|
|
||||||
|
readonly property string instanceIdRef: modelData.id
|
||||||
|
readonly property var liveInstanceData: {
|
||||||
|
const instances = root.allInstances;
|
||||||
|
return instances.find(inst => inst.id === instanceIdRef) ?? modelData;
|
||||||
|
}
|
||||||
|
|
||||||
|
width: groupSection.width - Theme.spacingM
|
||||||
|
height: groupCard.height
|
||||||
|
z: held ? 2 : 1
|
||||||
|
|
||||||
|
DesktopWidgetInstanceCard {
|
||||||
|
id: groupCard
|
||||||
|
width: parent.width
|
||||||
|
headerLeftPadding: 20
|
||||||
|
instanceData: groupDelegateItem.liveInstanceData
|
||||||
|
isExpanded: root.expandedStates[groupDelegateItem.instanceIdRef] ?? false
|
||||||
|
|
||||||
|
onExpandedChanged: {
|
||||||
|
if (expanded === (root.expandedStates[groupDelegateItem.instanceIdRef] ?? false))
|
||||||
|
return;
|
||||||
|
var states = Object.assign({}, root.expandedStates);
|
||||||
|
states[groupDelegateItem.instanceIdRef] = expanded;
|
||||||
|
root.expandedStates = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(groupDelegateItem.instanceIdRef)
|
||||||
|
|
||||||
|
onDeleteRequested: {
|
||||||
|
SettingsData.removeDesktopWidgetInstance(groupDelegateItem.instanceIdRef);
|
||||||
|
ToastService.showInfo(I18n.tr("Widget removed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: groupDragArea
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 40
|
||||||
|
height: 50
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.SizeVerCursor
|
||||||
|
drag.target: groupDelegateItem.held ? groupDelegateItem : undefined
|
||||||
|
drag.axis: Drag.YAxis
|
||||||
|
preventStealing: true
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
groupDelegateItem.z = 2;
|
||||||
|
groupDelegateItem.originalY = groupDelegateItem.y;
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
groupDelegateItem.z = 1;
|
||||||
|
if (!drag.active) {
|
||||||
|
groupDelegateItem.y = groupDelegateItem.originalY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const spacing = Theme.spacingM;
|
||||||
|
const itemH = groupDelegateItem.height + spacing;
|
||||||
|
var newIndex = Math.round(groupDelegateItem.y / itemH);
|
||||||
|
newIndex = Math.max(0, Math.min(newIndex, groupSection.groupInstances.length - 1));
|
||||||
|
if (newIndex !== groupDelegateItem.index)
|
||||||
|
SettingsData.reorderDesktopWidgetInstanceInGroup(groupDelegateItem.instanceIdRef, groupSection.groupId, newIndex);
|
||||||
|
groupDelegateItem.y = groupDelegateItem.originalY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
x: Theme.spacingL - 2
|
||||||
|
y: Theme.spacingL + (Theme.iconSize / 2) - (size / 2)
|
||||||
|
name: "drag_indicator"
|
||||||
|
size: 18
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: groupDragArea.containsMouse || groupDragArea.pressed ? 1 : 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on y {
|
||||||
|
enabled: !groupDragArea.pressed && !groupDragArea.drag.active
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: instancesColumn
|
id: ungroupedSection
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
visible: SettingsData.desktopWidgetInstances.length > 0
|
visible: ungroupedInstances.length > 0
|
||||||
|
|
||||||
Repeater {
|
readonly property var ungroupedInstances: root.allInstances.filter(inst => {
|
||||||
id: instanceRepeater
|
if (!inst.group)
|
||||||
model: ScriptModel {
|
return true;
|
||||||
id: instancesModel
|
return !root.allGroups.some(g => g.id === inst.group);
|
||||||
objectProp: "id"
|
})
|
||||||
values: SettingsData.desktopWidgetInstances
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 44
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
visible: root.allGroups.length > 0
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: (root.groupCollapsedStates["_ungrouped"] ?? false) ? "expand_more" : "expand_less"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "widgets"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Ungrouped")
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "(" + ungroupedSection.ungroupedInstances.length + ")"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopWidgetInstanceCard {
|
MouseArea {
|
||||||
required property var modelData
|
anchors.fill: parent
|
||||||
required property int index
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
var states = Object.assign({}, root.groupCollapsedStates);
|
||||||
|
states["_ungrouped"] = !(states["_ungrouped"] ?? false);
|
||||||
|
root.groupCollapsedStates = states;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
readonly property string instanceIdRef: modelData.id
|
Column {
|
||||||
readonly property var liveInstanceData: {
|
width: parent.width
|
||||||
const instances = SettingsData.desktopWidgetInstances || [];
|
spacing: Theme.spacingM
|
||||||
return instances.find(inst => inst.id === instanceIdRef) ?? modelData;
|
visible: !(root.groupCollapsedStates["_ungrouped"] ?? false)
|
||||||
|
leftPadding: root.allGroups.length > 0 ? Theme.spacingM : 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ScriptModel {
|
||||||
|
objectProp: "id"
|
||||||
|
values: ungroupedSection.ungroupedInstances
|
||||||
}
|
}
|
||||||
|
|
||||||
width: instancesColumn.width
|
Item {
|
||||||
instanceData: liveInstanceData
|
id: ungroupedDelegateItem
|
||||||
isExpanded: root.expandedStates[instanceIdRef] ?? false
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
onExpandedChanged: {
|
property bool held: ungroupedDragArea.pressed
|
||||||
if (expanded === (root.expandedStates[instanceIdRef] ?? false))
|
property real originalY: y
|
||||||
return;
|
|
||||||
var states = Object.assign({}, root.expandedStates);
|
|
||||||
states[instanceIdRef] = expanded;
|
|
||||||
root.expandedStates = states;
|
|
||||||
}
|
|
||||||
|
|
||||||
onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(instanceIdRef)
|
readonly property string instanceIdRef: modelData.id
|
||||||
|
readonly property var liveInstanceData: {
|
||||||
|
const instances = root.allInstances;
|
||||||
|
return instances.find(inst => inst.id === instanceIdRef) ?? modelData;
|
||||||
|
}
|
||||||
|
|
||||||
onDeleteRequested: {
|
width: ungroupedSection.width - (root.allGroups.length > 0 ? Theme.spacingM : 0)
|
||||||
SettingsData.removeDesktopWidgetInstance(instanceIdRef);
|
height: ungroupedCard.height
|
||||||
ToastService.showInfo(I18n.tr("Widget removed"));
|
z: held ? 2 : 1
|
||||||
|
|
||||||
|
DesktopWidgetInstanceCard {
|
||||||
|
id: ungroupedCard
|
||||||
|
width: parent.width
|
||||||
|
headerLeftPadding: 20
|
||||||
|
instanceData: ungroupedDelegateItem.liveInstanceData
|
||||||
|
isExpanded: root.expandedStates[ungroupedDelegateItem.instanceIdRef] ?? false
|
||||||
|
|
||||||
|
onExpandedChanged: {
|
||||||
|
if (expanded === (root.expandedStates[ungroupedDelegateItem.instanceIdRef] ?? false))
|
||||||
|
return;
|
||||||
|
var states = Object.assign({}, root.expandedStates);
|
||||||
|
states[ungroupedDelegateItem.instanceIdRef] = expanded;
|
||||||
|
root.expandedStates = states;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDuplicateRequested: SettingsData.duplicateDesktopWidgetInstance(ungroupedDelegateItem.instanceIdRef)
|
||||||
|
|
||||||
|
onDeleteRequested: {
|
||||||
|
SettingsData.removeDesktopWidgetInstance(ungroupedDelegateItem.instanceIdRef);
|
||||||
|
ToastService.showInfo(I18n.tr("Widget removed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: ungroupedDragArea
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
width: 40
|
||||||
|
height: 50
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.SizeVerCursor
|
||||||
|
drag.target: ungroupedDelegateItem.held ? ungroupedDelegateItem : undefined
|
||||||
|
drag.axis: Drag.YAxis
|
||||||
|
preventStealing: true
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
ungroupedDelegateItem.z = 2;
|
||||||
|
ungroupedDelegateItem.originalY = ungroupedDelegateItem.y;
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
ungroupedDelegateItem.z = 1;
|
||||||
|
if (!drag.active) {
|
||||||
|
ungroupedDelegateItem.y = ungroupedDelegateItem.originalY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const spacing = Theme.spacingM;
|
||||||
|
const itemH = ungroupedDelegateItem.height + spacing;
|
||||||
|
var newIndex = Math.round(ungroupedDelegateItem.y / itemH);
|
||||||
|
newIndex = Math.max(0, Math.min(newIndex, ungroupedSection.ungroupedInstances.length - 1));
|
||||||
|
if (newIndex !== ungroupedDelegateItem.index)
|
||||||
|
SettingsData.reorderDesktopWidgetInstanceInGroup(ungroupedDelegateItem.instanceIdRef, null, newIndex);
|
||||||
|
ungroupedDelegateItem.y = ungroupedDelegateItem.originalY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
x: Theme.spacingL - 2
|
||||||
|
y: Theme.spacingL + (Theme.iconSize / 2) - (size / 2)
|
||||||
|
name: "drag_indicator"
|
||||||
|
size: 18
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: ungroupedDragArea.containsMouse || ungroupedDragArea.pressed ? 1 : 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on y {
|
||||||
|
enabled: !ungroupedDragArea.pressed && !ungroupedDragArea.drag.active
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
visible: SettingsData.desktopWidgetInstances.length === 0
|
visible: root.allInstances.length === 0
|
||||||
text: I18n.tr("No widgets added. Click \"Add Widget\" to get started.")
|
text: I18n.tr("No widgets added. Click \"Add Widget\" to get started.")
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
@@ -147,6 +619,7 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -188,6 +661,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ Item {
|
|||||||
SettingsButtonGroupRow {
|
SettingsButtonGroupRow {
|
||||||
text: I18n.tr("Position")
|
text: I18n.tr("Position")
|
||||||
model: ["Top", "Bottom", "Left", "Right"]
|
model: ["Top", "Bottom", "Left", "Right"]
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
minButtonWidth: 44
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
currentIndex: {
|
currentIndex: {
|
||||||
switch (SettingsData.dockPosition) {
|
switch (SettingsData.dockPosition) {
|
||||||
case SettingsData.Position.Top:
|
case SettingsData.Position.Top:
|
||||||
@@ -129,6 +132,9 @@ Item {
|
|||||||
tags: ["dock", "indicator", "style", "circle", "line"]
|
tags: ["dock", "indicator", "style", "circle", "line"]
|
||||||
text: I18n.tr("Indicator Style")
|
text: I18n.tr("Indicator Style")
|
||||||
model: ["Circle", "Line"]
|
model: ["Circle", "Line"]
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
minButtonWidth: 44
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1
|
currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1
|
||||||
onSelectionChanged: (index, selected) => {
|
onSelectionChanged: (index, selected) => {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
@@ -225,6 +231,9 @@ Item {
|
|||||||
description: I18n.tr("Choose the border accent color")
|
description: I18n.tr("Choose the border accent color")
|
||||||
visible: SettingsData.dockBorderEnabled
|
visible: SettingsData.dockBorderEnabled
|
||||||
model: ["Surface", "Secondary", "Primary"]
|
model: ["Surface", "Secondary", "Primary"]
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
minButtonWidth: 44
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
currentIndex: {
|
currentIndex: {
|
||||||
switch (SettingsData.dockBorderColor) {
|
switch (SettingsData.dockBorderColor) {
|
||||||
case "surfaceText":
|
case "surfaceText":
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Modals.FileBrowser
|
import qs.Modals.FileBrowser
|
||||||
@@ -14,6 +15,7 @@ Item {
|
|||||||
property string expandedVpnUuid: ""
|
property string expandedVpnUuid: ""
|
||||||
property string expandedWifiSsid: ""
|
property string expandedWifiSsid: ""
|
||||||
property string expandedEthDevice: ""
|
property string expandedEthDevice: ""
|
||||||
|
property int maxPinnedWifiNetworks: 3
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
NetworkService.addRef();
|
NetworkService.addRef();
|
||||||
@@ -23,15 +25,59 @@ Item {
|
|||||||
NetworkService.removeRef();
|
NetworkService.removeRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserModal {
|
function openVpnFileBrowser() {
|
||||||
id: vpnFileBrowser
|
vpnFileBrowserLoader.active = true;
|
||||||
browserTitle: I18n.tr("Import VPN")
|
if (vpnFileBrowserLoader.item)
|
||||||
browserIcon: "vpn_key"
|
vpnFileBrowserLoader.item.open();
|
||||||
browserType: "vpn"
|
}
|
||||||
fileExtensions: VPNService.getFileFilter()
|
|
||||||
|
|
||||||
onFileSelected: path => {
|
function normalizePinList(value) {
|
||||||
VPNService.importVpn(path.replace("file://", ""));
|
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
|
||||||
|
|
||||||
|
FileBrowserModal {
|
||||||
|
browserTitle: I18n.tr("Import VPN")
|
||||||
|
browserIcon: "vpn_key"
|
||||||
|
browserType: "vpn"
|
||||||
|
fileExtensions: VPNService.getFileFilter()
|
||||||
|
|
||||||
|
onFileSelected: path => {
|
||||||
|
VPNService.importVpn(path.replace("file://", ""));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,15 +1060,19 @@ Item {
|
|||||||
model: {
|
model: {
|
||||||
const ssid = NetworkService.currentWifiSSID;
|
const ssid = NetworkService.currentWifiSSID;
|
||||||
const networks = NetworkService.wifiNetworks || [];
|
const networks = NetworkService.wifiNetworks || [];
|
||||||
const pins = SettingsData.wifiNetworkPins || {};
|
const pinnedList = networkTab.getPinnedWifiNetworks();
|
||||||
const pinnedSSID = pins["preferredWifi"];
|
|
||||||
|
|
||||||
let sorted = [...networks];
|
let sorted = [...networks];
|
||||||
sorted.sort((a, b) => {
|
sorted.sort((a, b) => {
|
||||||
if (a.ssid === pinnedSSID && b.ssid !== pinnedSSID)
|
const aPinnedIndex = pinnedList.indexOf(a.ssid)
|
||||||
return -1;
|
const bPinnedIndex = pinnedList.indexOf(b.ssid)
|
||||||
if (b.ssid === pinnedSSID && a.ssid !== pinnedSSID)
|
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
|
||||||
return 1;
|
if (aPinnedIndex === -1)
|
||||||
|
return 1
|
||||||
|
if (bPinnedIndex === -1)
|
||||||
|
return -1
|
||||||
|
return aPinnedIndex - bPinnedIndex
|
||||||
|
}
|
||||||
if (a.ssid === ssid)
|
if (a.ssid === ssid)
|
||||||
return -1;
|
return -1;
|
||||||
if (b.ssid === ssid)
|
if (b.ssid === ssid)
|
||||||
@@ -1038,7 +1088,7 @@ Item {
|
|||||||
required property int index
|
required property int index
|
||||||
|
|
||||||
readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID
|
readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID
|
||||||
readonly property bool isPinned: (SettingsData.wifiNetworkPins || {})["preferredWifi"] === modelData.ssid
|
readonly property bool isPinned: networkTab.getPinnedWifiNetworks().includes(modelData.ssid)
|
||||||
readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid
|
readonly property bool isExpanded: networkTab.expandedWifiSsid === modelData.ssid
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -1213,13 +1263,7 @@ Item {
|
|||||||
buttonSize: 28
|
buttonSize: 28
|
||||||
iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText
|
iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
|
networkTab.toggleWifiPin(modelData.ssid)
|
||||||
if (isPinned) {
|
|
||||||
delete pins["preferredWifi"];
|
|
||||||
} else {
|
|
||||||
pins["preferredWifi"] = modelData.ssid;
|
|
||||||
}
|
|
||||||
SettingsData.set("wifiNetworkPins", pins);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1520,7 +1564,7 @@ Item {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor
|
cursorShape: VPNService.importing ? Qt.BusyCursor : Qt.PointingHandCursor
|
||||||
enabled: !VPNService.importing
|
enabled: !VPNService.importing
|
||||||
onClicked: vpnFileBrowser.open()
|
onClicked: networkTab.openVpnFileBrowser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -144,6 +144,15 @@ Item {
|
|||||||
checked: SettingsData.notificationOverlayEnabled
|
checked: SettingsData.notificationOverlayEnabled
|
||||||
onToggled: checked => SettingsData.set("notificationOverlayEnabled", checked)
|
onToggled: checked => SettingsData.set("notificationOverlayEnabled", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
settingKey: "notificationCompactMode"
|
||||||
|
tags: ["notification", "compact", "size", "display", "mode"]
|
||||||
|
text: I18n.tr("Compact")
|
||||||
|
description: I18n.tr("Use smaller notification cards")
|
||||||
|
checked: SettingsData.notificationCompactMode
|
||||||
|
onToggled: checked => SettingsData.set("notificationCompactMode", checked)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
|
|||||||
@@ -270,7 +270,9 @@ FloatingWindow {
|
|||||||
root.updateFilteredPlugins();
|
root.updateFilteredPlugins();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
thirdPartyConfirmModal.visible = true;
|
thirdPartyConfirmLoader.active = true;
|
||||||
|
if (thirdPartyConfirmLoader.item)
|
||||||
|
thirdPartyConfirmLoader.item.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,119 +670,132 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingWindow {
|
LazyLoader {
|
||||||
id: thirdPartyConfirmModal
|
id: thirdPartyConfirmLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
objectName: "thirdPartyConfirm"
|
FloatingWindow {
|
||||||
title: I18n.tr("Third-Party Plugin Warning")
|
id: thirdPartyConfirmModal
|
||||||
implicitWidth: 500
|
|
||||||
implicitHeight: 350
|
|
||||||
color: Theme.surfaceContainer
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
FocusScope {
|
function show() {
|
||||||
anchors.fill: parent
|
visible = true;
|
||||||
focus: true
|
|
||||||
|
|
||||||
Keys.onPressed: event => {
|
|
||||||
if (event.key === Qt.Key_Escape) {
|
|
||||||
thirdPartyConfirmModal.visible = false;
|
|
||||||
event.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
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
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingL
|
focus: true
|
||||||
spacing: Theme.spacingL
|
|
||||||
|
|
||||||
Row {
|
Keys.onPressed: event => {
|
||||||
width: parent.width
|
if (event.key === Qt.Key_Escape) {
|
||||||
spacing: Theme.spacingM
|
thirdPartyConfirmModal.hide();
|
||||||
|
event.accepted = true;
|
||||||
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.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: parent.width
|
anchors.fill: parent
|
||||||
spacing: Theme.spacingS
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
StyledText {
|
Row {
|
||||||
text: I18n.tr("• Plugins may contain bugs or security issues")
|
width: parent.width
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
spacing: Theme.spacingM
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("• Review code before installation when possible")
|
width: parent.width
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
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.")
|
||||||
color: Theme.surfaceVariantText
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
Column {
|
||||||
text: I18n.tr("• Install only from trusted sources")
|
width: parent.width
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
spacing: Theme.spacingS
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
StyledText {
|
||||||
width: parent.width
|
text: I18n.tr("• Plugins may contain bugs or security issues")
|
||||||
height: parent.height - parent.spacing * 3 - y
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
}
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
StyledText {
|
||||||
anchors.right: parent.right
|
text: I18n.tr("• Review code before installation when possible")
|
||||||
spacing: Theme.spacingM
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
DankButton {
|
StyledText {
|
||||||
text: I18n.tr("Cancel")
|
text: I18n.tr("• Install only from trusted sources")
|
||||||
iconName: "close"
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
onClicked: thirdPartyConfirmModal.visible = false
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankButton {
|
Item {
|
||||||
text: I18n.tr("I Understand")
|
width: parent.width
|
||||||
iconName: "check"
|
height: parent.height - parent.spacing * 3 - y
|
||||||
onClicked: {
|
}
|
||||||
SessionData.setShowThirdPartyPlugins(true);
|
|
||||||
root.updateFilteredPlugins();
|
Row {
|
||||||
thirdPartyConfirmModal.visible = false;
|
anchors.right: parent.right
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Cancel")
|
||||||
|
iconName: "close"
|
||||||
|
onClicked: thirdPartyConfirmModal.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("I Understand")
|
||||||
|
iconName: "check"
|
||||||
|
onClicked: {
|
||||||
|
SessionData.setShowThirdPartyPlugins(true);
|
||||||
|
root.updateFilteredPlugins();
|
||||||
|
thirdPartyConfirmModal.hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -209,7 +210,7 @@ FocusScope {
|
|||||||
iconName: "store"
|
iconName: "store"
|
||||||
enabled: DMSService.dmsAvailable
|
enabled: DMSService.dmsAvailable
|
||||||
onClicked: {
|
onClicked: {
|
||||||
pluginBrowser.show();
|
showPluginBrowser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,9 +383,11 @@ FocusScope {
|
|||||||
Connections {
|
Connections {
|
||||||
target: DMSService
|
target: DMSService
|
||||||
function onPluginsListReceived(plugins) {
|
function onPluginsListReceived(plugins) {
|
||||||
pluginBrowser.isLoading = false;
|
if (!pluginBrowserLoader.item)
|
||||||
pluginBrowser.allPlugins = plugins;
|
return;
|
||||||
pluginBrowser.updateFilteredPlugins();
|
pluginBrowserLoader.item.isLoading = false;
|
||||||
|
pluginBrowserLoader.item.allPlugins = plugins;
|
||||||
|
pluginBrowserLoader.item.updateFilteredPlugins();
|
||||||
}
|
}
|
||||||
function onInstalledPluginsReceived(plugins) {
|
function onInstalledPluginsReceived(plugins) {
|
||||||
var pluginMap = {};
|
var pluginMap = {};
|
||||||
@@ -410,22 +413,36 @@ FocusScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
pluginBrowser.parentModal = pluginsTab.parentModal;
|
|
||||||
if (DMSService.dmsAvailable && DMSService.apiVersion >= 8)
|
if (DMSService.dmsAvailable && DMSService.apiVersion >= 8)
|
||||||
DMSService.listInstalled();
|
DMSService.listInstalled();
|
||||||
if (PopoutService.pendingPluginInstall)
|
if (PopoutService.pendingPluginInstall)
|
||||||
Qt.callLater(() => pluginBrowser.show());
|
Qt.callLater(showPluginBrowser);
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: PopoutService
|
target: PopoutService
|
||||||
function onPendingPluginInstallChanged() {
|
function onPendingPluginInstallChanged() {
|
||||||
if (PopoutService.pendingPluginInstall)
|
if (PopoutService.pendingPluginInstall)
|
||||||
pluginBrowser.show();
|
showPluginBrowser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginBrowser {
|
LazyLoader {
|
||||||
id: pluginBrowser
|
id: pluginBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
|
PluginBrowser {
|
||||||
|
id: pluginBrowserItem
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
pluginBrowserItem.parentModal = pluginsTab.parentModal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPluginBrowser() {
|
||||||
|
pluginBrowserLoader.active = true;
|
||||||
|
if (pluginBrowserLoader.item)
|
||||||
|
pluginBrowserLoader.item.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,159 @@ Item {
|
|||||||
onToggled: checked => SettingsData.set("runningAppsCurrentWorkspace", checked)
|
onToggled: checked => SettingsData.set("runningAppsCurrentWorkspace", checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
width: parent.width
|
||||||
|
iconName: "find_replace"
|
||||||
|
title: I18n.tr("App ID Substitutions")
|
||||||
|
settingKey: "appIdSubstitutions"
|
||||||
|
tags: ["app", "icon", "substitution", "replacement", "pattern", "window", "class", "regex"]
|
||||||
|
|
||||||
|
headerActions: [
|
||||||
|
DankActionButton {
|
||||||
|
buttonSize: 36
|
||||||
|
iconName: "restart_alt"
|
||||||
|
iconSize: 20
|
||||||
|
visible: JSON.stringify(SettingsData.appIdSubstitutions) !== JSON.stringify(SettingsData.getDefaultAppIdSubstitutions())
|
||||||
|
backgroundColor: Theme.surfaceContainer
|
||||||
|
iconColor: Theme.surfaceVariantText
|
||||||
|
onClicked: SettingsData.resetAppIdSubstitutions()
|
||||||
|
},
|
||||||
|
DankActionButton {
|
||||||
|
buttonSize: 36
|
||||||
|
iconName: "add"
|
||||||
|
iconSize: 20
|
||||||
|
backgroundColor: Theme.surfaceContainer
|
||||||
|
iconColor: Theme.primary
|
||||||
|
onClicked: SettingsData.addAppIdSubstitution("", "", "exact")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Map window class names to icon names for proper icon display")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: parent.width
|
||||||
|
bottomPadding: Theme.spacingS
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SettingsData.appIdSubstitutions
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: subItem
|
||||||
|
width: parent.width
|
||||||
|
height: subColumn.implicitHeight + Theme.spacingM
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainer, 0.5)
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: subColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: (parent.width - deleteBtn.width - Theme.spacingS) / 2
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Pattern")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall - 1
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: patternField
|
||||||
|
width: parent.width
|
||||||
|
text: modelData.pattern
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
onEditingFinished: SettingsData.updateAppIdSubstitution(index, text, replacementField.text, modelData.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: (parent.width - deleteBtn.width - Theme.spacingS) / 2
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Replacement")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall - 1
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: replacementField
|
||||||
|
width: parent.width
|
||||||
|
text: modelData.replacement
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
onEditingFinished: SettingsData.updateAppIdSubstitution(index, patternField.text, text, modelData.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: deleteBtn
|
||||||
|
width: 32
|
||||||
|
height: 40
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: deleteArea.containsMouse ? Theme.withAlpha(Theme.error, 0.2) : "transparent"
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "delete"
|
||||||
|
size: 18
|
||||||
|
color: deleteArea.containsMouse ? Theme.error : Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: deleteArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: SettingsData.removeAppIdSubstitution(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: 120
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Type")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall - 1
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
DankDropdown {
|
||||||
|
width: parent.width
|
||||||
|
compactMode: true
|
||||||
|
dropdownWidth: 120
|
||||||
|
currentValue: modelData.type
|
||||||
|
options: ["exact", "contains", "regex"]
|
||||||
|
onValueChanged: value => SettingsData.updateAppIdSubstitution(index, modelData.pattern, modelData.replacement, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ Item {
|
|||||||
if (DMSService.dmsAvailable)
|
if (DMSService.dmsAvailable)
|
||||||
DMSService.listInstalledThemes();
|
DMSService.listInstalledThemes();
|
||||||
if (PopoutService.pendingThemeInstall)
|
if (PopoutService.pendingThemeInstall)
|
||||||
Qt.callLater(() => themeBrowser.show());
|
Qt.callLater(() => showThemeBrowser());
|
||||||
templateCheckProcess.running = true;
|
templateCheckProcess.running = true;
|
||||||
if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl)
|
if (CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl)
|
||||||
checkCursorIncludeStatus();
|
checkCursorIncludeStatus();
|
||||||
@@ -169,7 +169,7 @@ Item {
|
|||||||
target: PopoutService
|
target: PopoutService
|
||||||
function onPendingThemeInstallChanged() {
|
function onPendingThemeInstallChanged() {
|
||||||
if (PopoutService.pendingThemeInstall)
|
if (PopoutService.pendingThemeInstall)
|
||||||
themeBrowser.show();
|
showThemeBrowser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +307,7 @@ Item {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: genericColorGrid.implicitHeight
|
height: genericColorGrid.implicitHeight + Math.ceil(genericColorGrid.dotSize * 0.05)
|
||||||
visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||||
|
|
||||||
Grid {
|
Grid {
|
||||||
@@ -939,7 +939,7 @@ Item {
|
|||||||
text: I18n.tr("Browse Themes", "browse themes button")
|
text: I18n.tr("Browse Themes", "browse themes button")
|
||||||
iconName: "store"
|
iconName: "store"
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
onClicked: themeBrowser.show()
|
onClicked: showThemeBrowser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2041,7 +2041,18 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeBrowser {
|
LazyLoader {
|
||||||
id: themeBrowser
|
id: themeBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
|
ThemeBrowser {
|
||||||
|
id: themeBrowserItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showThemeBrowser() {
|
||||||
|
themeBrowserLoader.active = true;
|
||||||
|
if (themeBrowserLoader.item)
|
||||||
|
themeBrowserLoader.item.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: mainWallpaperBrowser.open()
|
onClicked: root.openMainWallpaperBrowser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +476,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: lightWallpaperBrowser.open()
|
onClicked: root.openLightWallpaperBrowser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,7 +660,7 @@ Item {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: darkWallpaperBrowser.open()
|
onClicked: root.openDarkWallpaperBrowser()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1242,53 +1242,83 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserModal {
|
function openMainWallpaperBrowser() {
|
||||||
id: mainWallpaperBrowser
|
mainWallpaperBrowserLoader.active = true;
|
||||||
parentModal: root.parentModal
|
if (mainWallpaperBrowserLoader.item)
|
||||||
browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title")
|
mainWallpaperBrowserLoader.item.open();
|
||||||
browserIcon: "wallpaper"
|
}
|
||||||
browserType: "wallpaper"
|
|
||||||
showHiddenFiles: true
|
function openLightWallpaperBrowser() {
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
lightWallpaperBrowserLoader.active = true;
|
||||||
onFileSelected: path => {
|
if (lightWallpaperBrowserLoader.item)
|
||||||
if (SessionData.perMonitorWallpaper) {
|
lightWallpaperBrowserLoader.item.open();
|
||||||
SessionData.setMonitorWallpaper(selectedMonitorName, path);
|
}
|
||||||
} else {
|
|
||||||
SessionData.setWallpaper(path);
|
function openDarkWallpaperBrowser() {
|
||||||
|
darkWallpaperBrowserLoader.active = true;
|
||||||
|
if (darkWallpaperBrowserLoader.item)
|
||||||
|
darkWallpaperBrowserLoader.item.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: mainWallpaperBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
|
FileBrowserModal {
|
||||||
|
parentModal: root.parentModal
|
||||||
|
browserTitle: I18n.tr("Select Wallpaper", "wallpaper file browser title")
|
||||||
|
browserIcon: "wallpaper"
|
||||||
|
browserType: "wallpaper"
|
||||||
|
showHiddenFiles: true
|
||||||
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
|
onFileSelected: path => {
|
||||||
|
if (SessionData.perMonitorWallpaper) {
|
||||||
|
SessionData.setMonitorWallpaper(selectedMonitorName, path);
|
||||||
|
} else {
|
||||||
|
SessionData.setWallpaper(path);
|
||||||
|
}
|
||||||
|
close();
|
||||||
}
|
}
|
||||||
close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserModal {
|
LazyLoader {
|
||||||
id: lightWallpaperBrowser
|
id: lightWallpaperBrowserLoader
|
||||||
parentModal: root.parentModal
|
active: false
|
||||||
browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title")
|
|
||||||
browserIcon: "light_mode"
|
FileBrowserModal {
|
||||||
browserType: "wallpaper"
|
parentModal: root.parentModal
|
||||||
showHiddenFiles: true
|
browserTitle: I18n.tr("Select Wallpaper", "light mode wallpaper file browser title")
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
browserIcon: "light_mode"
|
||||||
onFileSelected: path => {
|
browserType: "wallpaper"
|
||||||
SessionData.wallpaperPathLight = path;
|
showHiddenFiles: true
|
||||||
SessionData.syncWallpaperForCurrentMode();
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
SessionData.saveSettings();
|
onFileSelected: path => {
|
||||||
close();
|
SessionData.wallpaperPathLight = path;
|
||||||
|
SessionData.syncWallpaperForCurrentMode();
|
||||||
|
SessionData.saveSettings();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowserModal {
|
LazyLoader {
|
||||||
id: darkWallpaperBrowser
|
id: darkWallpaperBrowserLoader
|
||||||
parentModal: root.parentModal
|
active: false
|
||||||
browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title")
|
|
||||||
browserIcon: "dark_mode"
|
FileBrowserModal {
|
||||||
browserType: "wallpaper"
|
parentModal: root.parentModal
|
||||||
showHiddenFiles: true
|
browserTitle: I18n.tr("Select Wallpaper", "dark mode wallpaper file browser title")
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
browserIcon: "dark_mode"
|
||||||
onFileSelected: path => {
|
browserType: "wallpaper"
|
||||||
SessionData.wallpaperPathDark = path;
|
showHiddenFiles: true
|
||||||
SessionData.syncWallpaperForCurrentMode();
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
SessionData.saveSettings();
|
onFileSelected: path => {
|
||||||
close();
|
SessionData.wallpaperPathDark = path;
|
||||||
|
SessionData.syncWallpaperForCurrentMode();
|
||||||
|
SessionData.saveSettings();
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ StyledRect {
|
|||||||
property string iconName: ""
|
property string iconName: ""
|
||||||
property bool collapsible: false
|
property bool collapsible: false
|
||||||
property bool expanded: true
|
property bool expanded: true
|
||||||
|
property real headerLeftPadding: 0
|
||||||
|
|
||||||
default property alias content: contentColumn.children
|
default property alias content: contentColumn.children
|
||||||
property alias headerActions: headerActionsRow.children
|
property alias headerActions: headerActionsRow.children
|
||||||
@@ -115,6 +116,7 @@ StyledRect {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: root.headerLeftPadding
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
@@ -142,7 +144,7 @@ StyledRect {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: headerActionsRow
|
id: headerActionsRow
|
||||||
anchors.right: caretIcon.left
|
anchors.right: root.collapsible ? caretIcon.left : parent.right
|
||||||
anchors.rightMargin: root.collapsible ? Theme.spacingS : 0
|
anchors.rightMargin: root.collapsible ? Theme.spacingS : 0
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
@@ -172,6 +174,7 @@ StyledRect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
visible: root.collapsible
|
||||||
anchors.left: caretIcon.left
|
anchors.left: caretIcon.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ StyledRect {
|
|||||||
|
|
||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
id: headerIcon
|
id: headerIcon
|
||||||
@@ -69,6 +70,8 @@ StyledRect {
|
|||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: root.title !== ""
|
visible: root.title !== ""
|
||||||
|
width: parent.width - (headerIcon.visible ? headerIcon.width + parent.spacing : 0)
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -382,6 +383,7 @@ Item {
|
|||||||
widgetObj.showMicPercent = SettingsData.controlCenterShowMicPercent;
|
widgetObj.showMicPercent = SettingsData.controlCenterShowMicPercent;
|
||||||
widgetObj.showBatteryIcon = SettingsData.controlCenterShowBatteryIcon;
|
widgetObj.showBatteryIcon = SettingsData.controlCenterShowBatteryIcon;
|
||||||
widgetObj.showPrinterIcon = SettingsData.controlCenterShowPrinterIcon;
|
widgetObj.showPrinterIcon = SettingsData.controlCenterShowPrinterIcon;
|
||||||
|
widgetObj.showScreenSharingIcon = SettingsData.controlCenterShowScreenSharingIcon;
|
||||||
}
|
}
|
||||||
if (widgetId === "diskUsage")
|
if (widgetId === "diskUsage")
|
||||||
widgetObj.mountPath = "/";
|
widgetObj.mountPath = "/";
|
||||||
@@ -400,6 +402,24 @@ Item {
|
|||||||
setWidgetsForSection(sectionId, widgets);
|
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) {
|
function handleItemEnabledChanged(sectionId, itemId, enabled) {
|
||||||
var widgets = getWidgetsForSection(sectionId).slice();
|
var widgets = getWidgetsForSection(sectionId).slice();
|
||||||
for (var i = 0; i < widgets.length; i++) {
|
for (var i = 0; i < widgets.length; i++) {
|
||||||
@@ -407,42 +427,8 @@ Item {
|
|||||||
var widgetId = typeof widget === "string" ? widget : widget.id;
|
var widgetId = typeof widget === "string" ? widget : widget.id;
|
||||||
if (widgetId !== itemId)
|
if (widgetId !== itemId)
|
||||||
continue;
|
continue;
|
||||||
|
var newWidget = cloneWidgetData(widget);
|
||||||
if (typeof widget === "string") {
|
newWidget.enabled = enabled;
|
||||||
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;
|
|
||||||
}
|
|
||||||
widgets[i] = newWidget;
|
widgets[i] = newWidget;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -455,128 +441,36 @@ Item {
|
|||||||
|
|
||||||
function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) {
|
function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) {
|
||||||
var widgets = getWidgetsForSection(sectionId).slice();
|
var widgets = getWidgetsForSection(sectionId).slice();
|
||||||
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
|
if (widgetIndex < 0 || widgetIndex >= widgets.length)
|
||||||
setWidgetsForSection(sectionId, widgets);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var widget = widgets[widgetIndex];
|
var widget = widgets[widgetIndex];
|
||||||
var widgetId = typeof widget === "string" ? widget : widget.id;
|
var widgetId = typeof widget === "string" ? widget : widget.id;
|
||||||
if (widgetId !== "spacer") {
|
if (widgetId !== "spacer")
|
||||||
setWidgetsForSection(sectionId, widgets);
|
|
||||||
return;
|
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;
|
|
||||||
}
|
|
||||||
widgets[widgetIndex] = newWidget;
|
widgets[widgetIndex] = newWidget;
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
|
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
|
||||||
var widgets = getWidgetsForSection(sectionId).slice();
|
var widgets = getWidgetsForSection(sectionId).slice();
|
||||||
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
|
if (widgetIndex < 0 || widgetIndex >= widgets.length)
|
||||||
setWidgetsForSection(sectionId, widgets);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
var pciId = DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : "";
|
var pciId = DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : "";
|
||||||
var widget = widgets[widgetIndex];
|
var newWidget = cloneWidgetData(widgets[widgetIndex]);
|
||||||
if (typeof widget === "string") {
|
newWidget.selectedGpuIndex = selectedGpuIndex;
|
||||||
widgets[widgetIndex] = {
|
newWidget.pciId = pciId;
|
||||||
"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;
|
widgets[widgetIndex] = newWidget;
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
|
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
|
||||||
var widgets = getWidgetsForSection(sectionId).slice();
|
var widgets = getWidgetsForSection(sectionId).slice();
|
||||||
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
|
if (widgetIndex < 0 || widgetIndex >= widgets.length)
|
||||||
setWidgetsForSection(sectionId, widgets);
|
|
||||||
return;
|
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;
|
|
||||||
}
|
|
||||||
widgets[widgetIndex] = newWidget;
|
widgets[widgetIndex] = newWidget;
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
@@ -585,32 +479,8 @@ Item {
|
|||||||
var widgets = getWidgetsForSection(sectionId).slice();
|
var widgets = getWidgetsForSection(sectionId).slice();
|
||||||
if (widgetIndex < 0 || widgetIndex >= widgets.length)
|
if (widgetIndex < 0 || widgetIndex >= widgets.length)
|
||||||
return;
|
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
|
|
||||||
};
|
|
||||||
newWidget[settingName] = value;
|
newWidget[settingName] = value;
|
||||||
|
|
||||||
widgets[widgetIndex] = newWidget;
|
widgets[widgetIndex] = newWidget;
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
@@ -635,46 +505,8 @@ Item {
|
|||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var newWidget = cloneWidgetData(widgets[widgetIndex]);
|
||||||
var widget = widgets[widgetIndex];
|
newWidget.minimumWidth = enabled;
|
||||||
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;
|
|
||||||
}
|
|
||||||
widgets[widgetIndex] = newWidget;
|
widgets[widgetIndex] = newWidget;
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
@@ -685,141 +517,41 @@ Item {
|
|||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var newWidget = cloneWidgetData(widgets[widgetIndex]);
|
||||||
var widget = widgets[widgetIndex];
|
newWidget.showSwap = enabled;
|
||||||
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;
|
|
||||||
}
|
|
||||||
widgets[widgetIndex] = newWidget;
|
widgets[widgetIndex] = newWidget;
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCompactModeChanged(sectionId, widgetId, value) {
|
function handleCompactModeChanged(sectionId, widgetId, value) {
|
||||||
var widgets = getWidgetsForSection(sectionId).slice();
|
var widgets = getWidgetsForSection(sectionId).slice();
|
||||||
|
|
||||||
for (var i = 0; i < widgets.length; i++) {
|
for (var i = 0; i < widgets.length; i++) {
|
||||||
var widget = widgets[i];
|
var widget = widgets[i];
|
||||||
var currentId = typeof widget === "string" ? widget : widget.id;
|
var currentId = typeof widget === "string" ? widget : widget.id;
|
||||||
|
|
||||||
if (currentId !== widgetId)
|
if (currentId !== widgetId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (typeof widget === "string") {
|
var newWidget = cloneWidgetData(widget);
|
||||||
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;
|
|
||||||
}
|
|
||||||
widgets[i] = newWidget;
|
|
||||||
widget = newWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (widgetId) {
|
switch (widgetId) {
|
||||||
case "music":
|
case "music":
|
||||||
widget.mediaSize = value;
|
newWidget.mediaSize = value;
|
||||||
break;
|
break;
|
||||||
case "clock":
|
case "clock":
|
||||||
widget.clockCompactMode = value;
|
newWidget.clockCompactMode = value;
|
||||||
break;
|
break;
|
||||||
case "focusedWindow":
|
case "focusedWindow":
|
||||||
widget.focusedWindowCompactMode = value;
|
newWidget.focusedWindowCompactMode = value;
|
||||||
break;
|
break;
|
||||||
case "runningApps":
|
case "runningApps":
|
||||||
widget.runningAppsCompactMode = value;
|
newWidget.runningAppsCompactMode = value;
|
||||||
break;
|
break;
|
||||||
case "keyboard_layout_name":
|
case "keyboard_layout_name":
|
||||||
widget.keyboardLayoutNameCompactMode = value;
|
newWidget.keyboardLayoutNameCompactMode = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
widgets[i] = newWidget;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setWidgetsForSection(sectionId, widgets);
|
setWidgetsForSection(sectionId, widgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,6 +598,8 @@ Item {
|
|||||||
item.showBatteryIcon = widget.showBatteryIcon;
|
item.showBatteryIcon = widget.showBatteryIcon;
|
||||||
if (widget.showPrinterIcon !== undefined)
|
if (widget.showPrinterIcon !== undefined)
|
||||||
item.showPrinterIcon = widget.showPrinterIcon;
|
item.showPrinterIcon = widget.showPrinterIcon;
|
||||||
|
if (widget.showScreenSharingIcon !== undefined)
|
||||||
|
item.showScreenSharingIcon = widget.showScreenSharingIcon;
|
||||||
if (widget.minimumWidth !== undefined)
|
if (widget.minimumWidth !== undefined)
|
||||||
item.minimumWidth = widget.minimumWidth;
|
item.minimumWidth = widget.minimumWidth;
|
||||||
if (widget.showSwap !== undefined)
|
if (widget.showSwap !== undefined)
|
||||||
@@ -916,14 +650,28 @@ Item {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
WidgetSelectionPopup {
|
LazyLoader {
|
||||||
id: widgetSelectionPopup
|
id: widgetSelectionPopupLoader
|
||||||
parentModal: widgetsTab.parentModal
|
active: false
|
||||||
onWidgetSelected: (widgetId, targetSection) => {
|
|
||||||
widgetsTab.addWidgetToSection(widgetId, targetSection);
|
WidgetSelectionPopup {
|
||||||
|
id: widgetSelectionPopupItem
|
||||||
|
parentModal: widgetsTab.parentModal
|
||||||
|
onWidgetSelected: (widgetId, targetSection) => {
|
||||||
|
widgetsTab.addWidgetToSection(widgetId, targetSection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showWidgetSelectionPopup(sectionId) {
|
||||||
|
widgetSelectionPopupLoader.active = true;
|
||||||
|
if (!widgetSelectionPopupLoader.item)
|
||||||
|
return;
|
||||||
|
widgetSelectionPopupLoader.item.targetSection = sectionId;
|
||||||
|
widgetSelectionPopupLoader.item.allWidgets = widgetsTab.getWidgetsForPopup();
|
||||||
|
widgetSelectionPopupLoader.item.show();
|
||||||
|
}
|
||||||
|
|
||||||
DankFlickable {
|
DankFlickable {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
clip: true
|
||||||
@@ -1113,9 +861,7 @@ Item {
|
|||||||
widgetsTab.handleItemOrderChanged(sectionId, newOrder);
|
widgetsTab.handleItemOrderChanged(sectionId, newOrder);
|
||||||
}
|
}
|
||||||
onAddWidget: sectionId => {
|
onAddWidget: sectionId => {
|
||||||
widgetSelectionPopup.targetSection = sectionId;
|
showWidgetSelectionPopup(sectionId);
|
||||||
widgetSelectionPopup.allWidgets = widgetsTab.getWidgetsForPopup();
|
|
||||||
widgetSelectionPopup.show();
|
|
||||||
}
|
}
|
||||||
onRemoveWidget: (sectionId, index) => {
|
onRemoveWidget: (sectionId, index) => {
|
||||||
widgetsTab.removeWidgetFromSection(sectionId, index);
|
widgetsTab.removeWidgetFromSection(sectionId, index);
|
||||||
@@ -1170,9 +916,7 @@ Item {
|
|||||||
widgetsTab.handleItemOrderChanged(sectionId, newOrder);
|
widgetsTab.handleItemOrderChanged(sectionId, newOrder);
|
||||||
}
|
}
|
||||||
onAddWidget: sectionId => {
|
onAddWidget: sectionId => {
|
||||||
widgetSelectionPopup.targetSection = sectionId;
|
showWidgetSelectionPopup(sectionId);
|
||||||
widgetSelectionPopup.allWidgets = widgetsTab.getWidgetsForPopup();
|
|
||||||
widgetSelectionPopup.show();
|
|
||||||
}
|
}
|
||||||
onRemoveWidget: (sectionId, index) => {
|
onRemoveWidget: (sectionId, index) => {
|
||||||
widgetsTab.removeWidgetFromSection(sectionId, index);
|
widgetsTab.removeWidgetFromSection(sectionId, index);
|
||||||
@@ -1227,9 +971,7 @@ Item {
|
|||||||
widgetsTab.handleItemOrderChanged(sectionId, newOrder);
|
widgetsTab.handleItemOrderChanged(sectionId, newOrder);
|
||||||
}
|
}
|
||||||
onAddWidget: sectionId => {
|
onAddWidget: sectionId => {
|
||||||
widgetSelectionPopup.targetSection = sectionId;
|
showWidgetSelectionPopup(sectionId);
|
||||||
widgetSelectionPopup.allWidgets = widgetsTab.getWidgetsForPopup();
|
|
||||||
widgetSelectionPopup.show();
|
|
||||||
}
|
}
|
||||||
onRemoveWidget: (sectionId, index) => {
|
onRemoveWidget: (sectionId, index) => {
|
||||||
widgetsTab.removeWidgetFromSection(sectionId, index);
|
widgetsTab.removeWidgetFromSection(sectionId, index);
|
||||||
|
|||||||
@@ -31,6 +31,19 @@ Column {
|
|||||||
signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled)
|
signal minimumWidthChanged(string sectionId, int widgetIndex, bool enabled)
|
||||||
signal showSwapChanged(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
|
width: parent.width
|
||||||
height: implicitHeight
|
height: implicitHeight
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
@@ -727,13 +740,7 @@ Column {
|
|||||||
var newItems = root.items.slice();
|
var newItems = root.items.slice();
|
||||||
var draggedItem = newItems.splice(index, 1)[0];
|
var draggedItem = newItems.splice(index, 1)[0];
|
||||||
newItems.splice(newIndex, 0, draggedItem);
|
newItems.splice(newIndex, 0, draggedItem);
|
||||||
root.itemOrderChanged(newItems.map(item => {
|
root.itemOrderChanged(newItems.map(item => root.cloneWidgetData(item)));
|
||||||
return ({
|
|
||||||
"id": item.id,
|
|
||||||
"enabled": item.enabled,
|
|
||||||
"size": item.size
|
|
||||||
});
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delegateItem.x = 0;
|
delegateItem.x = 0;
|
||||||
@@ -875,6 +882,11 @@ Column {
|
|||||||
icon: "print",
|
icon: "print",
|
||||||
label: I18n.tr("Printer"),
|
label: I18n.tr("Printer"),
|
||||||
setting: "showPrinterIcon"
|
setting: "showPrinterIcon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "screen_record",
|
||||||
|
label: I18n.tr("Screen Sharing"),
|
||||||
|
setting: "showScreenSharingIcon"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -907,6 +919,8 @@ Column {
|
|||||||
return wd?.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
|
return wd?.showBatteryIcon ?? SettingsData.controlCenterShowBatteryIcon;
|
||||||
case "showPrinterIcon":
|
case "showPrinterIcon":
|
||||||
return wd?.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
|
return wd?.showPrinterIcon ?? SettingsData.controlCenterShowPrinterIcon;
|
||||||
|
case "showScreenSharingIcon":
|
||||||
|
return wd?.showScreenSharingIcon ?? SettingsData.controlCenterShowScreenSharingIcon;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,15 +63,15 @@ Item {
|
|||||||
onToggled: checked => SettingsData.set("showWorkspaceApps", checked)
|
onToggled: checked => SettingsData.set("showWorkspaceApps", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Item {
|
||||||
width: parent.width - Theme.spacingL
|
width: parent.width
|
||||||
spacing: Theme.spacingL
|
height: maxAppsColumn.height
|
||||||
visible: SettingsData.showWorkspaceApps
|
visible: SettingsData.showWorkspaceApps
|
||||||
opacity: visible ? 1 : 0
|
opacity: visible ? 1 : 0
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingL
|
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
id: maxAppsColumn
|
||||||
|
x: Theme.spacingL
|
||||||
width: 120
|
width: 120
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
@@ -80,14 +80,15 @@ Item {
|
|||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
|
horizontalAlignment: Text.AlignLeft
|
||||||
}
|
}
|
||||||
|
|
||||||
DankTextField {
|
DankTextField {
|
||||||
width: 100
|
width: 100
|
||||||
height: 28
|
height: 28
|
||||||
placeholderText: "#ffffff"
|
placeholderText: "3"
|
||||||
text: SettingsData.maxWorkspaceIcons
|
text: SettingsData.maxWorkspaceIcons
|
||||||
maximumLength: 7
|
maximumLength: 2
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
topPadding: Theme.spacingXS
|
topPadding: Theme.spacingXS
|
||||||
bottomPadding: Theme.spacingXS
|
bottomPadding: Theme.spacingXS
|
||||||
@@ -114,12 +115,13 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
settingKey: "workspacesPerMonitor"
|
settingKey: "workspaceFollowFocus"
|
||||||
tags: ["workspace", "per-monitor", "multi-monitor"]
|
tags: ["workspace", "focus", "follow", "monitor"]
|
||||||
text: I18n.tr("Per-Monitor Workspaces")
|
text: I18n.tr("Follow Monitor Focus")
|
||||||
description: I18n.tr("Show only workspaces belonging to each specific monitor.")
|
description: I18n.tr("Show workspaces of the currently focused monitor")
|
||||||
checked: SettingsData.workspacesPerMonitor
|
checked: SettingsData.workspaceFollowFocus
|
||||||
onToggled: checked => SettingsData.set("workspacesPerMonitor", checked)
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
||||||
|
onToggled: checked => SettingsData.set("workspaceFollowFocus", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
@@ -153,6 +155,189 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
width: parent.width
|
||||||
|
iconName: "palette"
|
||||||
|
title: I18n.tr("Workspace Appearance")
|
||||||
|
settingKey: "workspaceAppearance"
|
||||||
|
|
||||||
|
SettingsButtonGroupRow {
|
||||||
|
text: I18n.tr("Focused Color")
|
||||||
|
model: ["pri", "s", "sc", "sch", "none"]
|
||||||
|
buttonHeight: 22
|
||||||
|
minButtonWidth: 36
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
checkIconSize: Theme.iconSizeSmall - 2
|
||||||
|
textSize: Theme.fontSizeSmall - 1
|
||||||
|
spacing: 1
|
||||||
|
currentIndex: {
|
||||||
|
switch (SettingsData.workspaceColorMode) {
|
||||||
|
case "s":
|
||||||
|
return 1;
|
||||||
|
case "sc":
|
||||||
|
return 2;
|
||||||
|
case "sch":
|
||||||
|
return 3;
|
||||||
|
case "none":
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
const modes = ["default", "s", "sc", "sch", "none"];
|
||||||
|
SettingsData.set("workspaceColorMode", modes[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: 0.15
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsButtonGroupRow {
|
||||||
|
text: I18n.tr("Unfocused Color")
|
||||||
|
model: ["def", "s", "sc", "sch"]
|
||||||
|
buttonHeight: 22
|
||||||
|
minButtonWidth: 36
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
checkIconSize: Theme.iconSizeSmall - 2
|
||||||
|
textSize: Theme.fontSizeSmall - 1
|
||||||
|
spacing: 1
|
||||||
|
currentIndex: {
|
||||||
|
switch (SettingsData.workspaceUnfocusedColorMode) {
|
||||||
|
case "s":
|
||||||
|
return 1;
|
||||||
|
case "sc":
|
||||||
|
return 2;
|
||||||
|
case "sch":
|
||||||
|
return 3;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
const modes = ["default", "s", "sc", "sch"];
|
||||||
|
SettingsData.set("workspaceUnfocusedColorMode", modes[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: 0.15
|
||||||
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsButtonGroupRow {
|
||||||
|
text: I18n.tr("Urgent Color")
|
||||||
|
visible: CompositorService.isNiri || CompositorService.isHyprland || CompositorService.isDwl || CompositorService.isSway || CompositorService.isScroll
|
||||||
|
model: ["err", "pri", "sec", "s", "sc"]
|
||||||
|
buttonHeight: 22
|
||||||
|
minButtonWidth: 36
|
||||||
|
buttonPadding: Theme.spacingS
|
||||||
|
checkIconSize: Theme.iconSizeSmall - 2
|
||||||
|
textSize: Theme.fontSizeSmall - 1
|
||||||
|
spacing: 1
|
||||||
|
currentIndex: {
|
||||||
|
switch (SettingsData.workspaceUrgentColorMode) {
|
||||||
|
case "primary":
|
||||||
|
return 1;
|
||||||
|
case "secondary":
|
||||||
|
return 2;
|
||||||
|
case "s":
|
||||||
|
return 3;
|
||||||
|
case "sc":
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
const modes = ["default", "primary", "secondary", "s", "sc"];
|
||||||
|
SettingsData.set("workspaceUrgentColorMode", modes[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: 0.15
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
settingKey: "workspaceFocusedBorderEnabled"
|
||||||
|
tags: ["workspace", "border", "outline", "focused", "ring"]
|
||||||
|
text: I18n.tr("Focused Border")
|
||||||
|
description: I18n.tr("Show an outline ring around the focused workspace indicator")
|
||||||
|
checked: SettingsData.workspaceFocusedBorderEnabled
|
||||||
|
onToggled: checked => SettingsData.set("workspaceFocusedBorderEnabled", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
visible: SettingsData.workspaceFocusedBorderEnabled
|
||||||
|
leftPadding: Theme.spacingM
|
||||||
|
|
||||||
|
SettingsButtonGroupRow {
|
||||||
|
width: parent.width - parent.leftPadding
|
||||||
|
text: I18n.tr("Border Color")
|
||||||
|
model: [I18n.tr("Surface"), I18n.tr("Secondary"), I18n.tr("Primary")]
|
||||||
|
currentIndex: {
|
||||||
|
switch (SettingsData.workspaceFocusedBorderColor) {
|
||||||
|
case "surfaceText":
|
||||||
|
return 0;
|
||||||
|
case "secondary":
|
||||||
|
return 1;
|
||||||
|
case "primary":
|
||||||
|
return 2;
|
||||||
|
default:
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSelectionChanged: (index, selected) => {
|
||||||
|
if (!selected)
|
||||||
|
return;
|
||||||
|
let newColor = "primary";
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
newColor = "surfaceText";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
newColor = "secondary";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
newColor = "primary";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SettingsData.set("workspaceFocusedBorderColor", newColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsSliderRow {
|
||||||
|
width: parent.width - parent.leftPadding
|
||||||
|
text: I18n.tr("Thickness")
|
||||||
|
value: SettingsData.workspaceFocusedBorderThickness
|
||||||
|
minimum: 1
|
||||||
|
maximum: 6
|
||||||
|
unit: "px"
|
||||||
|
defaultValue: 2
|
||||||
|
onSliderValueChanged: newValue => SettingsData.set("workspaceFocusedBorderThickness", newValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "label"
|
iconName: "label"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Scope {
|
|||||||
property bool isClosing: false
|
property bool isClosing: false
|
||||||
property bool releaseKeyboard: false
|
property bool releaseKeyboard: false
|
||||||
readonly property bool spotlightModalOpen: PopoutService.spotlightModal?.spotlightOpen ?? false
|
readonly property bool spotlightModalOpen: PopoutService.spotlightModal?.spotlightOpen ?? false
|
||||||
property bool overlayActive: (NiriService.inOverview && !spotlightModalOpen) || searchActive
|
property bool overlayActive: NiriService.inOverview || searchActive
|
||||||
|
|
||||||
function showSpotlight(screenName) {
|
function showSpotlight(screenName) {
|
||||||
isClosing = false;
|
isClosing = false;
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ Item {
|
|||||||
|
|
||||||
property var iconToWindowRatio: 0.25
|
property var iconToWindowRatio: 0.25
|
||||||
property var iconToWindowRatioCompact: 0.45
|
property var iconToWindowRatioCompact: 0.45
|
||||||
property var entry: DesktopEntries.heuristicLookup(windowData?.class)
|
property var entry: DesktopEntries.heuristicLookup(Paths.moddedAppId(windowData?.class ?? ""))
|
||||||
property var iconPath: Quickshell.iconPath(entry?.icon ?? windowData?.class ?? "application-x-executable", "image-missing")
|
property var iconPath: Paths.getAppIcon(windowData?.class ?? "", entry) || Quickshell.iconPath("application-x-executable", "image-missing")
|
||||||
property bool compactMode: Theme.fontSizeSmall * 4 > targetWindowHeight || Theme.fontSizeSmall * 4 > targetWindowWidth
|
property bool compactMode: Theme.fontSizeSmall * 4 > targetWindowHeight || Theme.fontSizeSmall * 4 > targetWindowWidth
|
||||||
|
|
||||||
x: initX
|
x: initX
|
||||||
|
|||||||
@@ -510,6 +510,16 @@ Singleton {
|
|||||||
objects: Pipewire.nodes.values.filter(node => node.audio && !node.isStream)
|
objects: Pipewire.nodes.values.filter(node => node.audio && !node.isStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Pipewire
|
||||||
|
function onDefaultAudioSinkChanged() {
|
||||||
|
if (soundsAvailable) {
|
||||||
|
Qt.callLater(root.destroySoundPlayers);
|
||||||
|
Qt.callLater(root.createSoundPlayers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setVolume(percentage) {
|
function setVolume(percentage) {
|
||||||
if (!root.sink?.audio) {
|
if (!root.sink?.audio) {
|
||||||
return "No audio sink available";
|
return "No audio sink available";
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property string currentVersion: "1.2"
|
readonly property string currentVersion: "1.2"
|
||||||
readonly property bool changelogEnabled: false
|
readonly property bool changelogEnabled: true
|
||||||
|
|
||||||
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
|
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
|
||||||
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion
|
readonly property string changelogMarkerPath: configDir + "/.changelog-" + currentVersion
|
||||||
@@ -37,7 +37,27 @@ Singleton {
|
|||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (!changelogEnabled)
|
if (!changelogEnabled)
|
||||||
return;
|
return;
|
||||||
changelogCheckProcess.running = true;
|
if (FirstLaunchService.checkComplete)
|
||||||
|
handleFirstLaunchResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFirstLaunchResult() {
|
||||||
|
if (FirstLaunchService.isFirstLaunch) {
|
||||||
|
checkComplete = true;
|
||||||
|
changelogDismissed = true;
|
||||||
|
touchMarkerProcess.running = true;
|
||||||
|
} else {
|
||||||
|
changelogCheckProcess.running = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: FirstLaunchService
|
||||||
|
|
||||||
|
function onCheckCompleteChanged() {
|
||||||
|
if (FirstLaunchService.checkComplete && root.changelogEnabled && !root.checkComplete)
|
||||||
|
root.handleFirstLaunchResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showChangelog() {
|
function showChangelog() {
|
||||||
@@ -66,9 +86,7 @@ Singleton {
|
|||||||
root.changelogDismissed = true;
|
root.changelogDismissed = true;
|
||||||
break;
|
break;
|
||||||
case "show":
|
case "show":
|
||||||
if (typeof FirstLaunchService === "undefined" || !FirstLaunchService.isFirstLaunch) {
|
root.changelogRequested();
|
||||||
root.changelogRequested();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,15 +316,16 @@ Singleton {
|
|||||||
const totalKB = mem.total || 0;
|
const totalKB = mem.total || 0;
|
||||||
const availableKB = mem.available || 0;
|
const availableKB = mem.available || 0;
|
||||||
const freeKB = mem.free || 0;
|
const freeKB = mem.free || 0;
|
||||||
|
const usedKB = mem.used !== undefined ? mem.used : (totalKB - availableKB);
|
||||||
|
|
||||||
totalMemoryMB = totalKB / 1024;
|
totalMemoryMB = totalKB / 1024;
|
||||||
availableMemoryMB = availableKB / 1024;
|
availableMemoryMB = availableKB / 1024;
|
||||||
freeMemoryMB = freeKB / 1024;
|
freeMemoryMB = freeKB / 1024;
|
||||||
usedMemoryMB = totalMemoryMB - availableMemoryMB;
|
usedMemoryMB = usedKB / 1024;
|
||||||
memoryUsage = totalKB > 0 ? ((totalKB - availableKB) / totalKB) * 100 : 0;
|
memoryUsage = mem.usedPercent !== undefined ? mem.usedPercent : (totalKB > 0 ? ((totalKB - availableKB) / totalKB) * 100 : 0);
|
||||||
|
|
||||||
totalMemoryKB = totalKB;
|
totalMemoryKB = totalKB;
|
||||||
usedMemoryKB = totalKB - availableKB;
|
usedMemoryKB = usedKB;
|
||||||
totalSwapKB = mem.swaptotal || 0;
|
totalSwapKB = mem.swaptotal || 0;
|
||||||
usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0);
|
usedSwapKB = (mem.swaptotal || 0) - (mem.swapfree || 0);
|
||||||
|
|
||||||
|
|||||||
@@ -74,12 +74,10 @@ Singleton {
|
|||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: data => {
|
onRead: data => {
|
||||||
const result = data.trim();
|
const result = data.trim();
|
||||||
root.checkComplete = true;
|
|
||||||
|
|
||||||
if (result === "first") {
|
if (result === "first") {
|
||||||
root.isFirstLaunch = true;
|
root.isFirstLaunch = true;
|
||||||
console.info("FirstLaunchService: First launch detected, greeter will be shown");
|
console.info("FirstLaunchService: First launch detected, greeter will be shown");
|
||||||
root.greeterRequested();
|
|
||||||
} else if (result === "existing_user") {
|
} else if (result === "existing_user") {
|
||||||
root.isFirstLaunch = false;
|
root.isFirstLaunch = false;
|
||||||
console.info("FirstLaunchService: Existing user detected, silently creating marker");
|
console.info("FirstLaunchService: Existing user detected, silently creating marker");
|
||||||
@@ -87,6 +85,11 @@ Singleton {
|
|||||||
} else {
|
} else {
|
||||||
root.isFirstLaunch = false;
|
root.isFirstLaunch = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root.checkComplete = true;
|
||||||
|
|
||||||
|
if (root.isFirstLaunch)
|
||||||
|
root.greeterRequested();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -501,8 +501,12 @@ Singleton {
|
|||||||
return Actions.buildSpawnAction(command, args);
|
return Actions.buildSpawnAction(command, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildShellAction(shellCmd) {
|
function buildShellAction(shellCmd, shell) {
|
||||||
return Actions.buildShellAction(currentProvider, shellCmd);
|
return Actions.buildShellAction(currentProvider, shellCmd, shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getShellFromAction(action) {
|
||||||
|
return Actions.getShellFromAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSpawnCommand(action) {
|
function parseSpawnCommand(action) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
pragma ComponentBehavior
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -27,6 +27,10 @@ Singleton {
|
|||||||
|
|
||||||
property bool inOverview: false
|
property bool inOverview: false
|
||||||
|
|
||||||
|
property var casts: []
|
||||||
|
property bool hasCasts: casts.length > 0
|
||||||
|
property bool hasActiveCast: casts.some(c => c.is_active)
|
||||||
|
|
||||||
property int currentKeyboardLayoutIndex: 0
|
property int currentKeyboardLayoutIndex: 0
|
||||||
property var keyboardLayoutNames: []
|
property var keyboardLayoutNames: []
|
||||||
|
|
||||||
@@ -356,6 +360,15 @@ Singleton {
|
|||||||
case 'ScreenshotCaptured':
|
case 'ScreenshotCaptured':
|
||||||
handleScreenshotCaptured(event.ScreenshotCaptured);
|
handleScreenshotCaptured(event.ScreenshotCaptured);
|
||||||
break;
|
break;
|
||||||
|
case 'CastsChanged':
|
||||||
|
handleCastsChanged(event.CastsChanged);
|
||||||
|
break;
|
||||||
|
case 'CastStartedOrChanged':
|
||||||
|
handleCastStartedOrChanged(event.CastStartedOrChanged);
|
||||||
|
break;
|
||||||
|
case 'CastStopped':
|
||||||
|
handleCastStopped(event.CastStopped);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,6 +662,28 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCastsChanged(data) {
|
||||||
|
casts = data.casts || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCastStartedOrChanged(data) {
|
||||||
|
if (!data.cast)
|
||||||
|
return;
|
||||||
|
const cast = data.cast;
|
||||||
|
const existingIndex = casts.findIndex(c => c.stream_id === cast.stream_id);
|
||||||
|
if (existingIndex >= 0) {
|
||||||
|
const updatedCasts = [...casts];
|
||||||
|
updatedCasts[existingIndex] = cast;
|
||||||
|
casts = updatedCasts;
|
||||||
|
} else {
|
||||||
|
casts = [...casts, cast];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCastStopped(data) {
|
||||||
|
casts = casts.filter(c => c.stream_id !== data.stream_id);
|
||||||
|
}
|
||||||
|
|
||||||
function updateCurrentOutputWorkspaces() {
|
function updateCurrentOutputWorkspaces() {
|
||||||
if (!currentOutput) {
|
if (!currentOutput) {
|
||||||
currentOutputWorkspaces = allWorkspaces;
|
currentOutputWorkspaces = allWorkspaces;
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ Singleton {
|
|||||||
property int maxIngressPerSecond: 20
|
property int maxIngressPerSecond: 20
|
||||||
property double _lastIngressSec: 0
|
property double _lastIngressSec: 0
|
||||||
property int _ingressCountThisSec: 0
|
property int _ingressCountThisSec: 0
|
||||||
property int maxStoredNotifications: SettingsData.notificationHistoryMaxCount
|
|
||||||
|
|
||||||
property var _dismissQueue: []
|
property var _dismissQueue: []
|
||||||
property int _dismissBatchSize: 8
|
property int _dismissBatchSize: 8
|
||||||
@@ -340,30 +339,6 @@ Singleton {
|
|||||||
historyFileView.writeAdapter();
|
historyFileView.writeAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _trimStored() {
|
|
||||||
if (notifications.length > maxStoredNotifications) {
|
|
||||||
const overflow = notifications.length - maxStoredNotifications;
|
|
||||||
const toDrop = [];
|
|
||||||
for (var i = notifications.length - 1; i >= 0 && toDrop.length < overflow; --i) {
|
|
||||||
const w = notifications[i];
|
|
||||||
if (w && w.notification && w.urgency !== NotificationUrgency.Critical) {
|
|
||||||
toDrop.push(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var i = notifications.length - 1; i >= 0 && toDrop.length < overflow; --i) {
|
|
||||||
const w = notifications[i];
|
|
||||||
if (w && w.notification && toDrop.indexOf(w) === -1) {
|
|
||||||
toDrop.push(w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const w of toDrop) {
|
|
||||||
try {
|
|
||||||
w.notification.dismiss();
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onOverlayOpen() {
|
function onOverlayOpen() {
|
||||||
popupsDisabled = true;
|
popupsDisabled = true;
|
||||||
addGate.stop();
|
addGate.stop();
|
||||||
@@ -493,7 +468,6 @@ Singleton {
|
|||||||
root.allWrappers.push(wrapper);
|
root.allWrappers.push(wrapper);
|
||||||
if (!isTransient) {
|
if (!isTransient) {
|
||||||
root.notifications.push(wrapper);
|
root.notifications.push(wrapper);
|
||||||
_trimStored();
|
|
||||||
if (_shouldSaveToHistory(notif.urgency)) {
|
if (_shouldSaveToHistory(notif.urgency)) {
|
||||||
root.addToHistory(wrapper);
|
root.addToHistory(wrapper);
|
||||||
}
|
}
|
||||||
@@ -529,10 +503,8 @@ Singleton {
|
|||||||
|
|
||||||
readonly property Timer timer: Timer {
|
readonly property Timer timer: Timer {
|
||||||
interval: {
|
interval: {
|
||||||
if (!wrapper.notification) {
|
if (!wrapper.notification)
|
||||||
return 5000;
|
return 5000;
|
||||||
}
|
|
||||||
|
|
||||||
switch (wrapper.notification.urgency) {
|
switch (wrapper.notification.urgency) {
|
||||||
case NotificationUrgency.Low:
|
case NotificationUrgency.Low:
|
||||||
return SettingsData.notificationTimeoutLow;
|
return SettingsData.notificationTimeoutLow;
|
||||||
@@ -601,37 +573,38 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
required property Notification notification
|
required property Notification notification
|
||||||
readonly property string summary: notification.summary
|
readonly property string summary: notification?.summary ?? ""
|
||||||
readonly property string body: notification.body
|
readonly property string body: notification?.body ?? ""
|
||||||
readonly property string htmlBody: {
|
readonly property string htmlBody: {
|
||||||
if (body && (body.includes('<') && body.includes('>'))) {
|
if (!body)
|
||||||
|
return "";
|
||||||
|
if (body.includes('<') && body.includes('>'))
|
||||||
return body;
|
return body;
|
||||||
}
|
|
||||||
return Markdown2Html.markdownToHtml(body);
|
return Markdown2Html.markdownToHtml(body);
|
||||||
}
|
}
|
||||||
readonly property string appIcon: notification.appIcon
|
readonly property string appIcon: notification?.appIcon ?? ""
|
||||||
readonly property string appName: {
|
readonly property string appName: {
|
||||||
|
if (!notification)
|
||||||
|
return "app";
|
||||||
if (notification.appName == "") {
|
if (notification.appName == "") {
|
||||||
const entry = DesktopEntries.heuristicLookup(notification.desktopEntry);
|
const entry = DesktopEntries.heuristicLookup(notification.desktopEntry);
|
||||||
if (entry && entry.name) {
|
if (entry && entry.name)
|
||||||
return entry.name.toLowerCase();
|
return entry.name.toLowerCase();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return notification.appName || "app";
|
return notification.appName || "app";
|
||||||
}
|
}
|
||||||
readonly property string desktopEntry: notification.desktopEntry
|
readonly property string desktopEntry: notification?.desktopEntry ?? ""
|
||||||
readonly property string image: notification.image
|
readonly property string image: notification?.image ?? ""
|
||||||
readonly property string cleanImage: {
|
readonly property string cleanImage: {
|
||||||
if (!image) {
|
if (!image)
|
||||||
return "";
|
return "";
|
||||||
}
|
|
||||||
return Paths.strip(image);
|
return Paths.strip(image);
|
||||||
}
|
}
|
||||||
readonly property int urgency: notification.urgency
|
readonly property int urgency: notification?.urgency ?? 1
|
||||||
readonly property list<NotificationAction> actions: notification.actions
|
readonly property list<NotificationAction> actions: notification?.actions ?? []
|
||||||
|
|
||||||
readonly property Connections conn: Connections {
|
readonly property Connections conn: Connections {
|
||||||
target: wrapper.notification.Retainable
|
target: wrapper.notification?.Retainable ?? null
|
||||||
|
|
||||||
function onDropped(): void {
|
function onDropped(): void {
|
||||||
root.allWrappers = root.allWrappers.filter(w => w !== wrapper);
|
root.allWrappers = root.allWrappers.filter(w => w !== wrapper);
|
||||||
@@ -743,6 +716,8 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const next = notificationQueue.shift();
|
const next = notificationQueue.shift();
|
||||||
|
if (!next)
|
||||||
|
return;
|
||||||
|
|
||||||
next.seq = ++seqCounter;
|
next.seq = ++seqCounter;
|
||||||
visibleNotifications = [...visibleNotifications, next];
|
visibleNotifications = [...visibleNotifications, next];
|
||||||
@@ -805,7 +780,7 @@ Singleton {
|
|||||||
const groups = {};
|
const groups = {};
|
||||||
|
|
||||||
for (const notif of notifications) {
|
for (const notif of notifications) {
|
||||||
if (!notif)
|
if (!notif || !notif.notification)
|
||||||
continue;
|
continue;
|
||||||
const groupKey = getGroupKey(notif);
|
const groupKey = getGroupKey(notif);
|
||||||
if (!groups[groupKey]) {
|
if (!groups[groupKey]) {
|
||||||
@@ -823,14 +798,15 @@ Singleton {
|
|||||||
groups[groupKey].latestNotification = groups[groupKey].notifications[0];
|
groups[groupKey].latestNotification = groups[groupKey].notifications[0];
|
||||||
groups[groupKey].count = groups[groupKey].notifications.length;
|
groups[groupKey].count = groups[groupKey].notifications.length;
|
||||||
|
|
||||||
if (notif.notification.hasInlineReply) {
|
if (notif.notification?.hasInlineReply)
|
||||||
groups[groupKey].hasInlineReply = true;
|
groups[groupKey].hasInlineReply = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.values(groups).sort((a, b) => {
|
return Object.values(groups).sort((a, b) => {
|
||||||
const aUrgency = a.latestNotification.urgency || NotificationUrgency.Low;
|
if (!a.latestNotification || !b.latestNotification)
|
||||||
const bUrgency = b.latestNotification.urgency || NotificationUrgency.Low;
|
return 0;
|
||||||
|
const aUrgency = a.latestNotification.urgency ?? NotificationUrgency.Low;
|
||||||
|
const bUrgency = b.latestNotification.urgency ?? NotificationUrgency.Low;
|
||||||
if (aUrgency !== bUrgency) {
|
if (aUrgency !== bUrgency) {
|
||||||
return bUrgency - aUrgency;
|
return bUrgency - aUrgency;
|
||||||
}
|
}
|
||||||
@@ -842,7 +818,7 @@ Singleton {
|
|||||||
const groups = {};
|
const groups = {};
|
||||||
|
|
||||||
for (const notif of popups) {
|
for (const notif of popups) {
|
||||||
if (!notif)
|
if (!notif || !notif.notification)
|
||||||
continue;
|
continue;
|
||||||
const groupKey = getGroupKey(notif);
|
const groupKey = getGroupKey(notif);
|
||||||
if (!groups[groupKey]) {
|
if (!groups[groupKey]) {
|
||||||
@@ -860,12 +836,13 @@ Singleton {
|
|||||||
groups[groupKey].latestNotification = groups[groupKey].notifications[0];
|
groups[groupKey].latestNotification = groups[groupKey].notifications[0];
|
||||||
groups[groupKey].count = groups[groupKey].notifications.length;
|
groups[groupKey].count = groups[groupKey].notifications.length;
|
||||||
|
|
||||||
if (notif.notification.hasInlineReply) {
|
if (notif.notification?.hasInlineReply)
|
||||||
groups[groupKey].hasInlineReply = true;
|
groups[groupKey].hasInlineReply = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Object.values(groups).sort((a, b) => {
|
return Object.values(groups).sort((a, b) => {
|
||||||
|
if (!a.latestNotification || !b.latestNotification)
|
||||||
|
return 0;
|
||||||
return b.latestNotification.time.getTime() - a.latestNotification.time.getTime();
|
return b.latestNotification.time.getTime() - a.latestNotification.time.getTime();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,11 +287,14 @@ Singleton {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MODIFICATION: Treat Launchers as persistent instances like Daemons
|
if (isDaemon) {
|
||||||
if (isDaemon || isLauncher) {
|
const newDaemons = Object.assign({}, pluginDaemonComponents);
|
||||||
|
newDaemons[pluginId] = comp;
|
||||||
|
pluginDaemonComponents = newDaemons;
|
||||||
|
} else if (isLauncher) {
|
||||||
const instance = comp.createObject(root, {
|
const instance = comp.createObject(root, {
|
||||||
"pluginId": pluginId,
|
"pluginId": pluginId,
|
||||||
"pluginService": root // Inject PluginService
|
"pluginService": root
|
||||||
});
|
});
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
console.error("PluginService: failed to instantiate plugin:", pluginId, comp.errorString());
|
console.error("PluginService: failed to instantiate plugin:", pluginId, comp.errorString());
|
||||||
@@ -302,15 +305,9 @@ Singleton {
|
|||||||
newInstances[pluginId] = instance;
|
newInstances[pluginId] = instance;
|
||||||
pluginInstances = newInstances;
|
pluginInstances = newInstances;
|
||||||
|
|
||||||
if (isDaemon) {
|
const newLaunchers = Object.assign({}, pluginLauncherComponents);
|
||||||
const newDaemons = Object.assign({}, pluginDaemonComponents);
|
newLaunchers[pluginId] = comp;
|
||||||
newDaemons[pluginId] = comp;
|
pluginLauncherComponents = newLaunchers;
|
||||||
pluginDaemonComponents = newDaemons;
|
|
||||||
} else {
|
|
||||||
const newLaunchers = Object.assign({}, pluginLauncherComponents);
|
|
||||||
newLaunchers[pluginId] = comp;
|
|
||||||
pluginLauncherComponents = newLaunchers;
|
|
||||||
}
|
|
||||||
} else if (isDesktop) {
|
} else if (isDesktop) {
|
||||||
const newDesktop = Object.assign({}, pluginDesktopComponents);
|
const newDesktop = Object.assign({}, pluginDesktopComponents);
|
||||||
newDesktop[pluginId] = comp;
|
newDesktop[pluginId] = comp;
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ Singleton {
|
|||||||
property var colorPickerModal: null
|
property var colorPickerModal: null
|
||||||
property var notificationModal: null
|
property var notificationModal: null
|
||||||
property var wifiPasswordModal: null
|
property var wifiPasswordModal: null
|
||||||
|
property var wifiPasswordModalLoader: null
|
||||||
property var polkitAuthModal: null
|
property var polkitAuthModal: null
|
||||||
|
property var polkitAuthModalLoader: null
|
||||||
property var bluetoothPairingModal: null
|
property var bluetoothPairingModal: null
|
||||||
property var networkInfoModal: null
|
property var networkInfoModal: null
|
||||||
|
|
||||||
@@ -416,11 +418,17 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showWifiPasswordModal(ssid) {
|
function showWifiPasswordModal(ssid) {
|
||||||
wifiPasswordModal?.show(ssid);
|
if (wifiPasswordModalLoader)
|
||||||
|
wifiPasswordModalLoader.active = true;
|
||||||
|
if (wifiPasswordModal)
|
||||||
|
wifiPasswordModal.show(ssid);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showHiddenNetworkModal() {
|
function showHiddenNetworkModal() {
|
||||||
wifiPasswordModal?.showHidden();
|
if (wifiPasswordModalLoader)
|
||||||
|
wifiPasswordModalLoader.active = true;
|
||||||
|
if (wifiPasswordModal)
|
||||||
|
wifiPasswordModal.showHidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideWifiPasswordModal() {
|
function hideWifiPasswordModal() {
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Singleton {
|
|||||||
"paru": archBasedPMSettings,
|
"paru": archBasedPMSettings,
|
||||||
"dnf": fedoraBasedPMSettings
|
"dnf": fedoraBasedPMSettings
|
||||||
}
|
}
|
||||||
readonly property list<string> supportedDistributions: ["arch", "cachyos", "manjaro", "endeavouros", "fedora"]
|
readonly property list<string> supportedDistributions: ["arch", "artix", "cachyos", "manjaro", "endeavouros", "fedora"]
|
||||||
readonly property int updateCount: availableUpdates.length
|
readonly property int updateCount: availableUpdates.length
|
||||||
readonly property bool helperAvailable: pkgManager !== "" && distributionSupported
|
readonly property bool helperAvailable: pkgManager !== "" && distributionSupported
|
||||||
|
|
||||||
|
|||||||
@@ -745,6 +745,7 @@ Singleton {
|
|||||||
|
|
||||||
hourly_forecast.push({
|
hourly_forecast.push({
|
||||||
"time": formatTime(hourly.time[i]),
|
"time": formatTime(hourly.time[i]),
|
||||||
|
"rawTime": hourly.time[i],
|
||||||
"temp": Math.round(tempC),
|
"temp": Math.round(tempC),
|
||||||
"tempF": Math.round(tempF),
|
"tempF": Math.round(tempF),
|
||||||
"feelsLike": Math.round(feelsLikeC),
|
"feelsLike": Math.round(feelsLikeC),
|
||||||
@@ -753,7 +754,7 @@ Singleton {
|
|||||||
"humidity": Math.round(hourly.relative_humidity_2m?.[i] || 0),
|
"humidity": Math.round(hourly.relative_humidity_2m?.[i] || 0),
|
||||||
"wind": Math.round(hourly.wind_speed_10m?.[i] || 0),
|
"wind": Math.round(hourly.wind_speed_10m?.[i] || 0),
|
||||||
"pressure": Math.round(hourly.surface_pressure?.[i] || 0),
|
"pressure": Math.round(hourly.surface_pressure?.[i] || 0),
|
||||||
"precipitationProbability": Math.round(hourly.precipitation_probability_max?.[0] || 0),
|
"precipitationProbability": Math.round(hourly.precipitation_probability?.[i] || 0),
|
||||||
"visibility": Math.round(hourly.visibility?.[i] || 0),
|
"visibility": Math.round(hourly.visibility?.[i] || 0),
|
||||||
"isDay": isDay
|
"isDay": isDay
|
||||||
});
|
});
|
||||||
@@ -778,7 +779,9 @@ Singleton {
|
|||||||
"tempMaxF": Math.round(tempMaxF),
|
"tempMaxF": Math.round(tempMaxF),
|
||||||
"precipitationProbability": Math.round(daily.precipitation_probability_max?.[i] || 0),
|
"precipitationProbability": Math.round(daily.precipitation_probability_max?.[i] || 0),
|
||||||
"sunrise": daily.sunrise?.[i] ? formatTime(daily.sunrise[i]) : "",
|
"sunrise": daily.sunrise?.[i] ? formatTime(daily.sunrise[i]) : "",
|
||||||
"sunset": daily.sunset?.[i] ? formatTime(daily.sunset[i]) : ""
|
"sunset": daily.sunset?.[i] ? formatTime(daily.sunset[i]) : "",
|
||||||
|
"rawSunrise": daily.sunrise?.[i] || "",
|
||||||
|
"rawSunset": daily.sunset?.[i] || ""
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -805,6 +808,8 @@ Singleton {
|
|||||||
"wind": Math.round(current.wind_speed_10m || 0) + " " + (currentUnits.wind_speed_10m || 'm/s'),
|
"wind": Math.round(current.wind_speed_10m || 0) + " " + (currentUnits.wind_speed_10m || 'm/s'),
|
||||||
"sunrise": formatTime(daily.sunrise?.[0]) || "06:00",
|
"sunrise": formatTime(daily.sunrise?.[0]) || "06:00",
|
||||||
"sunset": formatTime(daily.sunset?.[0]) || "18:00",
|
"sunset": formatTime(daily.sunset?.[0]) || "18:00",
|
||||||
|
"rawSunrise": daily.sunrise?.[0] || "",
|
||||||
|
"rawSunset": daily.sunset?.[0] || "",
|
||||||
"uv": 0,
|
"uv": 0,
|
||||||
"pressure": Math.round(current.surface_pressure || 0),
|
"pressure": Math.round(current.surface_pressure || 0),
|
||||||
"precipitationProbability": Math.round(daily.precipitation_probability_max?.[0] || 0),
|
"precipitationProbability": Math.round(daily.precipitation_probability_max?.[0] || 0),
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
v1.2-unstable
|
v1.2.3
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ Image {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Paths.mkdir(Paths.imagecache);
|
Paths.mkdir(Paths.imagecache);
|
||||||
source = cachePath || encodedImagePath;
|
const hash = djb2Hash(imagePath);
|
||||||
|
const cPath = hash ? `${Paths.stringify(Paths.imagecache)}/${hash}@${maxCacheSize}x${maxCacheSize}.png` : "";
|
||||||
|
const encoded = "file://" + imagePath.split('/').map(s => encodeURIComponent(s)).join('/');
|
||||||
|
source = cPath || encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
|
|||||||
@@ -94,10 +94,10 @@ Flow {
|
|||||||
border.color: "transparent"
|
border.color: "transparent"
|
||||||
border.width: 0
|
border.width: 0
|
||||||
|
|
||||||
topLeftRadius: (visualFirst || selected) ? Theme.cornerRadius : 4
|
topLeftRadius: (visualFirst || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius)
|
||||||
bottomLeftRadius: (visualFirst || selected) ? Theme.cornerRadius : 4
|
bottomLeftRadius: (visualFirst || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius)
|
||||||
topRightRadius: (visualLast || selected) ? Theme.cornerRadius : 4
|
topRightRadius: (visualLast || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius)
|
||||||
bottomRightRadius: (visualLast || selected) ? Theme.cornerRadius : 4
|
bottomRightRadius: (visualLast || selected) ? Theme.cornerRadius : Math.min(4, Theme.cornerRadius)
|
||||||
|
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
enabled: root.userInteracted
|
enabled: root.userInteracted
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ Item {
|
|||||||
"endeavouros": "\u{f322}",
|
"endeavouros": "\u{f322}",
|
||||||
"manjaro": "\u{f160a}",
|
"manjaro": "\u{f160a}",
|
||||||
"opensuse": "\u{f314}",
|
"opensuse": "\u{f314}",
|
||||||
|
"artix": "\u{f31f}",
|
||||||
|
"void": "\u{f32e}",
|
||||||
|
|
||||||
// --- special types ---
|
// --- special types ---
|
||||||
"folder": "\u{F024B}",
|
"folder": "\u{F024B}",
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ Item {
|
|||||||
setBarContext(pos, bottomGap);
|
setBarContext(pos, bottomGap);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool useBackgroundWindow: true
|
readonly property bool useBackgroundWindow: !CompositorService.isHyprland || CompositorService.useHyprlandFocusGrab
|
||||||
|
|
||||||
function open() {
|
function open() {
|
||||||
if (!screen)
|
if (!screen)
|
||||||
@@ -304,20 +304,37 @@ Item {
|
|||||||
anchors {
|
anchors {
|
||||||
left: true
|
left: true
|
||||||
top: true
|
top: true
|
||||||
|
right: !useBackgroundWindow
|
||||||
|
bottom: !useBackgroundWindow
|
||||||
}
|
}
|
||||||
|
|
||||||
WlrLayershell.margins {
|
WlrLayershell.margins {
|
||||||
left: root.alignedX - shadowBuffer
|
left: useBackgroundWindow ? (root.alignedX - shadowBuffer) : 0
|
||||||
top: root.alignedY - shadowBuffer
|
top: useBackgroundWindow ? (root.alignedY - shadowBuffer) : 0
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitWidth: root.alignedWidth + (shadowBuffer * 2)
|
implicitWidth: useBackgroundWindow ? (root.alignedWidth + (shadowBuffer * 2)) : 0
|
||||||
implicitHeight: root.alignedHeight + (shadowBuffer * 2)
|
implicitHeight: useBackgroundWindow ? (root.alignedHeight + (shadowBuffer * 2)) : 0
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: !useBackgroundWindow && shouldBeVisible && backgroundInteractive
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
|
z: -1
|
||||||
|
onClicked: mouse => {
|
||||||
|
const clickX = mouse.x;
|
||||||
|
const clickY = mouse.y;
|
||||||
|
const outsideContent = clickX < root.alignedX || clickX > root.alignedX + root.alignedWidth || clickY < root.alignedY || clickY > root.alignedY + root.alignedHeight;
|
||||||
|
if (!outsideContent)
|
||||||
|
return;
|
||||||
|
backgroundClicked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: contentContainer
|
id: contentContainer
|
||||||
x: shadowBuffer
|
x: useBackgroundWindow ? shadowBuffer : root.alignedX
|
||||||
y: shadowBuffer
|
y: useBackgroundWindow ? shadowBuffer : root.alignedY
|
||||||
width: root.alignedWidth
|
width: root.alignedWidth
|
||||||
height: root.alignedHeight
|
height: root.alignedHeight
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ StyledRect {
|
|||||||
property color leftIconColor: Theme.surfaceVariantText
|
property color leftIconColor: Theme.surfaceVariantText
|
||||||
property color leftIconFocusedColor: Theme.primary
|
property color leftIconFocusedColor: Theme.primary
|
||||||
property bool showClearButton: false
|
property bool showClearButton: false
|
||||||
|
property bool showPasswordToggle: false
|
||||||
|
property bool passwordVisible: false
|
||||||
property color backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
property color backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
property color focusedBorderColor: Theme.primary
|
property color focusedBorderColor: Theme.primary
|
||||||
property color normalBorderColor: Theme.outlineMedium
|
property color normalBorderColor: Theme.outlineMedium
|
||||||
@@ -40,7 +42,14 @@ StyledRect {
|
|||||||
property int focusedBorderWidth: 2
|
property int focusedBorderWidth: 2
|
||||||
property real cornerRadius: Theme.cornerRadius
|
property real cornerRadius: Theme.cornerRadius
|
||||||
readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0)
|
readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0)
|
||||||
readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0)
|
readonly property real rightPadding: {
|
||||||
|
let p = Theme.spacingM;
|
||||||
|
if (showPasswordToggle)
|
||||||
|
p += 24 + Theme.spacingS;
|
||||||
|
if (showClearButton && text.length > 0)
|
||||||
|
p += 24 + Theme.spacingS;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
property real topPadding: Theme.spacingM
|
property real topPadding: Theme.spacingM
|
||||||
property real bottomPadding: Theme.spacingM
|
property real bottomPadding: Theme.spacingM
|
||||||
property bool ignoreLeftRightKeys: false
|
property bool ignoreLeftRightKeys: false
|
||||||
@@ -97,8 +106,8 @@ StyledRect {
|
|||||||
|
|
||||||
anchors.left: leftIcon.visible ? leftIcon.right : parent.left
|
anchors.left: leftIcon.visible ? leftIcon.right : parent.left
|
||||||
anchors.leftMargin: Theme.spacingM
|
anchors.leftMargin: Theme.spacingM
|
||||||
anchors.right: clearButton.visible ? clearButton.left : parent.right
|
anchors.right: rightButtonsRow.left
|
||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: rightButtonsRow.visible ? Theme.spacingS : Theme.spacingM
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: root.topPadding
|
anchors.topMargin: root.topPadding
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
@@ -151,33 +160,64 @@ StyledRect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledRect {
|
Row {
|
||||||
id: clearButton
|
id: rightButtonsRow
|
||||||
|
|
||||||
width: 24
|
|
||||||
height: 24
|
|
||||||
radius: 12
|
|
||||||
color: clearArea.containsMouse ? Theme.outlineStrong : "transparent"
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: Theme.spacingM
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: showClearButton && text.length > 0
|
spacing: Theme.spacingXS
|
||||||
|
visible: showPasswordToggle || (showClearButton && text.length > 0)
|
||||||
|
|
||||||
DankIcon {
|
StyledRect {
|
||||||
anchors.centerIn: parent
|
id: passwordToggleButton
|
||||||
name: "close"
|
|
||||||
size: 16
|
width: 24
|
||||||
color: clearArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
|
height: 24
|
||||||
|
radius: 12
|
||||||
|
color: passwordToggleArea.containsMouse ? Theme.outlineStrong : "transparent"
|
||||||
|
visible: showPasswordToggle
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: passwordVisible ? "visibility_off" : "visibility"
|
||||||
|
size: 16
|
||||||
|
color: passwordToggleArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: passwordToggleArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: passwordVisible = !passwordVisible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
StyledRect {
|
||||||
id: clearArea
|
id: clearButton
|
||||||
|
|
||||||
anchors.fill: parent
|
width: 24
|
||||||
hoverEnabled: true
|
height: 24
|
||||||
cursorShape: Qt.PointingHandCursor
|
radius: 12
|
||||||
onClicked: {
|
color: clearArea.containsMouse ? Theme.outlineStrong : "transparent"
|
||||||
textInput.text = "";
|
visible: showClearButton && text.length > 0
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "close"
|
||||||
|
size: 16
|
||||||
|
color: clearArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: clearArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: textInput.text = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pragma ComponentBehavior
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
@@ -1273,6 +1273,7 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
visible: optionsRow.argConfig?.base !== "screenshot-window"
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
DankToggle {
|
DankToggle {
|
||||||
@@ -1441,8 +1442,9 @@ Item {
|
|||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (root._actionType !== "shell")
|
if (root._actionType !== "shell")
|
||||||
return;
|
return;
|
||||||
|
var shell = Actions.getShellFromAction(root.editAction);
|
||||||
root.updateEdit({
|
root.updateEdit({
|
||||||
"action": Actions.buildShellAction(KeybindsService.currentProvider, text)
|
"action": Actions.buildShellAction(KeybindsService.currentProvider, text, shell)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
[templates.dmsmango]
|
[templates.dmsmango]
|
||||||
input_path = 'SHELL_DIR/matugen/templates/mango-colors.conf'
|
input_path = 'SHELL_DIR/matugen/templates/mango-colors.conf'
|
||||||
output_path = 'CONFIG_DIR/mango/dms/colors.conf'
|
output_path = 'CONFIG_DIR/mango/dms/colors.conf'
|
||||||
|
post_hook = 'sh -c "mmsg -d reload_config 2>&1 || true"'
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
// Focus + active indicators
|
// Focus + active indicators
|
||||||
//
|
//
|
||||||
"focusBorder": "{{colors.primary.dark.hex}}",
|
"focusBorder": "{{colors.primary.dark.hex}}",
|
||||||
"selection.background": "{{colors.primary_container.dark.hex}}66",
|
"selection.background": "{{colors.primary_container.dark.hex}}99",
|
||||||
//
|
//
|
||||||
// Title bar, activity bar, sidebar
|
// Title bar, activity bar, sidebar
|
||||||
//
|
//
|
||||||
@@ -127,7 +127,7 @@
|
|||||||
"editor.lineHighlightBackground": "{{colors.surface_container.dark.hex}}66",
|
"editor.lineHighlightBackground": "{{colors.surface_container.dark.hex}}66",
|
||||||
"editor.wordHighlightBackground": "{{colors.secondary.dark.hex}}22",
|
"editor.wordHighlightBackground": "{{colors.secondary.dark.hex}}22",
|
||||||
"editor.wordHighlightStrongBackground": "{{colors.tertiary.dark.hex}}22",
|
"editor.wordHighlightStrongBackground": "{{colors.tertiary.dark.hex}}22",
|
||||||
"editor.selectionBackground": "{{colors.primary_container.dark.hex}}66",
|
"editor.selectionBackground": "{{colors.primary_container.dark.hex}}99",
|
||||||
"editor.inactiveSelectionBackground": "{{colors.primary_container.dark.hex}}33",
|
"editor.inactiveSelectionBackground": "{{colors.primary_container.dark.hex}}33",
|
||||||
"editorWhitespace.foreground": "{{colors.outline.dark.hex}}66",
|
"editorWhitespace.foreground": "{{colors.outline.dark.hex}}66",
|
||||||
"editorIndentGuide.background1": "{{colors.outline.dark.hex}}33",
|
"editorIndentGuide.background1": "{{colors.outline.dark.hex}}33",
|
||||||
@@ -186,7 +186,8 @@
|
|||||||
"terminal.ansiBrightBlue": "{{dank16.color12.dark.hex}}",
|
"terminal.ansiBrightBlue": "{{dank16.color12.dark.hex}}",
|
||||||
"terminal.ansiBrightMagenta": "{{dank16.color13.dark.hex}}",
|
"terminal.ansiBrightMagenta": "{{dank16.color13.dark.hex}}",
|
||||||
"terminal.ansiBrightCyan": "{{dank16.color14.dark.hex}}",
|
"terminal.ansiBrightCyan": "{{dank16.color14.dark.hex}}",
|
||||||
"terminal.ansiBrightWhite": "{{dank16.color15.dark.hex}}"
|
"terminal.ansiBrightWhite": "{{dank16.color15.dark.hex}}",
|
||||||
|
"terminal.selectionBackground": "{{colors.primary_container.dark.hex}}99"
|
||||||
},
|
},
|
||||||
//
|
//
|
||||||
// Token colors
|
// Token colors
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user