mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-30 16:32:50 -05:00
Compare commits
4 Commits
d23fc9f2df
...
c1d95a3086
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1d95a3086 | ||
|
|
9b027df1d5 | ||
|
|
5e03afe7f0 | ||
|
|
145a974b6d |
@@ -17,3 +17,4 @@ This file is more of a quick reference so I know what to account for before next
|
|||||||
- Theme registry
|
- Theme registry
|
||||||
- Notification persistence & history
|
- Notification persistence & history
|
||||||
- **BREAKING** vscode theme needs re-installed
|
- **BREAKING** vscode theme needs re-installed
|
||||||
|
- dms doctor cmd
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ func (c category) String() string {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
checkNameMaxLength = 21
|
checkNameMaxLength = 21
|
||||||
|
doctorDocsURL = "https://danklinux.com/docs/dankmaterialshell/cli-doctor"
|
||||||
)
|
)
|
||||||
|
|
||||||
type checkResult struct {
|
type checkResult struct {
|
||||||
@@ -155,6 +156,7 @@ type checkResult struct {
|
|||||||
status status
|
status status
|
||||||
message string
|
message string
|
||||||
details string
|
details string
|
||||||
|
url string
|
||||||
}
|
}
|
||||||
|
|
||||||
type checkResultJSON struct {
|
type checkResultJSON struct {
|
||||||
@@ -163,6 +165,7 @@ type checkResultJSON struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Details string `json:"details,omitempty"`
|
Details string `json:"details,omitempty"`
|
||||||
|
URL string `json:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type doctorOutputJSON struct {
|
type doctorOutputJSON struct {
|
||||||
@@ -182,6 +185,7 @@ func (r checkResult) toJSON() checkResultJSON {
|
|||||||
Status: string(r.status),
|
Status: string(r.status),
|
||||||
Message: r.message,
|
Message: r.message,
|
||||||
Details: r.details,
|
Details: r.details,
|
||||||
|
URL: r.url,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,20 +235,21 @@ func checkSystemInfo() []checkResult {
|
|||||||
|
|
||||||
if strings.Contains(err.Error(), "Unsupported distribution") {
|
if strings.Contains(err.Error(), "Unsupported distribution") {
|
||||||
osRelease := readOSRelease()
|
osRelease := readOSRelease()
|
||||||
if osRelease["ID"] == "nixos" {
|
switch {
|
||||||
|
case osRelease["ID"] == "nixos":
|
||||||
status = statusOK
|
status = statusOK
|
||||||
message = osRelease["PRETTY_NAME"]
|
message = osRelease["PRETTY_NAME"]
|
||||||
if message == "" {
|
if message == "" {
|
||||||
message = fmt.Sprintf("NixOS %s", osRelease["VERSION_ID"])
|
message = fmt.Sprintf("NixOS %s", osRelease["VERSION_ID"])
|
||||||
}
|
}
|
||||||
details = "Supported for runtime (install via NixOS module or Flake)"
|
details = "Supported for runtime (install via NixOS module or Flake)"
|
||||||
} else if osRelease["PRETTY_NAME"] != "" {
|
case osRelease["PRETTY_NAME"] != "":
|
||||||
message = fmt.Sprintf("%s (not supported by dms setup)", osRelease["PRETTY_NAME"])
|
message = fmt.Sprintf("%s (not supported by dms setup)", osRelease["PRETTY_NAME"])
|
||||||
details = "DMS may work but automatic installation is not available"
|
details = "DMS may work but automatic installation is not available"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, checkResult{catSystem, "Operating System", status, message, details})
|
results = append(results, checkResult{catSystem, "Operating System", status, message, details, doctorDocsURL + "#operating-system"})
|
||||||
} else {
|
} else {
|
||||||
status := statusOK
|
status := statusOK
|
||||||
message := osInfo.PrettyName
|
message := osInfo.PrettyName
|
||||||
@@ -258,6 +263,7 @@ func checkSystemInfo() []checkResult {
|
|||||||
results = append(results, checkResult{
|
results = append(results, checkResult{
|
||||||
catSystem, "Operating System", status, message,
|
catSystem, "Operating System", status, message,
|
||||||
fmt.Sprintf("ID: %s, Version: %s, Arch: %s", osInfo.Distribution.ID, osInfo.VersionID, osInfo.Architecture),
|
fmt.Sprintf("ID: %s, Version: %s, Arch: %s", osInfo.Distribution.ID, osInfo.VersionID, osInfo.Architecture),
|
||||||
|
doctorDocsURL + "#operating-system",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +272,7 @@ func checkSystemInfo() []checkResult {
|
|||||||
if arch != "amd64" && arch != "arm64" {
|
if arch != "amd64" && arch != "arm64" {
|
||||||
archStatus = statusError
|
archStatus = statusError
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catSystem, "Architecture", archStatus, arch, ""})
|
results = append(results, checkResult{catSystem, "Architecture", archStatus, arch, "", doctorDocsURL + "#architecture"})
|
||||||
|
|
||||||
waylandDisplay := os.Getenv("WAYLAND_DISPLAY")
|
waylandDisplay := os.Getenv("WAYLAND_DISPLAY")
|
||||||
xdgSessionType := os.Getenv("XDG_SESSION_TYPE")
|
xdgSessionType := os.Getenv("XDG_SESSION_TYPE")
|
||||||
@@ -276,13 +282,15 @@ func checkSystemInfo() []checkResult {
|
|||||||
results = append(results, checkResult{
|
results = append(results, checkResult{
|
||||||
catSystem, "Display Server", statusOK, "Wayland",
|
catSystem, "Display Server", statusOK, "Wayland",
|
||||||
fmt.Sprintf("WAYLAND_DISPLAY=%s", waylandDisplay),
|
fmt.Sprintf("WAYLAND_DISPLAY=%s", waylandDisplay),
|
||||||
|
doctorDocsURL + "#display-server",
|
||||||
})
|
})
|
||||||
case xdgSessionType == "x11":
|
case xdgSessionType == "x11":
|
||||||
results = append(results, checkResult{catSystem, "Display Server", statusError, "X11 (DMS requires Wayland)", ""})
|
results = append(results, checkResult{catSystem, "Display Server", statusError, "X11 (DMS requires Wayland)", "", doctorDocsURL + "#display-server"})
|
||||||
default:
|
default:
|
||||||
results = append(results, checkResult{
|
results = append(results, checkResult{
|
||||||
catSystem, "Display Server", statusWarn, "Unknown (ensure you're running Wayland)",
|
catSystem, "Display Server", statusWarn, "Unknown (ensure you're running Wayland)",
|
||||||
fmt.Sprintf("XDG_SESSION_TYPE=%s", xdgSessionType),
|
fmt.Sprintf("XDG_SESSION_TYPE=%s", xdgSessionType),
|
||||||
|
doctorDocsURL + "#display-server",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,9 +307,10 @@ func checkEnvironmentVars() []checkResult {
|
|||||||
func checkEnvVar(name string) []checkResult {
|
func checkEnvVar(name string) []checkResult {
|
||||||
value := os.Getenv(name)
|
value := os.Getenv(name)
|
||||||
if value != "" {
|
if value != "" {
|
||||||
return []checkResult{{catEnvironment, name, statusInfo, value, ""}}
|
return []checkResult{{catEnvironment, name, statusInfo, value, "", doctorDocsURL + "#environment-variables"}}
|
||||||
} else if doctorVerbose {
|
}
|
||||||
return []checkResult{{catEnvironment, name, statusInfo, "Not set", ""}}
|
if doctorVerbose {
|
||||||
|
return []checkResult{{catEnvironment, name, statusInfo, "Not set", "", doctorDocsURL + "#environment-variables"}}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -328,7 +337,7 @@ func checkVersions(qsMissingFeatures bool) []checkResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
results := []checkResult{
|
results := []checkResult{
|
||||||
{catVersions, "DMS CLI", statusOK, formatVersion(Version), dmsCliDetails},
|
{catVersions, "DMS CLI", statusOK, formatVersion(Version), dmsCliDetails, doctorDocsURL + "#dms-cli"},
|
||||||
}
|
}
|
||||||
|
|
||||||
qsVersion, qsStatus, qsPath := getQuickshellVersionInfo(qsMissingFeatures)
|
qsVersion, qsStatus, qsPath := getQuickshellVersionInfo(qsMissingFeatures)
|
||||||
@@ -336,13 +345,13 @@ func checkVersions(qsMissingFeatures bool) []checkResult {
|
|||||||
if doctorVerbose && qsPath != "" {
|
if doctorVerbose && qsPath != "" {
|
||||||
qsDetails = qsPath
|
qsDetails = qsPath
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catVersions, "Quickshell", qsStatus, qsVersion, qsDetails})
|
results = append(results, checkResult{catVersions, "Quickshell", qsStatus, qsVersion, qsDetails, doctorDocsURL + "#quickshell"})
|
||||||
|
|
||||||
dmsVersion, dmsPath := getDMSShellVersion()
|
dmsVersion, dmsPath := getDMSShellVersion()
|
||||||
if dmsVersion != "" {
|
if dmsVersion != "" {
|
||||||
results = append(results, checkResult{catVersions, "DMS Shell", statusOK, dmsVersion, dmsPath})
|
results = append(results, checkResult{catVersions, "DMS Shell", statusOK, dmsVersion, dmsPath, doctorDocsURL + "#dms-shell"})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catVersions, "DMS Shell", statusError, "Not installed or not detected", "Run 'dms setup' to install"})
|
results = append(results, checkResult{catVersions, "DMS Shell", statusError, "Not installed or not detected", "Run 'dms setup' to install", doctorDocsURL + "#dms-shell"})
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -405,16 +414,16 @@ func checkDMSInstallation() []checkResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if dmsPath == "" {
|
if dmsPath == "" {
|
||||||
return []checkResult{{catInstallation, "DMS Configuration", statusError, "Not found", "shell.qml not found in any config path"}}
|
return []checkResult{{catInstallation, "DMS Configuration", statusError, "Not found", "shell.qml not found in any config path", doctorDocsURL + "#dms-configuration"}}
|
||||||
}
|
}
|
||||||
|
|
||||||
results = append(results, checkResult{catInstallation, "DMS Configuration", statusOK, "Found", dmsPath})
|
results = append(results, checkResult{catInstallation, "DMS Configuration", statusOK, "Found", dmsPath, doctorDocsURL + "#dms-configuration"})
|
||||||
|
|
||||||
shellQml := filepath.Join(dmsPath, "shell.qml")
|
shellQml := filepath.Join(dmsPath, "shell.qml")
|
||||||
if _, err := os.Stat(shellQml); err != nil {
|
if _, err := os.Stat(shellQml); err != nil {
|
||||||
results = append(results, checkResult{catInstallation, "shell.qml", statusError, "Missing", shellQml})
|
results = append(results, checkResult{catInstallation, "shell.qml", statusError, "Missing", shellQml, doctorDocsURL + "#dms-configuration"})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catInstallation, "shell.qml", statusOK, "Present", shellQml})
|
results = append(results, checkResult{catInstallation, "shell.qml", statusOK, "Present", shellQml, doctorDocsURL + "#dms-configuration"})
|
||||||
}
|
}
|
||||||
|
|
||||||
if doctorVerbose {
|
if doctorVerbose {
|
||||||
@@ -427,7 +436,7 @@ func checkDMSInstallation() []checkResult {
|
|||||||
case strings.Contains(dmsPath, ".config"):
|
case strings.Contains(dmsPath, ".config"):
|
||||||
installType = "User config"
|
installType = "User config"
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catInstallation, "Install Type", statusInfo, installType, dmsPath})
|
results = append(results, checkResult{catInstallation, "Install Type", statusInfo, installType, dmsPath, doctorDocsURL + "#dms-configuration"})
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -450,24 +459,26 @@ func checkWindowManagers() []checkResult {
|
|||||||
foundAny := false
|
foundAny := false
|
||||||
|
|
||||||
for _, c := range compositors {
|
for _, c := range compositors {
|
||||||
if slices.ContainsFunc(c.commands, utils.CommandExists) {
|
if !slices.ContainsFunc(c.commands, utils.CommandExists) {
|
||||||
foundAny = true
|
continue
|
||||||
var compositorPath string
|
|
||||||
for _, cmd := range c.commands {
|
|
||||||
if path, err := exec.LookPath(cmd); err == nil {
|
|
||||||
compositorPath = path
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
details := ""
|
|
||||||
if doctorVerbose && compositorPath != "" {
|
|
||||||
details = compositorPath
|
|
||||||
}
|
|
||||||
results = append(results, checkResult{
|
|
||||||
catCompositor, c.name, statusOK,
|
|
||||||
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
foundAny = true
|
||||||
|
var compositorPath string
|
||||||
|
for _, cmd := range c.commands {
|
||||||
|
if path, err := exec.LookPath(cmd); err == nil {
|
||||||
|
compositorPath = path
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
details := ""
|
||||||
|
if doctorVerbose && compositorPath != "" {
|
||||||
|
details = compositorPath
|
||||||
|
}
|
||||||
|
results = append(results, checkResult{
|
||||||
|
catCompositor, c.name, statusOK,
|
||||||
|
getVersionFromCommand(c.versionCmd, c.versionArg, c.versionRegex), details,
|
||||||
|
doctorDocsURL + "#compositor",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if !foundAny {
|
if !foundAny {
|
||||||
@@ -475,11 +486,12 @@ 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",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if wm := detectRunningWM(); wm != "" {
|
if wm := detectRunningWM(); wm != "" {
|
||||||
results = append(results, checkResult{catCompositor, "Active", statusInfo, wm, ""})
|
results = append(results, checkResult{catCompositor, "Active", statusInfo, wm, "", doctorDocsURL + "#compositor"})
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
@@ -601,7 +613,7 @@ ShellRoot {
|
|||||||
status, message = statusInfo, "Not available"
|
status, message = statusInfo, "Not available"
|
||||||
missingFeatures = true
|
missingFeatures = true
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catQuickshellFeatures, f.name, status, message, f.desc})
|
results = append(results, checkResult{catQuickshellFeatures, f.name, status, message, f.desc, doctorDocsURL + "#quickshell-features"})
|
||||||
}
|
}
|
||||||
|
|
||||||
return results, missingFeatures
|
return results, missingFeatures
|
||||||
@@ -610,16 +622,16 @@ ShellRoot {
|
|||||||
func checkI2CAvailability() checkResult {
|
func checkI2CAvailability() checkResult {
|
||||||
ddc, err := brightness.NewDDCBackend()
|
ddc, err := brightness.NewDDCBackend()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return checkResult{catOptionalFeatures, "I2C/DDC", statusInfo, "Not available", "External monitor brightness control"}
|
return checkResult{catOptionalFeatures, "I2C/DDC", statusInfo, "Not available", "External monitor brightness control", doctorDocsURL + "#optional-features"}
|
||||||
}
|
}
|
||||||
defer ddc.Close()
|
defer ddc.Close()
|
||||||
|
|
||||||
devices, err := ddc.GetDevices()
|
devices, err := ddc.GetDevices()
|
||||||
if err != nil || len(devices) == 0 {
|
if err != nil || len(devices) == 0 {
|
||||||
return checkResult{catOptionalFeatures, "I2C/DDC", statusInfo, "No monitors detected", "External monitor brightness control"}
|
return checkResult{catOptionalFeatures, "I2C/DDC", statusInfo, "No monitors detected", "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"}
|
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() string {
|
||||||
@@ -649,25 +661,24 @@ func checkOptionalDependencies() []checkResult {
|
|||||||
var results []checkResult
|
var results []checkResult
|
||||||
|
|
||||||
if utils.IsServiceActive("accounts-daemon", false) {
|
if utils.IsServiceActive("accounts-daemon", false) {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusOK, "Running", "User accounts"})
|
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusOK, "Running", "User accounts", doctorDocsURL + "#optional-features"})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusWarn, "Not running", "User accounts"})
|
results = append(results, checkResult{catOptionalFeatures, "accountsservice", statusWarn, "Not running", "User accounts", doctorDocsURL + "#optional-features"})
|
||||||
}
|
}
|
||||||
|
|
||||||
if utils.IsServiceActive("power-profiles-daemon", false) {
|
if utils.IsServiceActive("power-profiles-daemon", false) {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusOK, "Running", "Power profile management"})
|
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusOK, "Running", "Power profile management", doctorDocsURL + "#optional-features"})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusInfo, "Not running", "Power profile management"})
|
results = append(results, checkResult{catOptionalFeatures, "power-profiles-daemon", statusInfo, "Not running", "Power profile management", doctorDocsURL + "#optional-features"})
|
||||||
}
|
}
|
||||||
|
|
||||||
i2cStatus := checkI2CAvailability()
|
results = append(results, checkI2CAvailability())
|
||||||
results = append(results, i2cStatus)
|
|
||||||
|
|
||||||
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], ""})
|
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusOK, terminals[idx], "", doctorDocsURL + "#optional-features"})
|
||||||
} else {
|
} else {
|
||||||
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty"})
|
results = append(results, checkResult{catOptionalFeatures, "Terminal", statusWarn, "None found", "Install ghostty, kitty, or alacritty", doctorDocsURL + "#optional-features"})
|
||||||
}
|
}
|
||||||
|
|
||||||
deps := []struct {
|
deps := []struct {
|
||||||
@@ -686,13 +697,12 @@ func checkOptionalDependencies() []checkResult {
|
|||||||
|
|
||||||
for _, d := range deps {
|
for _, d := range deps {
|
||||||
found, foundCmd := utils.CommandExists(d.cmd), d.cmd
|
found, foundCmd := utils.CommandExists(d.cmd), d.cmd
|
||||||
if !found && d.altCmd != "" {
|
if !found && d.altCmd != "" && utils.CommandExists(d.altCmd) {
|
||||||
if utils.CommandExists(d.altCmd) {
|
found, foundCmd = true, d.altCmd
|
||||||
found, foundCmd = true, d.altCmd
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if found {
|
switch {
|
||||||
|
case found:
|
||||||
message := "Installed"
|
message := "Installed"
|
||||||
details := d.desc
|
details := d.desc
|
||||||
if d.name == "Network" {
|
if d.name == "Network" {
|
||||||
@@ -711,11 +721,11 @@ func checkOptionalDependencies() []checkResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, message, details})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusOK, message, details, doctorDocsURL + "#optional-features"})
|
||||||
} else if d.important {
|
case d.important:
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusWarn, "Missing", d.desc, doctorDocsURL + "#optional-features"})
|
||||||
} else {
|
default:
|
||||||
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc})
|
results = append(results, checkResult{catOptionalFeatures, d.name, statusInfo, "Not installed", d.desc, doctorDocsURL + "#optional-features"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,19 +748,18 @@ func checkConfigurationFiles() []checkResult {
|
|||||||
var results []checkResult
|
var results []checkResult
|
||||||
for _, cf := range configFiles {
|
for _, cf := range configFiles {
|
||||||
info, err := os.Stat(cf.path)
|
info, err := os.Stat(cf.path)
|
||||||
if err == nil {
|
if err != nil {
|
||||||
status := statusOK
|
results = append(results, checkResult{catConfigFiles, cf.name, statusInfo, "Not yet created", cf.path, doctorDocsURL + "#config-files"})
|
||||||
message := "Present"
|
continue
|
||||||
|
|
||||||
if info.Mode().Perm()&0200 == 0 {
|
|
||||||
status = statusWarn
|
|
||||||
message += " (read-only)"
|
|
||||||
}
|
|
||||||
|
|
||||||
results = append(results, checkResult{catConfigFiles, cf.name, status, message, cf.path})
|
|
||||||
} else {
|
|
||||||
results = append(results, checkResult{catConfigFiles, cf.name, statusInfo, "Not yet created", cf.path})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status := statusOK
|
||||||
|
message := "Present"
|
||||||
|
if info.Mode().Perm()&0200 == 0 {
|
||||||
|
status = statusWarn
|
||||||
|
message += " (read-only)"
|
||||||
|
}
|
||||||
|
results = append(results, checkResult{catConfigFiles, cf.name, status, message, cf.path, doctorDocsURL + "#config-files"})
|
||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
@@ -764,29 +773,31 @@ func checkSystemdServices() []checkResult {
|
|||||||
|
|
||||||
dmsState := getServiceState("dms", true)
|
dmsState := getServiceState("dms", true)
|
||||||
if !dmsState.exists {
|
if !dmsState.exists {
|
||||||
results = append(results, checkResult{catServices, "dms.service", statusInfo, "Not installed", "Optional user service"})
|
results = append(results, checkResult{catServices, "dms.service", statusInfo, "Not installed", "Optional user service", doctorDocsURL + "#services"})
|
||||||
} else {
|
} else {
|
||||||
status, message := statusOK, dmsState.enabled
|
status, message := statusOK, dmsState.enabled
|
||||||
if dmsState.active != "" {
|
if dmsState.active != "" {
|
||||||
message = fmt.Sprintf("%s, %s", dmsState.enabled, dmsState.active)
|
message = fmt.Sprintf("%s, %s", dmsState.enabled, dmsState.active)
|
||||||
}
|
}
|
||||||
if dmsState.enabled == "disabled" {
|
switch {
|
||||||
|
case dmsState.enabled == "disabled":
|
||||||
status, message = statusWarn, "Disabled"
|
status, message = statusWarn, "Disabled"
|
||||||
} else if dmsState.active == "failed" || dmsState.active == "inactive" {
|
case dmsState.active == "failed" || dmsState.active == "inactive":
|
||||||
status = statusError
|
status = statusError
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catServices, "dms.service", status, message, ""})
|
results = append(results, checkResult{catServices, "dms.service", status, message, "", doctorDocsURL + "#services"})
|
||||||
}
|
}
|
||||||
|
|
||||||
greetdState := getServiceState("greetd", false)
|
greetdState := getServiceState("greetd", false)
|
||||||
if greetdState.exists {
|
switch {
|
||||||
|
case greetdState.exists:
|
||||||
status := statusOK
|
status := statusOK
|
||||||
if greetdState.enabled == "disabled" {
|
if greetdState.enabled == "disabled" {
|
||||||
status = statusInfo
|
status = statusInfo
|
||||||
}
|
}
|
||||||
results = append(results, checkResult{catServices, "greetd", status, greetdState.enabled, ""})
|
results = append(results, checkResult{catServices, "greetd", status, greetdState.enabled, "", doctorDocsURL + "#services"})
|
||||||
} else if doctorVerbose {
|
case doctorVerbose:
|
||||||
results = append(results, checkResult{catServices, "greetd", statusInfo, "Not installed", "Optional greeter service"})
|
results = append(results, checkResult{catServices, "greetd", statusInfo, "Not installed", "Optional greeter service", doctorDocsURL + "#services"})
|
||||||
}
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|||||||
@@ -829,7 +829,11 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: FirstLaunchService
|
target: FirstLaunchService
|
||||||
function onGreeterRequested() {
|
function onGreeterRequested() {
|
||||||
greeterLoader.active = true;
|
if (greeterLoader.active && greeterLoader.item) {
|
||||||
|
greeterLoader.item.show();
|
||||||
|
} else {
|
||||||
|
greeterLoader.active = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -894,6 +894,26 @@ Item {
|
|||||||
target: "clipboard"
|
target: "clipboard"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function open(): string {
|
||||||
|
FirstLaunchService.showWelcome();
|
||||||
|
return "WELCOME_OPEN_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
function doctor(): string {
|
||||||
|
FirstLaunchService.showDoctor();
|
||||||
|
return "WELCOME_DOCTOR_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
function page(pageNum: string): string {
|
||||||
|
const num = parseInt(pageNum) || 0;
|
||||||
|
FirstLaunchService.showGreeter(num);
|
||||||
|
return `WELCOME_PAGE_SUCCESS: ${num}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "welcome"
|
||||||
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function toggleOverlay(instanceId: string): string {
|
function toggleOverlay(instanceId: string): string {
|
||||||
if (!instanceId)
|
if (!instanceId)
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ Rectangle {
|
|||||||
Column {
|
Column {
|
||||||
anchors.left: statusIcon.right
|
anchors.left: statusIcon.right
|
||||||
anchors.leftMargin: Theme.spacingS
|
anchors.leftMargin: Theme.spacingS
|
||||||
anchors.right: categoryChip.visible ? categoryChip.left : parent.right
|
anchors.right: categoryChip.visible ? categoryChip.left : (urlButton.visible ? urlButton.left : parent.right)
|
||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: Theme.spacingS
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: 1
|
spacing: 1
|
||||||
|
|
||||||
@@ -76,8 +76,8 @@ Rectangle {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: categoryChip
|
id: categoryChip
|
||||||
anchors.right: parent.right
|
anchors.right: urlButton.visible ? urlButton.left : parent.right
|
||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: urlButton.visible ? Theme.spacingXS : Theme.spacingM
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
height: Math.round(Theme.fontSizeSmall * 1.67)
|
height: Math.round(Theme.fontSizeSmall * 1.67)
|
||||||
width: categoryText.implicitWidth + Theme.spacingS
|
width: categoryText.implicitWidth + Theme.spacingS
|
||||||
@@ -93,4 +93,17 @@ Rectangle {
|
|||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
id: urlButton
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
iconName: "open_in_new"
|
||||||
|
iconSize: Theme.iconSize - 6
|
||||||
|
buttonSize: 24
|
||||||
|
visible: !!(root.resultData?.url)
|
||||||
|
tooltipText: root.resultData?.url || ""
|
||||||
|
onClicked: Qt.openUrlExternally(root.resultData.url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,12 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
currentPage = 0;
|
currentPage = FirstLaunchService.requestedStartPage || 0;
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showAtPage(page) {
|
||||||
|
currentPage = page;
|
||||||
visible = true;
|
visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,9 +114,13 @@ Item {
|
|||||||
const items = AppSearchService.getPluginItems(pluginCategory, "");
|
const items = AppSearchService.getPluginItems(pluginCategory, "");
|
||||||
emptyTriggerItems = emptyTriggerItems.concat(items);
|
emptyTriggerItems = emptyTriggerItems.concat(items);
|
||||||
});
|
});
|
||||||
apps = AppSearchService.applications.concat(emptyTriggerItems);
|
// Add Core Apps
|
||||||
|
const coreItems = AppSearchService.getCoreApps("");
|
||||||
|
apps = AppSearchService.applications.concat(emptyTriggerItems).concat(coreItems);
|
||||||
} else {
|
} else {
|
||||||
apps = AppSearchService.getAppsInCategory(selectedCategory).slice(0, maxResults);
|
apps = AppSearchService.getAppsInCategory(selectedCategory).slice(0, maxResults);
|
||||||
|
const coreItems = AppSearchService.getCoreApps("").filter(app => app.categories.includes(selectedCategory));
|
||||||
|
apps = apps.concat(coreItems);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (selectedCategory === allCategory) {
|
if (selectedCategory === allCategory) {
|
||||||
@@ -129,7 +133,9 @@ Item {
|
|||||||
const items = AppSearchService.getPluginItems(pluginCategory, searchQuery);
|
const items = AppSearchService.getPluginItems(pluginCategory, searchQuery);
|
||||||
emptyTriggerItems = emptyTriggerItems.concat(items);
|
emptyTriggerItems = emptyTriggerItems.concat(items);
|
||||||
});
|
});
|
||||||
apps = apps.concat(emptyTriggerItems);
|
|
||||||
|
const coreItems = AppSearchService.getCoreApps(searchQuery);
|
||||||
|
apps = apps.concat(emptyTriggerItems).concat(coreItems);
|
||||||
} else {
|
} else {
|
||||||
const categoryApps = AppSearchService.getAppsInCategory(selectedCategory);
|
const categoryApps = AppSearchService.getAppsInCategory(selectedCategory);
|
||||||
if (categoryApps.length > 0) {
|
if (categoryApps.length > 0) {
|
||||||
@@ -139,6 +145,9 @@ Item {
|
|||||||
} else {
|
} else {
|
||||||
apps = [];
|
apps = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const coreItems = AppSearchService.getCoreApps(searchQuery).filter(app => app.categories.includes(selectedCategory));
|
||||||
|
apps = apps.concat(coreItems);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +182,7 @@ Item {
|
|||||||
seenNames.add(itemKey);
|
seenNames.add(itemKey);
|
||||||
uniqueApps.push(app);
|
uniqueApps.push(app);
|
||||||
|
|
||||||
const isPluginItem = app.action !== undefined;
|
const isPluginItem = app.isCore ? false : (app.action !== undefined);
|
||||||
filteredModel.append({
|
filteredModel.append({
|
||||||
"name": app.name || "",
|
"name": app.name || "",
|
||||||
"exec": app.execString || app.exec || app.action || "",
|
"exec": app.execString || app.exec || app.action || "",
|
||||||
@@ -181,6 +190,7 @@ Item {
|
|||||||
"comment": app.comment || "",
|
"comment": app.comment || "",
|
||||||
"categories": app.categories || [],
|
"categories": app.categories || [],
|
||||||
"isPlugin": isPluginItem,
|
"isPlugin": isPluginItem,
|
||||||
|
"isCore": app.isCore === true,
|
||||||
"appIndex": uniqueApps.length - 1
|
"appIndex": uniqueApps.length - 1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -237,6 +247,12 @@ Item {
|
|||||||
|
|
||||||
const actualApp = _uniqueApps[appData.appIndex];
|
const actualApp = _uniqueApps[appData.appIndex];
|
||||||
|
|
||||||
|
if (appData.isCore) {
|
||||||
|
AppSearchService.executeCoreApp(actualApp);
|
||||||
|
appLaunched(appData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (appData.isPlugin) {
|
if (appData.isPlugin) {
|
||||||
const pluginId = getPluginIdForItem(actualApp);
|
const pluginId = getPluginIdForItem(actualApp);
|
||||||
if (pluginId) {
|
if (pluginId) {
|
||||||
|
|||||||
@@ -713,6 +713,63 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StyledRect {
|
||||||
|
width: parent.width
|
||||||
|
height: toolsSection.implicitHeight + Theme.spacingL * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: toolsSection
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "build"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Tools")
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("Show Welcome")
|
||||||
|
iconName: "waving_hand"
|
||||||
|
backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
onClicked: FirstLaunchService.showWelcome()
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
text: I18n.tr("System Check")
|
||||||
|
iconName: "vital_signs"
|
||||||
|
backgroundColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08)
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
onClicked: FirstLaunchService.showDoctor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: `<a href="https://github.com/AvengeMedia/DankMaterialShell/blob/master/LICENSE" style="text-decoration:none; color:${Theme.surfaceVariantText};">MIT License</a>`
|
text: `<a href="https://github.com/AvengeMedia/DankMaterialShell/blob/master/LICENSE" style="text-decoration:none; color:${Theme.surfaceVariantText};">MIT License</a>`
|
||||||
|
|||||||
@@ -42,6 +42,68 @@ Singleton {
|
|||||||
_cachedCategories = null;
|
_cachedCategories = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property var coreApps: [
|
||||||
|
{
|
||||||
|
name: "DMS Settings",
|
||||||
|
icon: Qt.resolvedUrl("../assets/danklogo2.svg"),
|
||||||
|
comment: "Manage DMS configuration",
|
||||||
|
action: "ipc:settings",
|
||||||
|
categories: ["Settings", "System"],
|
||||||
|
isCore: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DMS Notepad",
|
||||||
|
icon: "material:description",
|
||||||
|
comment: "Quick notes",
|
||||||
|
action: "ipc:notepad",
|
||||||
|
categories: ["Office", "Utility"],
|
||||||
|
isCore: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "DMS System Monitor",
|
||||||
|
icon: "material:monitor_heart",
|
||||||
|
comment: "System monitor and process list",
|
||||||
|
action: "ipc:processlist",
|
||||||
|
categories: ["System", "Monitor"],
|
||||||
|
isCore: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
function getCoreApps(query) {
|
||||||
|
if (!query || query.length === 0) {
|
||||||
|
return coreApps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerQuery = query.toLowerCase();
|
||||||
|
return coreApps.filter(app => {
|
||||||
|
return app.name.toLowerCase().includes(lowerQuery) || app.comment.toLowerCase().includes(lowerQuery);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeCoreApp(app) {
|
||||||
|
if (!app || !app.action) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const actionParts = app.action.split(":");
|
||||||
|
const actionType = actionParts[0];
|
||||||
|
const actionTarget = actionParts[1];
|
||||||
|
|
||||||
|
if (actionType === "ipc") {
|
||||||
|
if (actionTarget === "settings") {
|
||||||
|
Quickshell.execDetached(["dms", "ipc", "call", "settings", "toggle"]);
|
||||||
|
return true;
|
||||||
|
} else if (actionTarget === "notepad") {
|
||||||
|
Quickshell.execDetached(["dms", "ipc", "call", "notepad", "toggle"]);
|
||||||
|
return true;
|
||||||
|
} else if (actionTarget === "processlist") {
|
||||||
|
Quickshell.execDetached(["dms", "ipc", "call", "processlist", "focusOrToggle"]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DesktopEntries
|
target: DesktopEntries
|
||||||
function onApplicationsChanged() {
|
function onApplicationsChanged() {
|
||||||
|
|||||||
@@ -17,12 +17,26 @@ Singleton {
|
|||||||
property bool isFirstLaunch: false
|
property bool isFirstLaunch: false
|
||||||
property bool checkComplete: false
|
property bool checkComplete: false
|
||||||
property bool greeterDismissed: false
|
property bool greeterDismissed: false
|
||||||
|
property int requestedStartPage: 0
|
||||||
|
|
||||||
readonly property bool shouldShowGreeter: checkComplete && isFirstLaunch && !greeterDismissed
|
readonly property bool shouldShowGreeter: checkComplete && isFirstLaunch && !greeterDismissed
|
||||||
|
|
||||||
signal greeterRequested
|
signal greeterRequested
|
||||||
signal greeterCompleted
|
signal greeterCompleted
|
||||||
|
|
||||||
|
function showGreeter(startPage) {
|
||||||
|
requestedStartPage = startPage || 0;
|
||||||
|
greeterRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWelcome() {
|
||||||
|
showGreeter(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDoctor() {
|
||||||
|
showGreeter(1);
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
checkFirstLaunch();
|
checkFirstLaunch();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
@@ -54,7 +53,7 @@ Item {
|
|||||||
source: root.iconPath
|
source: root.iconPath
|
||||||
smooth: true
|
smooth: true
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
visible: !root.isMaterial && !root.isUnicode && status === Image.Ready
|
visible: !root.isMaterial && !root.isUnicode && root.iconPath !== "" && status === Image.Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -65,7 +64,7 @@ Item {
|
|||||||
anchors.rightMargin: root.fallbackRightMargin
|
anchors.rightMargin: root.fallbackRightMargin
|
||||||
anchors.topMargin: root.fallbackTopMargin
|
anchors.topMargin: root.fallbackTopMargin
|
||||||
anchors.bottomMargin: root.fallbackBottomMargin
|
anchors.bottomMargin: root.fallbackBottomMargin
|
||||||
visible: !root.isMaterial && !root.isUnicode && iconImg.status !== Image.Ready
|
visible: !root.isMaterial && !root.isUnicode && (root.iconPath === "" || iconImg.status !== Image.Ready)
|
||||||
color: root.fallbackBackgroundColor
|
color: root.fallbackBackgroundColor
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
border.width: 0
|
border.width: 0
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ Rectangle {
|
|||||||
width: computedIconSize
|
width: computedIconSize
|
||||||
height: computedIconSize
|
height: computedIconSize
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
iconValue: model.icon && model.icon !== "" ? model.icon : model.startupClass
|
iconValue: (model.icon && model.icon !== "") ? model.icon : ""
|
||||||
iconSize: computedIconSize
|
iconSize: computedIconSize
|
||||||
fallbackText: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
fallbackText: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
||||||
materialIconSizeAdjustment: root.iconMaterialSizeAdjustment
|
materialIconSizeAdjustment: root.iconMaterialSizeAdjustment
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Rectangle {
|
|||||||
width: root.iconSize
|
width: root.iconSize
|
||||||
height: root.iconSize
|
height: root.iconSize
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
iconValue: model.icon && model.icon !== "" ? model.icon : model.startupClass
|
iconValue: (model.icon && model.icon !== "") ? model.icon : ""
|
||||||
iconSize: root.iconSize
|
iconSize: root.iconSize
|
||||||
fallbackText: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
fallbackText: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
||||||
iconMargins: root.iconMargins
|
iconMargins: root.iconMargins
|
||||||
|
|||||||
@@ -102,12 +102,10 @@ Item {
|
|||||||
|
|
||||||
property string text: ""
|
property string text: ""
|
||||||
|
|
||||||
implicitWidth: Math.min(300, Math.max(120, textContent.implicitWidth + Theme.spacingM * 2))
|
leftPadding: Theme.spacingM
|
||||||
implicitHeight: textContent.implicitHeight + Theme.spacingS * 2
|
rightPadding: Theme.spacingM
|
||||||
width: implicitWidth
|
topPadding: Theme.spacingS
|
||||||
height: implicitHeight
|
bottomPadding: Theme.spacingS
|
||||||
|
|
||||||
padding: 0
|
|
||||||
closePolicy: Popup.NoAutoClose
|
closePolicy: Popup.NoAutoClose
|
||||||
modal: false
|
modal: false
|
||||||
dim: false
|
dim: false
|
||||||
@@ -122,6 +120,7 @@ Item {
|
|||||||
contentItem: Text {
|
contentItem: Text {
|
||||||
id: textContent
|
id: textContent
|
||||||
|
|
||||||
|
width: Math.min(implicitWidth, 500)
|
||||||
text: tooltip.text
|
text: tooltip.text
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ MouseArea {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: hoverDelay
|
id: hoverDelay
|
||||||
interval: 1000
|
interval: 400
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
tooltip.show(root.tooltipText, root, 0, 0, "bottom");
|
tooltip.show(root.tooltipText, root, 0, 0, "bottom");
|
||||||
|
|||||||
Reference in New Issue
Block a user