mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-30 08:22:51 -05:00
Compare commits
15 Commits
6f3c4c89ab
...
bc27253cbf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc27253cbf | ||
|
|
0672b711f3 | ||
|
|
ed9ee6e347 | ||
|
|
7ad23ad4a2 | ||
|
|
8a83f03cc1 | ||
|
|
0be9ac4097 | ||
|
|
ba5be6b516 | ||
|
|
c4aea6d326 | ||
|
|
858c6407a9 | ||
|
|
c4313395b5 | ||
|
|
a32aec3d59 | ||
|
|
696bcfe8fa | ||
|
|
2f3a253c6a | ||
|
|
e41fbe0188 | ||
|
|
ef9d28597b |
@@ -127,7 +127,7 @@ dms plugins search # Browse plugin registry
|
||||
## Documentation
|
||||
|
||||
- **Website:** [danklinux.com](https://danklinux.com)
|
||||
- **Docs:** [danklinux.com/docs](https://danklinux.com/docs)
|
||||
- **Docs:** [danklinux.com/docs](https://danklinux.com/docs/)
|
||||
- **Theming:** [Application themes](https://danklinux.com/docs/dankmaterialshell/application-themes) | [Custom themes](https://danklinux.com/docs/dankmaterialshell/custom-themes)
|
||||
- **Plugins:** [Development guide](https://danklinux.com/docs/dankmaterialshell/plugins-overview)
|
||||
- **Support:** [Ko-fi](https://ko-fi.com/avengemediallc)
|
||||
|
||||
@@ -208,7 +208,7 @@ func (d *DebianDistribution) InstallPrerequisites(ctx context.Context, sudoPassw
|
||||
|
||||
checkCmd := exec.CommandContext(ctx, "dpkg", "-l", "build-essential")
|
||||
if err := checkCmd.Run(); err != nil {
|
||||
cmd := ExecSudoCommand(ctx, sudoPassword, "apt-get install -y build-essential")
|
||||
cmd := ExecSudoCommand(ctx, sudoPassword, "DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential")
|
||||
if err := d.runWithProgress(cmd, progressChan, PhasePrerequisites, 0.08, 0.09); err != nil {
|
||||
return fmt.Errorf("failed to install build-essential: %w", err)
|
||||
}
|
||||
@@ -225,7 +225,7 @@ func (d *DebianDistribution) InstallPrerequisites(ctx context.Context, sudoPassw
|
||||
}
|
||||
|
||||
devToolsCmd := ExecSudoCommand(ctx, sudoPassword,
|
||||
"apt-get install -y curl wget git cmake ninja-build pkg-config libxcb-cursor-dev libglib2.0-dev libpolkit-agent-1-dev libjpeg-dev libpugixml-dev")
|
||||
"DEBIAN_FRONTEND=noninteractive apt-get install -y curl wget git cmake ninja-build pkg-config libxcb-cursor-dev libglib2.0-dev libpolkit-agent-1-dev libjpeg-dev libpugixml-dev")
|
||||
if err := d.runWithProgress(devToolsCmd, progressChan, PhasePrerequisites, 0.10, 0.12); err != nil {
|
||||
return fmt.Errorf("failed to install development tools: %w", err)
|
||||
}
|
||||
@@ -453,7 +453,7 @@ func (d *DebianDistribution) enableOBSRepos(ctx context.Context, obsPkgs []Packa
|
||||
CommandInfo: fmt.Sprintf("curl & gpg to add key for %s", pkg.RepoURL),
|
||||
}
|
||||
|
||||
keyCmd := fmt.Sprintf("curl -fsSL %s/Release.key | gpg --dearmor -o %s", baseURL, keyringPath)
|
||||
keyCmd := fmt.Sprintf("bash -c 'rm -f %s && curl -fsSL %s/Release.key | gpg --batch --dearmor -o %s'", keyringPath, baseURL, keyringPath)
|
||||
cmd := ExecSudoCommand(ctx, sudoPassword, keyCmd)
|
||||
if err := d.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.18, 0.20); err != nil {
|
||||
return fmt.Errorf("failed to add OBS GPG key for %s: %w", pkg.RepoURL, err)
|
||||
@@ -471,7 +471,7 @@ func (d *DebianDistribution) enableOBSRepos(ctx context.Context, obsPkgs []Packa
|
||||
}
|
||||
|
||||
addRepoCmd := ExecSudoCommand(ctx, sudoPassword,
|
||||
fmt.Sprintf("echo '%s' | tee %s", repoLine, listFile))
|
||||
fmt.Sprintf("bash -c \"echo '%s' | tee %s\"", repoLine, listFile))
|
||||
if err := d.runWithProgress(addRepoCmd, progressChan, PhaseSystemPackages, 0.20, 0.22); err != nil {
|
||||
return fmt.Errorf("failed to add OBS repo %s: %w", pkg.RepoURL, err)
|
||||
}
|
||||
@@ -506,7 +506,7 @@ func (d *DebianDistribution) installAPTPackages(ctx context.Context, packages []
|
||||
|
||||
d.log(fmt.Sprintf("Installing APT packages: %s", strings.Join(packages, ", ")))
|
||||
|
||||
args := []string{"apt-get", "install", "-y"}
|
||||
args := []string{"DEBIAN_FRONTEND=noninteractive", "apt-get", "install", "-y"}
|
||||
args = append(args, packages...)
|
||||
|
||||
progressChan <- InstallProgressMsg{
|
||||
@@ -616,7 +616,7 @@ func (d *DebianDistribution) installRust(ctx context.Context, sudoPassword strin
|
||||
CommandInfo: "sudo apt-get install rustup",
|
||||
}
|
||||
|
||||
rustupInstallCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get install -y rustup")
|
||||
rustupInstallCmd := ExecSudoCommand(ctx, sudoPassword, "DEBIAN_FRONTEND=noninteractive apt-get install -y rustup")
|
||||
if err := d.runWithProgress(rustupInstallCmd, progressChan, PhaseSystemPackages, 0.82, 0.83); err != nil {
|
||||
return fmt.Errorf("failed to install rustup: %w", err)
|
||||
}
|
||||
@@ -655,7 +655,7 @@ func (d *DebianDistribution) installGo(ctx context.Context, sudoPassword string,
|
||||
CommandInfo: "sudo apt-get install golang-go",
|
||||
}
|
||||
|
||||
installCmd := ExecSudoCommand(ctx, sudoPassword, "apt-get install -y golang-go")
|
||||
installCmd := ExecSudoCommand(ctx, sudoPassword, "DEBIAN_FRONTEND=noninteractive apt-get install -y golang-go")
|
||||
return d.runWithProgress(installCmd, progressChan, PhaseSystemPackages, 0.87, 0.90)
|
||||
}
|
||||
|
||||
|
||||
@@ -476,7 +476,7 @@ func (o *OpenSUSEDistribution) enableOBSRepos(ctx context.Context, obsPkgs []Pac
|
||||
cmd := ExecSudoCommand(ctx, sudoPassword,
|
||||
fmt.Sprintf("zypper addrepo -f %s", repoURL))
|
||||
if err := o.runWithProgress(cmd, progressChan, PhaseSystemPackages, 0.20, 0.22); err != nil {
|
||||
return fmt.Errorf("failed to enable OBS repo %s: %w", pkg.RepoURL, err)
|
||||
o.log(fmt.Sprintf("OBS repo %s add failed (may already exist): %v", pkg.RepoURL, err))
|
||||
}
|
||||
|
||||
enabledRepos[pkg.RepoURL] = true
|
||||
|
||||
@@ -562,53 +562,62 @@ func (m *Manager) transitionWorker() {
|
||||
case <-m.stopChan:
|
||||
return
|
||||
case targetTemp := <-m.transitionChan:
|
||||
m.transitionMutex.Lock()
|
||||
currentTemp := m.currentTemp
|
||||
m.targetTemp = targetTemp
|
||||
m.transitionMutex.Unlock()
|
||||
m.runTransition(targetTemp, steps, stepDur)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if currentTemp == targetTemp {
|
||||
continue
|
||||
func (m *Manager) runTransition(targetTemp int, steps int, stepDur time.Duration) {
|
||||
for {
|
||||
m.transitionMutex.Lock()
|
||||
currentTemp := m.currentTemp
|
||||
m.targetTemp = targetTemp
|
||||
m.transitionMutex.Unlock()
|
||||
|
||||
if currentTemp == targetTemp {
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Starting smooth transition: %dK -> %dK over %v", currentTemp, targetTemp, stepDur*time.Duration(steps))
|
||||
|
||||
redirected := false
|
||||
for i := 0; i <= steps; i++ {
|
||||
select {
|
||||
case newTarget := <-m.transitionChan:
|
||||
m.transitionMutex.Lock()
|
||||
m.targetTemp = newTarget
|
||||
m.transitionMutex.Unlock()
|
||||
if newTarget != targetTemp {
|
||||
log.Debugf("Transition %dK -> %dK redirected to %dK", currentTemp, targetTemp, newTarget)
|
||||
targetTemp = newTarget
|
||||
redirected = true
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
log.Debugf("Starting smooth transition: %dK -> %dK over %v", currentTemp, targetTemp, dur)
|
||||
|
||||
stepLoop:
|
||||
for i := 0; i <= steps; i++ {
|
||||
select {
|
||||
case newTarget := <-m.transitionChan:
|
||||
m.transitionMutex.Lock()
|
||||
m.targetTemp = newTarget
|
||||
m.transitionMutex.Unlock()
|
||||
log.Debugf("Transition %dK -> %dK aborted (newer transition started)", currentTemp, targetTemp)
|
||||
break stepLoop
|
||||
default:
|
||||
}
|
||||
|
||||
m.transitionMutex.RLock()
|
||||
if m.targetTemp != targetTemp {
|
||||
m.transitionMutex.RUnlock()
|
||||
break
|
||||
}
|
||||
m.transitionMutex.RUnlock()
|
||||
|
||||
progress := float64(i) / float64(steps)
|
||||
temp := currentTemp + int(float64(targetTemp-currentTemp)*progress)
|
||||
|
||||
m.post(func() { m.applyNowOnActor(temp) })
|
||||
|
||||
if i < steps {
|
||||
time.Sleep(stepDur)
|
||||
}
|
||||
if redirected {
|
||||
break
|
||||
}
|
||||
|
||||
m.transitionMutex.RLock()
|
||||
finalTarget := m.targetTemp
|
||||
currentTarget := m.targetTemp
|
||||
m.transitionMutex.RUnlock()
|
||||
|
||||
if finalTarget == targetTemp {
|
||||
log.Debugf("Transition complete: now at %dK", targetTemp)
|
||||
if currentTarget != targetTemp {
|
||||
targetTemp = currentTarget
|
||||
break
|
||||
}
|
||||
|
||||
progress := float64(i) / float64(steps)
|
||||
temp := currentTemp + int(float64(targetTemp-currentTemp)*progress)
|
||||
m.post(func() { m.applyNowOnActor(temp) })
|
||||
|
||||
if i == steps {
|
||||
log.Debugf("Transition complete: now at %dK", targetTemp)
|
||||
return
|
||||
}
|
||||
|
||||
time.Sleep(stepDur)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1206,11 +1215,18 @@ func (m *Manager) SetGamma(gamma float64) error {
|
||||
|
||||
func (m *Manager) SetEnabled(enabled bool) {
|
||||
m.configMutex.Lock()
|
||||
wasEnabled := m.config.Enabled
|
||||
m.config.Enabled = enabled
|
||||
highTemp := m.config.HighTemp
|
||||
m.configMutex.Unlock()
|
||||
|
||||
if enabled {
|
||||
if !m.controlsInitialized {
|
||||
m.transitionMutex.Lock()
|
||||
m.currentTemp = highTemp
|
||||
m.targetTemp = highTemp
|
||||
m.transitionMutex.Unlock()
|
||||
|
||||
m.post(func() {
|
||||
log.Info("Creating gamma controls")
|
||||
gammaMgr := m.gammaControl.(*wlr_gamma_control.ZwlrGammaControlManagerV1)
|
||||
@@ -1221,9 +1237,10 @@ func (m *Manager) SetEnabled(enabled bool) {
|
||||
log.Errorf("Failed to create gamma controls: %v", err)
|
||||
} else {
|
||||
m.controlsInitialized = true
|
||||
m.triggerUpdate()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
} else if !wasEnabled {
|
||||
m.triggerUpdate()
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
|
||||
user = config.services.greetd.settings.default_session.user;
|
||||
|
||||
cacheDir = "/var/lib/dms-greeter";
|
||||
greeterScript = pkgs.writeShellScriptBin "dms-greeter" ''
|
||||
export PATH=$PATH:${lib.makeBinPath [cfg.quickshell.package config.programs.${cfg.compositor.name}.package]}
|
||||
${lib.escapeShellArgs ([
|
||||
"sh"
|
||||
"${../../quickshell/Modules/Greetd/assets/dms-greeter}"
|
||||
"--cache-dir"
|
||||
"/var/lib/dmsgreeter"
|
||||
cacheDir
|
||||
"--command"
|
||||
cfg.compositor.name
|
||||
"-p"
|
||||
@@ -27,6 +28,8 @@
|
||||
"${pkgs.writeText "dmsgreeter-compositor-config" cfg.compositor.customConfig}"
|
||||
])} ${lib.optionalString cfg.logs.save "> ${cfg.logs.path} 2>&1"}
|
||||
'';
|
||||
|
||||
jq = lib.getExe pkgs.jq;
|
||||
in {
|
||||
imports = let
|
||||
msg = "The option 'programs.dankMaterialShell.greeter.compositor.extraConfig' is deprecated. Please use 'programs.dankMaterialShell.greeter.compositor.customConfig' instead.";
|
||||
@@ -93,17 +96,17 @@ in {
|
||||
material-symbols
|
||||
];
|
||||
systemd.tmpfiles.settings."10-dmsgreeter" = {
|
||||
"/var/lib/dmsgreeter".d = {
|
||||
${cacheDir}.d = {
|
||||
user = user;
|
||||
group =
|
||||
if config.users.users.${user}.group != ""
|
||||
then config.users.users.${user}.group
|
||||
else "greeter";
|
||||
mode = "0755";
|
||||
mode = "0750";
|
||||
};
|
||||
};
|
||||
systemd.services.greetd.preStart = ''
|
||||
cd /var/lib/dmsgreeter
|
||||
cd ${cacheDir}
|
||||
${lib.concatStringsSep "\n" (lib.map (f: ''
|
||||
if [ -f "${f}" ]; then
|
||||
cp "${f}" .
|
||||
@@ -112,9 +115,16 @@ in {
|
||||
cfg.configFiles)}
|
||||
|
||||
if [ -f session.json ]; then
|
||||
if cp "$(${lib.getExe pkgs.jq} -r '.wallpaperPath' session.json)" wallpaper.jpg; then
|
||||
if cp "$(${jq} -r '.wallpaperPath' session.json)" wallpaper.jpg; then
|
||||
mv session.json session.orig.json
|
||||
${lib.getExe pkgs.jq} '.wallpaperPath = "/var/lib/dmsgreeter/wallpaper.jpg"' session.orig.json > session.json
|
||||
${jq} '.wallpaperPath = "${cacheDir}/wallpaper.jpg"' session.orig.json > session.json
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f settings.json ]; then
|
||||
if cp "$(${jq} -r '.customThemeFile' settings.json)" custom-theme.json; then
|
||||
mv settings.json settings.orig.json
|
||||
${jq} '.customThemeFile = "${cacheDir}/custom-theme.json"' settings.orig.json > settings.json
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
1
quickshell/CODENAME
Normal file
1
quickshell/CODENAME
Normal file
@@ -0,0 +1 @@
|
||||
The Dark Knight
|
||||
@@ -53,7 +53,7 @@ Singleton {
|
||||
if (appId === "home assistant desktop")
|
||||
return "homeassistant-desktop";
|
||||
if (appId.includes("com.transmissionbt.transmission"))
|
||||
return "transmission-gtk";
|
||||
return "transmission";
|
||||
return appId;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,21 +128,13 @@ Singleton {
|
||||
setDesiredTheme("image", rawWallpaperPath, isLight, iconTheme, selectedMatugenType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let primaryColor;
|
||||
let matugenType;
|
||||
if (currentTheme === "custom") {
|
||||
if (customThemeData && customThemeData.primary) {
|
||||
primaryColor = customThemeData.primary;
|
||||
matugenType = customThemeData.matugen_type;
|
||||
}
|
||||
} else {
|
||||
primaryColor = currentThemeData.primary;
|
||||
matugenType = currentThemeData.matugen_type;
|
||||
}
|
||||
|
||||
if (primaryColor) {
|
||||
setDesiredTheme("hex", primaryColor, isLight, iconTheme, matugenType);
|
||||
} else if (currentTheme !== "custom") {
|
||||
const darkTheme = StockThemes.getThemeByName(currentTheme, false);
|
||||
const lightTheme = StockThemes.getThemeByName(currentTheme, true);
|
||||
if (darkTheme && darkTheme.primary) {
|
||||
const stockColors = buildMatugenColorsFromTheme(darkTheme, lightTheme);
|
||||
const themeData = isLight ? lightTheme : darkTheme;
|
||||
setDesiredTheme("hex", themeData.primary, isLight, iconTheme, themeData.matugen_type, stockColors);
|
||||
}
|
||||
}
|
||||
}, 0);
|
||||
|
||||
@@ -332,18 +332,16 @@ Item {
|
||||
if (!provider)
|
||||
return "ERROR: No provider specified";
|
||||
|
||||
KeybindsService.currentProvider = provider;
|
||||
KeybindsService.loadBinds();
|
||||
KeybindsService.loadCheatsheet(provider);
|
||||
root.hyprKeybindsModalLoader.active = true;
|
||||
|
||||
if (!root.hyprKeybindsModalLoader.item)
|
||||
return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
|
||||
|
||||
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
|
||||
if (root.hyprKeybindsModalLoader.item.shouldBeVisible)
|
||||
root.hyprKeybindsModalLoader.item.close();
|
||||
} else {
|
||||
else
|
||||
root.hyprKeybindsModalLoader.item.open();
|
||||
}
|
||||
return `KEYBINDS_TOGGLE_SUCCESS: ${provider}`;
|
||||
}
|
||||
|
||||
@@ -351,18 +349,16 @@ Item {
|
||||
if (!provider)
|
||||
return "ERROR: No provider specified";
|
||||
|
||||
KeybindsService.currentProvider = provider;
|
||||
KeybindsService.loadBinds();
|
||||
KeybindsService.loadCheatsheet(provider);
|
||||
root.hyprKeybindsModalLoader.active = true;
|
||||
|
||||
if (!root.hyprKeybindsModalLoader.item)
|
||||
return `KEYBINDS_TOGGLE_FAILED: ${provider}`;
|
||||
|
||||
if (root.hyprKeybindsModalLoader.item.shouldBeVisible) {
|
||||
if (root.hyprKeybindsModalLoader.item.shouldBeVisible)
|
||||
root.hyprKeybindsModalLoader.item.close();
|
||||
} else {
|
||||
else
|
||||
root.hyprKeybindsModalLoader.item.open();
|
||||
}
|
||||
return `KEYBINDS_TOGGLE_SUCCESS: ${provider} (${path})`;
|
||||
}
|
||||
|
||||
@@ -370,8 +366,7 @@ Item {
|
||||
if (!provider)
|
||||
return "ERROR: No provider specified";
|
||||
|
||||
KeybindsService.currentProvider = provider;
|
||||
KeybindsService.loadBinds();
|
||||
KeybindsService.loadCheatsheet(provider);
|
||||
root.hyprKeybindsModalLoader.active = true;
|
||||
|
||||
if (!root.hyprKeybindsModalLoader.item)
|
||||
@@ -385,8 +380,7 @@ Item {
|
||||
if (!provider)
|
||||
return "ERROR: No provider specified";
|
||||
|
||||
KeybindsService.currentProvider = provider;
|
||||
KeybindsService.loadBinds();
|
||||
KeybindsService.loadCheatsheet(provider);
|
||||
root.hyprKeybindsModalLoader.active = true;
|
||||
|
||||
if (!root.hyprKeybindsModalLoader.item)
|
||||
|
||||
@@ -17,7 +17,11 @@ DankModal {
|
||||
modalWidth: _maxW
|
||||
modalHeight: _maxH
|
||||
onBackgroundClicked: close()
|
||||
onOpened: () => Qt.callLater(() => modalFocusScope.forceActiveFocus())
|
||||
onOpened: {
|
||||
Qt.callLater(() => modalFocusScope.forceActiveFocus());
|
||||
if (!Object.keys(KeybindsService.cheatsheet).length && KeybindsService.cheatsheetAvailable)
|
||||
KeybindsService.loadCheatsheet();
|
||||
}
|
||||
|
||||
HyprlandFocusGrab {
|
||||
windows: [root.contentWindow]
|
||||
@@ -66,7 +70,7 @@ DankModal {
|
||||
spacing: Theme.spacingL
|
||||
|
||||
StyledText {
|
||||
text: KeybindsService.keybinds.title || "Keybinds"
|
||||
text: KeybindsService.cheatsheet.title || "Keybinds"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Bold
|
||||
color: Theme.primary
|
||||
@@ -82,7 +86,7 @@ DankModal {
|
||||
|
||||
Component.onCompleted: root.activeFlickable = mainFlickable
|
||||
|
||||
property var rawBinds: KeybindsService.keybinds.binds || {}
|
||||
property var rawBinds: KeybindsService.cheatsheet.binds || {}
|
||||
property var categories: {
|
||||
const processed = {};
|
||||
for (const cat in rawBinds) {
|
||||
@@ -114,12 +118,36 @@ DankModal {
|
||||
}
|
||||
property var categoryKeys: Object.keys(categories)
|
||||
|
||||
function estimateCategoryHeight(catName) {
|
||||
const catData = categories[catName];
|
||||
if (!catData)
|
||||
return 0;
|
||||
let bindCount = 0;
|
||||
for (const key of catData.subcatKeys) {
|
||||
bindCount += catData.subcats[key]?.length || 0;
|
||||
if (key !== "_root")
|
||||
bindCount += 1;
|
||||
}
|
||||
return 40 + bindCount * 28;
|
||||
}
|
||||
|
||||
function distributeCategories(cols) {
|
||||
const columns = [];
|
||||
for (let i = 0; i < cols; i++)
|
||||
const heights = [];
|
||||
for (let i = 0; i < cols; i++) {
|
||||
columns.push([]);
|
||||
for (let i = 0; i < categoryKeys.length; i++)
|
||||
columns[i % cols].push(categoryKeys[i]);
|
||||
heights.push(0);
|
||||
}
|
||||
const sorted = [...categoryKeys].sort((a, b) => estimateCategoryHeight(b) - estimateCategoryHeight(a));
|
||||
for (const cat of sorted) {
|
||||
let minIdx = 0;
|
||||
for (let i = 1; i < cols; i++) {
|
||||
if (heights[i] < heights[minIdx])
|
||||
minIdx = i;
|
||||
}
|
||||
columns[minIdx].push(cat);
|
||||
heights[minIdx] += estimateCategoryHeight(cat);
|
||||
}
|
||||
return columns;
|
||||
}
|
||||
|
||||
@@ -137,7 +165,7 @@ DankModal {
|
||||
Column {
|
||||
id: masonryColumn
|
||||
width: (rowLayout.width - rowLayout.spacing * (rowLayout.numColumns - 1)) / rowLayout.numColumns
|
||||
spacing: Theme.spacingM
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
Repeater {
|
||||
model: rowLayout.columnCategories[index] || []
|
||||
@@ -199,37 +227,37 @@ DankModal {
|
||||
Repeater {
|
||||
model: parent.parent.subcatBinds
|
||||
|
||||
Row {
|
||||
Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
height: 24
|
||||
|
||||
StyledRect {
|
||||
width: Math.min(140, parent.width * 0.42)
|
||||
id: keyBadge
|
||||
width: Math.min(keyText.implicitWidth + 12, 160)
|
||||
height: 22
|
||||
radius: 4
|
||||
opacity: 0.9
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
id: keyText
|
||||
anchors.centerIn: parent
|
||||
anchors.margins: 2
|
||||
width: parent.width - 4
|
||||
color: Theme.secondary
|
||||
text: modelData.key || ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
isMonospace: true
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width - 150
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 170
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: modelData.desc || modelData.action || ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
opacity: 0.9
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +384,7 @@ DankPopout {
|
||||
active: true
|
||||
tabBarItem: tabBar
|
||||
keyForwardTarget: mainContainer
|
||||
targetScreen: root.triggerScreen
|
||||
targetScreen: root.screen
|
||||
parentPopout: root
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import QtQuick.Effects
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Widgets
|
||||
|
||||
Item {
|
||||
id: aboutTab
|
||||
@@ -200,6 +199,16 @@ Item {
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
StyledText {
|
||||
visible: SystemUpdateService.shellCodename.length > 0
|
||||
text: `"${SystemUpdateService.shellCodename}"`
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.italic: true
|
||||
color: Theme.surfaceVariantText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Row {
|
||||
id: resourceButtonsRow
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -82,6 +82,7 @@ Variants {
|
||||
readonly property bool transitioning: transitionAnimation.running
|
||||
property bool effectActive: false
|
||||
property bool useNextForEffect: false
|
||||
property string pendingWallpaper: ""
|
||||
|
||||
function getFillMode(modeName) {
|
||||
switch (modeName) {
|
||||
@@ -162,12 +163,10 @@ Variants {
|
||||
return;
|
||||
if (!newPath || newPath.startsWith("#"))
|
||||
return;
|
||||
if (root.transitioning) {
|
||||
transitionAnimation.stop();
|
||||
root.transitionProgress = 0;
|
||||
root.effectActive = false;
|
||||
currentWallpaper.source = nextWallpaper.source;
|
||||
nextWallpaper.source = "";
|
||||
|
||||
if (root.transitioning || root.effectActive) {
|
||||
root.pendingWallpaper = newPath;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentWallpaper.source) {
|
||||
@@ -488,24 +487,28 @@ Variants {
|
||||
currentWallpaper.source = nextWallpaper.source;
|
||||
}
|
||||
root.useNextForEffect = false;
|
||||
Qt.callLater(() => {
|
||||
nextWallpaper.source = "";
|
||||
nextWallpaper.source = "";
|
||||
root.transitionProgress = 0.0;
|
||||
currentWallpaper.layer.enabled = false;
|
||||
nextWallpaper.layer.enabled = false;
|
||||
currentWallpaper.cache = true;
|
||||
nextWallpaper.cache = false;
|
||||
root.effectActive = false;
|
||||
|
||||
if (root.pendingWallpaper) {
|
||||
var pending = root.pendingWallpaper;
|
||||
root.pendingWallpaper = "";
|
||||
Qt.callLater(() => {
|
||||
root.effectActive = false;
|
||||
currentWallpaper.layer.enabled = false;
|
||||
nextWallpaper.layer.enabled = false;
|
||||
currentWallpaper.cache = true;
|
||||
nextWallpaper.cache = false;
|
||||
root.transitionProgress = 0.0;
|
||||
root.changeWallpaper(pending, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
source: effectLoader.active ? effectLoader.item : (root.actualTransitionType === "none" ? currentWallpaper : null)
|
||||
visible: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && source !== null
|
||||
source: effectLoader.active ? effectLoader.item : currentWallpaper
|
||||
visible: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && currentWallpaper.source !== ""
|
||||
blurEnabled: true
|
||||
blur: 0.8
|
||||
blurMax: 75
|
||||
|
||||
@@ -22,6 +22,18 @@ Singleton {
|
||||
|
||||
property bool available: CompositorService.isNiri && shortcutInhibitorAvailable
|
||||
property string currentProvider: "niri"
|
||||
|
||||
readonly property string cheatsheetProvider: {
|
||||
if (CompositorService.isNiri)
|
||||
return "niri";
|
||||
if (CompositorService.isHyprland)
|
||||
return "hyprland";
|
||||
return "";
|
||||
}
|
||||
property bool cheatsheetAvailable: cheatsheetProvider !== ""
|
||||
property bool cheatsheetLoading: false
|
||||
property var cheatsheet: ({})
|
||||
|
||||
property bool loading: false
|
||||
property bool saving: false
|
||||
property bool fixing: false
|
||||
@@ -58,17 +70,14 @@ Singleton {
|
||||
signal bindSaveCompleted(bool success)
|
||||
signal bindRemoved(string key)
|
||||
signal dmsBindsFixed
|
||||
|
||||
Component.onCompleted: {
|
||||
if (available)
|
||||
Qt.callLater(loadBinds);
|
||||
}
|
||||
signal cheatsheetLoaded
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
function onCompositorChanged() {
|
||||
if (CompositorService.isNiri)
|
||||
Qt.callLater(root.loadBinds);
|
||||
if (!CompositorService.isNiri)
|
||||
return;
|
||||
Qt.callLater(root.loadBinds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +89,31 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: cheatsheetProcess
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
root.cheatsheet = JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error("[KeybindsService] Failed to parse cheatsheet:", e);
|
||||
root.cheatsheet = {};
|
||||
}
|
||||
root.cheatsheetLoading = false;
|
||||
root.cheatsheetLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0)
|
||||
return;
|
||||
console.warn("[KeybindsService] Cheatsheet load failed with code:", exitCode);
|
||||
root.cheatsheetLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: loadProcess
|
||||
running: false
|
||||
@@ -199,6 +233,17 @@ Singleton {
|
||||
loadBinds(true);
|
||||
}
|
||||
|
||||
function loadCheatsheet(provider) {
|
||||
if (cheatsheetProcess.running)
|
||||
return;
|
||||
const target = provider || cheatsheetProvider;
|
||||
if (!target)
|
||||
return;
|
||||
cheatsheetLoading = true;
|
||||
cheatsheetProcess.command = ["dms", "keybinds", "show", target];
|
||||
cheatsheetProcess.running = true;
|
||||
}
|
||||
|
||||
function loadBinds(showLoading) {
|
||||
if (loadProcess.running || !available)
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
@@ -20,6 +19,7 @@ Singleton {
|
||||
property string distribution: ""
|
||||
property bool distributionSupported: false
|
||||
property string shellVersion: ""
|
||||
property string shellCodename: ""
|
||||
|
||||
readonly property var archBasedUCSettings: {
|
||||
"listUpdatesSettings": {
|
||||
@@ -34,7 +34,7 @@ Singleton {
|
||||
"currentVersion": match[2],
|
||||
"newVersion": match[3],
|
||||
"description": `${match[1]} ${match[2]} → ${match[3]}`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ Singleton {
|
||||
"currentVersion": match[2],
|
||||
"newVersion": match[3],
|
||||
"description": `${match[1]} ${match[2]} → ${match[3]}`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,7 +78,7 @@ Singleton {
|
||||
"currentVersion": "",
|
||||
"newVersion": match[2],
|
||||
"description": `${match[1]} → ${match[2]}`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,40 +100,49 @@ Singleton {
|
||||
command: ["sh", "-c", "cat /etc/os-release | grep '^ID=' | cut -d'=' -f2 | tr -d '\"'"]
|
||||
running: true
|
||||
|
||||
onExited: (exitCode) => {
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
distribution = stdout.text.trim().toLowerCase()
|
||||
distributionSupported = supportedDistributions.includes(distribution)
|
||||
distribution = stdout.text.trim().toLowerCase();
|
||||
distributionSupported = supportedDistributions.includes(distribution);
|
||||
|
||||
if (distributionSupported) {
|
||||
updateFinderDetection.running = true
|
||||
pkgManagerDetection.running = true
|
||||
checkForUpdates()
|
||||
updateFinderDetection.running = true;
|
||||
pkgManagerDetection.running = true;
|
||||
checkForUpdates();
|
||||
} else {
|
||||
console.warn("SystemUpdate: Unsupported distribution:", distribution)
|
||||
console.warn("SystemUpdate: Unsupported distribution:", distribution);
|
||||
}
|
||||
} else {
|
||||
console.warn("SystemUpdate: Failed to detect distribution")
|
||||
console.warn("SystemUpdate: Failed to detect distribution");
|
||||
}
|
||||
}
|
||||
|
||||
stdout: StdioCollector {}
|
||||
|
||||
Component.onCompleted: {
|
||||
versionDetection.running = true
|
||||
versionDetection.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: versionDetection
|
||||
command: [
|
||||
"sh", "-c",
|
||||
`cd "${Quickshell.shellDir}" && if [ -d .git ]; then echo "(git) $(git rev-parse --short HEAD)"; elif [ -f VERSION ]; then cat VERSION; fi`
|
||||
]
|
||||
command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -d .git ]; then echo "(git) $(git rev-parse --short HEAD)"; elif [ -f VERSION ]; then cat VERSION; fi`]
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
shellVersion = text.trim()
|
||||
shellVersion = text.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: codenameDetection
|
||||
command: ["sh", "-c", `cd "${Quickshell.shellDir}" && if [ -f CODENAME ]; then cat CODENAME; fi`]
|
||||
running: true
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
shellCodename = text.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,12 +151,12 @@ Singleton {
|
||||
id: updateFinderDetection
|
||||
command: ["sh", "-c", "which checkupdates"]
|
||||
|
||||
onExited: (exitCode) => {
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
const exeFound = stdout.text.trim()
|
||||
updChecker = exeFound.split('/').pop()
|
||||
const exeFound = stdout.text.trim();
|
||||
updChecker = exeFound.split('/').pop();
|
||||
} else {
|
||||
console.warn("SystemUpdate: No update checker found. Will use package manager.")
|
||||
console.warn("SystemUpdate: No update checker found. Will use package manager.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,12 +167,12 @@ Singleton {
|
||||
id: pkgManagerDetection
|
||||
command: ["sh", "-c", "which paru || which yay || which dnf"]
|
||||
|
||||
onExited: (exitCode) => {
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
const exeFound = stdout.text.trim()
|
||||
pkgManager = exeFound.split('/').pop()
|
||||
const exeFound = stdout.text.trim();
|
||||
pkgManager = exeFound.split('/').pop();
|
||||
} else {
|
||||
console.warn("SystemUpdate: No package manager found")
|
||||
console.warn("SystemUpdate: No package manager found");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,19 +182,17 @@ Singleton {
|
||||
Process {
|
||||
id: updateChecker
|
||||
|
||||
onExited: (exitCode) => {
|
||||
isChecking = false
|
||||
const correctExitCodes = updChecker.length > 0 ?
|
||||
[updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.correctExitCodes) :
|
||||
[pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.correctExitCodes)
|
||||
onExited: exitCode => {
|
||||
isChecking = false;
|
||||
const correctExitCodes = updChecker.length > 0 ? [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.correctExitCodes) : [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.correctExitCodes);
|
||||
if (correctExitCodes.includes(exitCode)) {
|
||||
parseUpdates(stdout.text)
|
||||
hasError = false
|
||||
errorMessage = ""
|
||||
parseUpdates(stdout.text);
|
||||
hasError = false;
|
||||
errorMessage = "";
|
||||
} else {
|
||||
hasError = true
|
||||
errorMessage = "Failed to check for updates"
|
||||
console.warn("SystemUpdate: Update check failed with code:", exitCode)
|
||||
hasError = true;
|
||||
errorMessage = "Failed to check for updates";
|
||||
console.warn("SystemUpdate: Update check failed with code:", exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,67 +201,67 @@ Singleton {
|
||||
|
||||
Process {
|
||||
id: updater
|
||||
onExited: (exitCode) => {
|
||||
checkForUpdates()
|
||||
onExited: exitCode => {
|
||||
checkForUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
function checkForUpdates() {
|
||||
if (!distributionSupported || (!pkgManager && !updChecker) || isChecking) return
|
||||
|
||||
isChecking = true
|
||||
hasError = false
|
||||
if (!distributionSupported || (!pkgManager && !updChecker) || isChecking)
|
||||
return;
|
||||
isChecking = true;
|
||||
hasError = false;
|
||||
if (updChecker.length > 0) {
|
||||
updateChecker.command = [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.params)
|
||||
updateChecker.command = [updChecker].concat(updateCheckerParams[updChecker].listUpdatesSettings.params);
|
||||
} else {
|
||||
updateChecker.command = [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.params)
|
||||
updateChecker.command = [pkgManager].concat(packageManagerParams[pkgManager].listUpdatesSettings.params);
|
||||
}
|
||||
updateChecker.running = true
|
||||
updateChecker.running = true;
|
||||
}
|
||||
|
||||
function parseUpdates(output) {
|
||||
const lines = output.trim().split('\n').filter(line => line.trim())
|
||||
const updates = []
|
||||
const lines = output.trim().split('\n').filter(line => line.trim());
|
||||
const updates = [];
|
||||
|
||||
const regex = packageManagerParams[pkgManager].parserSettings.lineRegex
|
||||
const entryProducer = packageManagerParams[pkgManager].parserSettings.entryProducer
|
||||
const regex = packageManagerParams[pkgManager].parserSettings.lineRegex;
|
||||
const entryProducer = packageManagerParams[pkgManager].parserSettings.entryProducer;
|
||||
|
||||
for (const line of lines) {
|
||||
const match = line.match(regex)
|
||||
const match = line.match(regex);
|
||||
if (match) {
|
||||
updates.push(entryProducer(match))
|
||||
updates.push(entryProducer(match));
|
||||
}
|
||||
}
|
||||
|
||||
availableUpdates = updates
|
||||
availableUpdates = updates;
|
||||
}
|
||||
|
||||
function runUpdates() {
|
||||
if (!distributionSupported || !pkgManager || updateCount === 0) return
|
||||
|
||||
const terminal = Quickshell.env("TERMINAL") || "xterm"
|
||||
if (!distributionSupported || !pkgManager || updateCount === 0)
|
||||
return;
|
||||
const terminal = Quickshell.env("TERMINAL") || "xterm";
|
||||
|
||||
if (SettingsData.updaterUseCustomCommand && SettingsData.updaterCustomCommand.length > 0) {
|
||||
const updateCommand = `${SettingsData.updaterCustomCommand} && echo "Updates complete! Press Enter to close..." && read`
|
||||
const termClass = SettingsData.updaterTerminalAdditionalParams
|
||||
const updateCommand = `${SettingsData.updaterCustomCommand} && echo "Updates complete! Press Enter to close..." && read`;
|
||||
const termClass = SettingsData.updaterTerminalAdditionalParams;
|
||||
|
||||
var finalCommand = [terminal]
|
||||
var finalCommand = [terminal];
|
||||
if (termClass.length > 0) {
|
||||
finalCommand = finalCommand.concat(termClass.split(" "))
|
||||
finalCommand = finalCommand.concat(termClass.split(" "));
|
||||
}
|
||||
finalCommand.push("-e")
|
||||
finalCommand.push("sh")
|
||||
finalCommand.push("-c")
|
||||
finalCommand.push(updateCommand)
|
||||
updater.command = finalCommand
|
||||
finalCommand.push("-e");
|
||||
finalCommand.push("sh");
|
||||
finalCommand.push("-c");
|
||||
finalCommand.push(updateCommand);
|
||||
updater.command = finalCommand;
|
||||
} else {
|
||||
const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" ")
|
||||
const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : ""
|
||||
const updateCommand = `${sudo} ${pkgManager} ${params} && echo "Updates complete! Press Enter to close..." && read`
|
||||
const params = packageManagerParams[pkgManager].upgradeSettings.params.join(" ");
|
||||
const sudo = packageManagerParams[pkgManager].upgradeSettings.requiresSudo ? "sudo" : "";
|
||||
const updateCommand = `${sudo} ${pkgManager} ${params} && echo "Updates complete! Press Enter to close..." && read`;
|
||||
|
||||
updater.command = [terminal, "-e", "sh", "-c", updateCommand]
|
||||
updater.command = [terminal, "-e", "sh", "-c", updateCommand];
|
||||
}
|
||||
updater.running = true
|
||||
updater.running = true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
@@ -263,22 +270,22 @@ Singleton {
|
||||
running: refCount > 0 && distributionSupported && (pkgManager || updChecker)
|
||||
onTriggered: checkForUpdates()
|
||||
}
|
||||
|
||||
|
||||
IpcHandler {
|
||||
target: "systemupdater"
|
||||
|
||||
function updatestatus(): string {
|
||||
if (root.isChecking) {
|
||||
return "ERROR: already checking"
|
||||
return "ERROR: already checking";
|
||||
}
|
||||
if (!distributionSupported) {
|
||||
return "ERROR: distribution not supported"
|
||||
return "ERROR: distribution not supported";
|
||||
}
|
||||
if (!pkgManager && !updChecker) {
|
||||
return "ERROR: update checker not available"
|
||||
return "ERROR: update checker not available";
|
||||
}
|
||||
root.checkForUpdates()
|
||||
return "SUCCESS: Now checking..."
|
||||
root.checkForUpdates();
|
||||
return "SUCCESS: Now checking...";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user