mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-31 08:52:49 -05:00
Compare commits
11 Commits
77fd61f81e
...
5b8edb13d8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b8edb13d8 | ||
|
|
c595727b94 | ||
|
|
d46302588a | ||
|
|
0ff9fdb365 | ||
|
|
e95f7ce367 | ||
|
|
df1a8f4066 | ||
|
|
32e6c1660f | ||
|
|
d6b9b72e9b | ||
|
|
179ad03fa4 | ||
|
|
c3cb82c84e | ||
|
|
4b52e2ed9e |
500
.github/workflows/release.yml
vendored
500
.github/workflows/release.yml
vendored
@@ -1,16 +1,19 @@
|
|||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
workflow_dispatch:
|
||||||
tags:
|
inputs:
|
||||||
- "v*"
|
tag:
|
||||||
|
description: "Tag to release (e.g., v1.0.1)"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
actions: write
|
actions: write
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: release-${{ github.ref_name }}
|
group: release-${{ inputs.tag }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -24,10 +27,14 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: core
|
working-directory: core
|
||||||
|
|
||||||
|
env:
|
||||||
|
TAG: ${{ inputs.tag }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
ref: ${{ inputs.tag }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
@@ -54,7 +61,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -eux
|
set -eux
|
||||||
cd cmd/dankinstall
|
cd cmd/dankinstall
|
||||||
go build -trimpath -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \
|
go build -trimpath -ldflags "-s -w -X main.Version=${TAG}" \
|
||||||
-o ../../dankinstall-${{ matrix.arch }}
|
-o ../../dankinstall-${{ matrix.arch }}
|
||||||
cd ../..
|
cd ../..
|
||||||
gzip -9 -k dankinstall-${{ matrix.arch }}
|
gzip -9 -k dankinstall-${{ matrix.arch }}
|
||||||
@@ -68,7 +75,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -eux
|
set -eux
|
||||||
cd cmd/dms
|
cd cmd/dms
|
||||||
go build -trimpath -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \
|
go build -trimpath -ldflags "-s -w -X main.Version=${TAG}" \
|
||||||
-o ../../dms-${{ matrix.arch }}
|
-o ../../dms-${{ matrix.arch }}
|
||||||
cd ../..
|
cd ../..
|
||||||
gzip -9 -k dms-${{ matrix.arch }}
|
gzip -9 -k dms-${{ matrix.arch }}
|
||||||
@@ -91,7 +98,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -eux
|
set -eux
|
||||||
cd cmd/dms
|
cd cmd/dms
|
||||||
go build -trimpath -tags distro_binary -ldflags "-s -w -X main.Version=${GITHUB_REF#refs/tags/}" \
|
go build -trimpath -tags distro_binary -ldflags "-s -w -X main.Version=${TAG}" \
|
||||||
-o ../../dms-distropkg-${{ matrix.arch }}
|
-o ../../dms-distropkg-${{ matrix.arch }}
|
||||||
cd ../..
|
cd ../..
|
||||||
gzip -9 -k dms-distropkg-${{ matrix.arch }}
|
gzip -9 -k dms-distropkg-${{ matrix.arch }}
|
||||||
@@ -171,17 +178,18 @@ jobs:
|
|||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs: [build-core] #, update-versions]
|
needs: [build-core] #, update-versions]
|
||||||
env:
|
env:
|
||||||
TAG: ${{ github.ref_name }}
|
TAG: ${{ inputs.tag }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
|
ref: ${{ inputs.tag }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Fetch updated tag after version bump
|
- name: Fetch updated tag after version bump
|
||||||
run: |
|
run: |
|
||||||
git fetch origin --force tag ${{ github.ref_name }}
|
git fetch origin --force tag ${TAG}
|
||||||
git checkout ${{ github.ref_name }}
|
git checkout ${TAG}
|
||||||
|
|
||||||
- name: Download core artifacts
|
- name: Download core artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
@@ -391,288 +399,296 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
trigger-obs-update:
|
# trigger-obs-update:
|
||||||
runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
needs: release
|
# needs: release
|
||||||
steps:
|
# env:
|
||||||
- name: Checkout
|
# TAG: ${{ inputs.tag }}
|
||||||
uses: actions/checkout@v4
|
# steps:
|
||||||
|
# - name: Checkout
|
||||||
|
# uses: actions/checkout@v4
|
||||||
|
# with:
|
||||||
|
# ref: ${{ inputs.tag }}
|
||||||
|
|
||||||
- name: Install OSC
|
# - name: Install OSC
|
||||||
run: |
|
# run: |
|
||||||
sudo apt-get update
|
# sudo apt-get update
|
||||||
sudo apt-get install -y osc
|
# sudo apt-get install -y osc
|
||||||
|
|
||||||
mkdir -p ~/.config/osc
|
# mkdir -p ~/.config/osc
|
||||||
cat > ~/.config/osc/oscrc << EOF
|
# cat > ~/.config/osc/oscrc << EOF
|
||||||
[general]
|
# [general]
|
||||||
apiurl = https://api.opensuse.org
|
# apiurl = https://api.opensuse.org
|
||||||
|
|
||||||
[https://api.opensuse.org]
|
# [https://api.opensuse.org]
|
||||||
user = ${{ secrets.OBS_USERNAME }}
|
# user = ${{ secrets.OBS_USERNAME }}
|
||||||
pass = ${{ secrets.OBS_PASSWORD }}
|
# pass = ${{ secrets.OBS_PASSWORD }}
|
||||||
EOF
|
# EOF
|
||||||
chmod 600 ~/.config/osc/oscrc
|
# chmod 600 ~/.config/osc/oscrc
|
||||||
|
|
||||||
- name: Update OBS packages
|
# - name: Update OBS packages
|
||||||
run: |
|
# run: |
|
||||||
VERSION="${{ github.ref_name }}"
|
# cd distro
|
||||||
cd distro
|
# bash scripts/obs-upload.sh dms "Update to ${TAG}"
|
||||||
bash scripts/obs-upload.sh dms "Update to $VERSION"
|
|
||||||
|
|
||||||
trigger-ppa-update:
|
# trigger-ppa-update:
|
||||||
runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
needs: release
|
# needs: release
|
||||||
steps:
|
# env:
|
||||||
- name: Checkout
|
# TAG: ${{ inputs.tag }}
|
||||||
uses: actions/checkout@v4
|
# steps:
|
||||||
|
# - name: Checkout
|
||||||
|
# uses: actions/checkout@v4
|
||||||
|
# with:
|
||||||
|
# ref: ${{ inputs.tag }}
|
||||||
|
|
||||||
- name: Install build dependencies
|
# - name: Install build dependencies
|
||||||
run: |
|
# run: |
|
||||||
sudo apt-get update
|
# sudo apt-get update
|
||||||
sudo apt-get install -y \
|
# sudo apt-get install -y \
|
||||||
debhelper \
|
# debhelper \
|
||||||
devscripts \
|
# devscripts \
|
||||||
dput \
|
# dput \
|
||||||
lftp \
|
# lftp \
|
||||||
build-essential \
|
# build-essential \
|
||||||
fakeroot \
|
# fakeroot \
|
||||||
dpkg-dev
|
# dpkg-dev
|
||||||
|
|
||||||
- name: Configure GPG
|
# - name: Configure GPG
|
||||||
env:
|
# env:
|
||||||
GPG_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
# GPG_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
run: |
|
# run: |
|
||||||
echo "$GPG_KEY" | gpg --import
|
# echo "$GPG_KEY" | gpg --import
|
||||||
GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | grep sec | awk '{print $2}' | cut -d'/' -f2)
|
# GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format LONG | grep sec | awk '{print $2}' | cut -d'/' -f2)
|
||||||
echo "DEBSIGN_KEYID=$GPG_KEY_ID" >> $GITHUB_ENV
|
# echo "DEBSIGN_KEYID=$GPG_KEY_ID" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Upload to PPA
|
# - name: Upload to PPA
|
||||||
run: |
|
# run: |
|
||||||
VERSION="${{ github.ref_name }}"
|
# cd distro/ubuntu/ppa
|
||||||
cd distro/ubuntu/ppa
|
# bash create-and-upload.sh ../dms dms questing
|
||||||
bash create-and-upload.sh ../dms dms questing
|
|
||||||
|
|
||||||
copr-build:
|
# copr-build:
|
||||||
runs-on: ubuntu-latest
|
# runs-on: ubuntu-latest
|
||||||
needs: release
|
# needs: release
|
||||||
env:
|
# env:
|
||||||
TAG: ${{ github.ref_name }}
|
# TAG: ${{ inputs.tag }}
|
||||||
|
|
||||||
steps:
|
# steps:
|
||||||
- name: Checkout repository
|
# - name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
# uses: actions/checkout@v4
|
||||||
|
# with:
|
||||||
|
# ref: ${{ inputs.tag }}
|
||||||
|
|
||||||
- name: Determine version
|
# - name: Determine version
|
||||||
id: version
|
# id: version
|
||||||
run: |
|
# run: |
|
||||||
VERSION="${TAG#v}"
|
# VERSION="${TAG#v}"
|
||||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
# echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
echo "Building DMS stable version: $VERSION"
|
# echo "Building DMS stable version: $VERSION"
|
||||||
|
|
||||||
- name: Setup build environment
|
# - name: Setup build environment
|
||||||
run: |
|
# run: |
|
||||||
sudo apt-get update
|
# sudo apt-get update
|
||||||
sudo apt-get install -y rpm wget curl jq gzip
|
# sudo apt-get install -y rpm wget curl jq gzip
|
||||||
mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
|
# mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
|
||||||
|
|
||||||
- name: Download release assets
|
# - name: Download release assets
|
||||||
run: |
|
# run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
# VERSION="${{ steps.version.outputs.version }}"
|
||||||
cd ~/rpmbuild/SOURCES
|
# cd ~/rpmbuild/SOURCES
|
||||||
|
|
||||||
wget "https://github.com/AvengeMedia/DankMaterialShell/releases/download/v${VERSION}/dms-qml.tar.gz" || {
|
# wget "https://github.com/AvengeMedia/DankMaterialShell/releases/download/v${VERSION}/dms-qml.tar.gz" || {
|
||||||
echo "Failed to download dms-qml.tar.gz for v${VERSION}"
|
# echo "Failed to download dms-qml.tar.gz for v${VERSION}"
|
||||||
exit 1
|
# exit 1
|
||||||
}
|
# }
|
||||||
|
|
||||||
- name: Generate stable spec file
|
# - name: Generate stable spec file
|
||||||
run: |
|
# run: |
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
# VERSION="${{ steps.version.outputs.version }}"
|
||||||
CHANGELOG_DATE="$(date '+%a %b %d %Y')"
|
# CHANGELOG_DATE="$(date '+%a %b %d %Y')"
|
||||||
|
|
||||||
cat > ~/rpmbuild/SPECS/dms.spec <<'SPECEOF'
|
# cat > ~/rpmbuild/SPECS/dms.spec <<'SPECEOF'
|
||||||
# Spec for DMS stable releases - Generated by GitHub Actions
|
# # Spec for DMS stable releases - Generated by GitHub Actions
|
||||||
|
|
||||||
%global debug_package %{nil}
|
# %global debug_package %{nil}
|
||||||
%global version VERSION_PLACEHOLDER
|
# %global version VERSION_PLACEHOLDER
|
||||||
%global pkg_summary DankMaterialShell - Material 3 inspired shell for Wayland compositors
|
# %global pkg_summary DankMaterialShell - Material 3 inspired shell for Wayland compositors
|
||||||
|
|
||||||
Name: dms
|
# Name: dms
|
||||||
Version: %{version}
|
# Version: %{version}
|
||||||
Release: 1%{?dist}
|
# Release: 1%{?dist}
|
||||||
Summary: %{pkg_summary}
|
# Summary: %{pkg_summary}
|
||||||
|
|
||||||
License: MIT
|
# License: MIT
|
||||||
URL: https://github.com/AvengeMedia/DankMaterialShell
|
# URL: https://github.com/AvengeMedia/DankMaterialShell
|
||||||
|
|
||||||
Source0: dms-qml.tar.gz
|
# Source0: dms-qml.tar.gz
|
||||||
|
|
||||||
BuildRequires: gzip
|
# BuildRequires: gzip
|
||||||
BuildRequires: wget
|
# BuildRequires: wget
|
||||||
BuildRequires: systemd-rpm-macros
|
# BuildRequires: systemd-rpm-macros
|
||||||
|
|
||||||
Requires: (quickshell or quickshell-git)
|
# Requires: (quickshell or quickshell-git)
|
||||||
Requires: accountsservice
|
# Requires: accountsservice
|
||||||
Requires: dms-cli = %{version}-%{release}
|
# Requires: dms-cli = %{version}-%{release}
|
||||||
Requires: dgop
|
# Requires: dgop
|
||||||
|
|
||||||
Recommends: cava
|
# Recommends: cava
|
||||||
Recommends: cliphist
|
# Recommends: cliphist
|
||||||
Recommends: danksearch
|
# Recommends: danksearch
|
||||||
Recommends: matugen
|
# Recommends: matugen
|
||||||
Recommends: wl-clipboard
|
# Recommends: wl-clipboard
|
||||||
Recommends: NetworkManager
|
# Recommends: NetworkManager
|
||||||
Recommends: qt6-qtmultimedia
|
# Recommends: qt6-qtmultimedia
|
||||||
Suggests: qt6ct
|
# Suggests: qt6ct
|
||||||
|
|
||||||
%description
|
# %description
|
||||||
DankMaterialShell (DMS) is a modern Wayland desktop shell built with Quickshell
|
# DankMaterialShell (DMS) is a modern Wayland desktop shell built with Quickshell
|
||||||
and optimized for the niri and hyprland compositors. Features notifications,
|
# and optimized for the niri and hyprland compositors. Features notifications,
|
||||||
app launcher, wallpaper customization, and fully customizable with plugins.
|
# app launcher, wallpaper customization, and fully customizable with plugins.
|
||||||
|
|
||||||
Includes auto-theming for GTK/Qt apps with matugen, 20+ customizable widgets,
|
# Includes auto-theming for GTK/Qt apps with matugen, 20+ customizable widgets,
|
||||||
process monitoring, notification center, clipboard history, dock, control center,
|
# process monitoring, notification center, clipboard history, dock, control center,
|
||||||
lock screen, and comprehensive plugin system.
|
# lock screen, and comprehensive plugin system.
|
||||||
|
|
||||||
%package -n dms-cli
|
# %package -n dms-cli
|
||||||
Summary: DankMaterialShell CLI tool
|
# Summary: DankMaterialShell CLI tool
|
||||||
License: MIT
|
# License: MIT
|
||||||
URL: https://github.com/AvengeMedia/DankMaterialShell
|
# URL: https://github.com/AvengeMedia/DankMaterialShell
|
||||||
|
|
||||||
%description -n dms-cli
|
# %description -n dms-cli
|
||||||
Command-line interface for DankMaterialShell configuration and management.
|
# Command-line interface for DankMaterialShell configuration and management.
|
||||||
Provides native DBus bindings, NetworkManager integration, and system utilities.
|
# Provides native DBus bindings, NetworkManager integration, and system utilities.
|
||||||
|
|
||||||
%prep
|
# %prep
|
||||||
%setup -q -c -n dms-qml
|
# %setup -q -c -n dms-qml
|
||||||
|
|
||||||
# Download architecture-specific binaries during build
|
# # Download architecture-specific binaries during build
|
||||||
case "%{_arch}" in
|
# case "%{_arch}" in
|
||||||
x86_64)
|
# x86_64)
|
||||||
ARCH_SUFFIX="amd64"
|
# ARCH_SUFFIX="amd64"
|
||||||
;;
|
# ;;
|
||||||
aarch64)
|
# aarch64)
|
||||||
ARCH_SUFFIX="arm64"
|
# ARCH_SUFFIX="arm64"
|
||||||
;;
|
# ;;
|
||||||
*)
|
# *)
|
||||||
echo "Unsupported architecture: %{_arch}"
|
# echo "Unsupported architecture: %{_arch}"
|
||||||
exit 1
|
# exit 1
|
||||||
;;
|
# ;;
|
||||||
esac
|
# esac
|
||||||
|
|
||||||
wget -O %{_builddir}/dms-cli.gz "https://github.com/AvengeMedia/DankMaterialShell/releases/latest/download/dms-distropkg-${ARCH_SUFFIX}.gz" || {
|
# wget -O %{_builddir}/dms-cli.gz "https://github.com/AvengeMedia/DankMaterialShell/releases/latest/download/dms-distropkg-${ARCH_SUFFIX}.gz" || {
|
||||||
echo "Failed to download dms-cli for architecture %{_arch}"
|
# echo "Failed to download dms-cli for architecture %{_arch}"
|
||||||
exit 1
|
# exit 1
|
||||||
}
|
# }
|
||||||
gunzip -c %{_builddir}/dms-cli.gz > %{_builddir}/dms-cli
|
# gunzip -c %{_builddir}/dms-cli.gz > %{_builddir}/dms-cli
|
||||||
chmod +x %{_builddir}/dms-cli
|
# chmod +x %{_builddir}/dms-cli
|
||||||
|
|
||||||
%build
|
# %build
|
||||||
|
|
||||||
%install
|
# %install
|
||||||
install -Dm755 %{_builddir}/dms-cli %{buildroot}%{_bindir}/dms
|
# install -Dm755 %{_builddir}/dms-cli %{buildroot}%{_bindir}/dms
|
||||||
|
|
||||||
install -d %{buildroot}%{_datadir}/bash-completion/completions
|
# install -d %{buildroot}%{_datadir}/bash-completion/completions
|
||||||
install -d %{buildroot}%{_datadir}/zsh/site-functions
|
# install -d %{buildroot}%{_datadir}/zsh/site-functions
|
||||||
install -d %{buildroot}%{_datadir}/fish/vendor_completions.d
|
# install -d %{buildroot}%{_datadir}/fish/vendor_completions.d
|
||||||
%{_builddir}/dms-cli completion bash > %{buildroot}%{_datadir}/bash-completion/completions/dms || :
|
# %{_builddir}/dms-cli completion bash > %{buildroot}%{_datadir}/bash-completion/completions/dms || :
|
||||||
%{_builddir}/dms-cli completion zsh > %{buildroot}%{_datadir}/zsh/site-functions/_dms || :
|
# %{_builddir}/dms-cli completion zsh > %{buildroot}%{_datadir}/zsh/site-functions/_dms || :
|
||||||
%{_builddir}/dms-cli completion fish > %{buildroot}%{_datadir}/fish/vendor_completions.d/dms.fish || :
|
# %{_builddir}/dms-cli completion fish > %{buildroot}%{_datadir}/fish/vendor_completions.d/dms.fish || :
|
||||||
|
|
||||||
install -Dm644 assets/systemd/dms.service %{buildroot}%{_userunitdir}/dms.service
|
# install -Dm644 assets/systemd/dms.service %{buildroot}%{_userunitdir}/dms.service
|
||||||
|
|
||||||
install -Dm644 assets/dms-open.desktop %{buildroot}%{_datadir}/applications/dms-open.desktop
|
# install -Dm644 assets/dms-open.desktop %{buildroot}%{_datadir}/applications/dms-open.desktop
|
||||||
install -Dm644 assets/danklogo.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
# install -Dm644 assets/danklogo.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
||||||
|
|
||||||
install -dm755 %{buildroot}%{_datadir}/quickshell/dms
|
# install -dm755 %{buildroot}%{_datadir}/quickshell/dms
|
||||||
cp -r %{_builddir}/dms-qml/* %{buildroot}%{_datadir}/quickshell/dms/
|
# cp -r %{_builddir}/dms-qml/* %{buildroot}%{_datadir}/quickshell/dms/
|
||||||
|
|
||||||
rm -rf %{buildroot}%{_datadir}/quickshell/dms/.git*
|
# rm -rf %{buildroot}%{_datadir}/quickshell/dms/.git*
|
||||||
rm -f %{buildroot}%{_datadir}/quickshell/dms/.gitignore
|
# rm -f %{buildroot}%{_datadir}/quickshell/dms/.gitignore
|
||||||
rm -rf %{buildroot}%{_datadir}/quickshell/dms/.github
|
# rm -rf %{buildroot}%{_datadir}/quickshell/dms/.github
|
||||||
rm -rf %{buildroot}%{_datadir}/quickshell/dms/distro
|
# rm -rf %{buildroot}%{_datadir}/quickshell/dms/distro
|
||||||
|
|
||||||
echo "%{version}" > %{buildroot}%{_datadir}/quickshell/dms/VERSION
|
# echo "%{version}" > %{buildroot}%{_datadir}/quickshell/dms/VERSION
|
||||||
|
|
||||||
%posttrans
|
# %posttrans
|
||||||
if [ -d "%{_sysconfdir}/xdg/quickshell/dms" ]; then
|
# if [ -d "%{_sysconfdir}/xdg/quickshell/dms" ]; then
|
||||||
rmdir "%{_sysconfdir}/xdg/quickshell/dms" 2>/dev/null || true
|
# rmdir "%{_sysconfdir}/xdg/quickshell/dms" 2>/dev/null || true
|
||||||
rmdir "%{_sysconfdir}/xdg/quickshell" 2>/dev/null || true
|
# rmdir "%{_sysconfdir}/xdg/quickshell" 2>/dev/null || true
|
||||||
rmdir "%{_sysconfdir}/xdg" 2>/dev/null || true
|
# rmdir "%{_sysconfdir}/xdg" 2>/dev/null || true
|
||||||
fi
|
# fi
|
||||||
# Signal running DMS instances to reload
|
# # Signal running DMS instances to reload
|
||||||
pkill -USR1 -x dms >/dev/null 2>&1 || :
|
# pkill -USR1 -x dms >/dev/null 2>&1 || :
|
||||||
|
|
||||||
%files
|
# %files
|
||||||
%license LICENSE
|
# %license LICENSE
|
||||||
%doc README.md CONTRIBUTING.md
|
# %doc README.md CONTRIBUTING.md
|
||||||
%{_datadir}/quickshell/dms/
|
# %{_datadir}/quickshell/dms/
|
||||||
%{_userunitdir}/dms.service
|
# %{_userunitdir}/dms.service
|
||||||
%{_datadir}/applications/dms-open.desktop
|
# %{_datadir}/applications/dms-open.desktop
|
||||||
%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
# %{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
||||||
|
|
||||||
%files -n dms-cli
|
# %files -n dms-cli
|
||||||
%{_bindir}/dms
|
# %{_bindir}/dms
|
||||||
%{_datadir}/bash-completion/completions/dms
|
# %{_datadir}/bash-completion/completions/dms
|
||||||
%{_datadir}/zsh/site-functions/_dms
|
# %{_datadir}/zsh/site-functions/_dms
|
||||||
%{_datadir}/fish/vendor_completions.d/dms.fish
|
# %{_datadir}/fish/vendor_completions.d/dms.fish
|
||||||
|
|
||||||
%changelog
|
# %changelog
|
||||||
* CHANGELOG_DATE_PLACEHOLDER AvengeMedia <contact@avengemedia.com> - VERSION_PLACEHOLDER-1
|
# * CHANGELOG_DATE_PLACEHOLDER AvengeMedia <contact@avengemedia.com> - VERSION_PLACEHOLDER-1
|
||||||
- Stable release VERSION_PLACEHOLDER
|
# - Stable release VERSION_PLACEHOLDER
|
||||||
- Built from GitHub release
|
# - Built from GitHub release
|
||||||
SPECEOF
|
# SPECEOF
|
||||||
|
|
||||||
sed -i "s/VERSION_PLACEHOLDER/${VERSION}/g" ~/rpmbuild/SPECS/dms.spec
|
# sed -i "s/VERSION_PLACEHOLDER/${VERSION}/g" ~/rpmbuild/SPECS/dms.spec
|
||||||
sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" ~/rpmbuild/SPECS/dms.spec
|
# sed -i "s/CHANGELOG_DATE_PLACEHOLDER/${CHANGELOG_DATE}/g" ~/rpmbuild/SPECS/dms.spec
|
||||||
|
|
||||||
- name: Build SRPM
|
# - name: Build SRPM
|
||||||
id: build
|
# id: build
|
||||||
run: |
|
# run: |
|
||||||
cd ~/rpmbuild/SPECS
|
# cd ~/rpmbuild/SPECS
|
||||||
rpmbuild -bs dms.spec
|
# rpmbuild -bs dms.spec
|
||||||
|
|
||||||
SRPM=$(ls ~/rpmbuild/SRPMS/*.src.rpm | tail -n 1)
|
# SRPM=$(ls ~/rpmbuild/SRPMS/*.src.rpm | tail -n 1)
|
||||||
SRPM_NAME=$(basename "$SRPM")
|
# SRPM_NAME=$(basename "$SRPM")
|
||||||
|
|
||||||
echo "srpm_path=$SRPM" >> $GITHUB_OUTPUT
|
# echo "srpm_path=$SRPM" >> $GITHUB_OUTPUT
|
||||||
echo "srpm_name=$SRPM_NAME" >> $GITHUB_OUTPUT
|
# echo "srpm_name=$SRPM_NAME" >> $GITHUB_OUTPUT
|
||||||
echo "SRPM built: $SRPM_NAME"
|
# echo "SRPM built: $SRPM_NAME"
|
||||||
|
|
||||||
- name: Upload SRPM artifact
|
# - name: Upload SRPM artifact
|
||||||
uses: actions/upload-artifact@v4
|
# uses: actions/upload-artifact@v4
|
||||||
with:
|
# with:
|
||||||
name: dms-stable-srpm-${{ steps.version.outputs.version }}
|
# name: dms-stable-srpm-${{ steps.version.outputs.version }}
|
||||||
path: ${{ steps.build.outputs.srpm_path }}
|
# path: ${{ steps.build.outputs.srpm_path }}
|
||||||
retention-days: 90
|
# retention-days: 90
|
||||||
|
|
||||||
- name: Install Copr CLI
|
# - name: Install Copr CLI
|
||||||
run: |
|
# run: |
|
||||||
sudo apt-get install -y python3-pip
|
# sudo apt-get install -y python3-pip
|
||||||
pip3 install copr-cli
|
# pip3 install copr-cli
|
||||||
|
|
||||||
mkdir -p ~/.config
|
# mkdir -p ~/.config
|
||||||
cat > ~/.config/copr << EOF
|
# cat > ~/.config/copr << EOF
|
||||||
[copr-cli]
|
# [copr-cli]
|
||||||
login = ${{ secrets.COPR_LOGIN }}
|
# login = ${{ secrets.COPR_LOGIN }}
|
||||||
username = avengemedia
|
# username = avengemedia
|
||||||
token = ${{ secrets.COPR_TOKEN }}
|
# token = ${{ secrets.COPR_TOKEN }}
|
||||||
copr_url = https://copr.fedorainfracloud.org
|
# copr_url = https://copr.fedorainfracloud.org
|
||||||
EOF
|
# EOF
|
||||||
chmod 600 ~/.config/copr
|
# chmod 600 ~/.config/copr
|
||||||
|
|
||||||
- name: Upload to Copr
|
# - name: Upload to Copr
|
||||||
run: |
|
# run: |
|
||||||
SRPM="${{ steps.build.outputs.srpm_path }}"
|
# SRPM="${{ steps.build.outputs.srpm_path }}"
|
||||||
VERSION="${{ steps.version.outputs.version }}"
|
# VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
|
||||||
echo "Uploading SRPM to avengemedia/dms..."
|
# echo "Uploading SRPM to avengemedia/dms..."
|
||||||
BUILD_OUTPUT=$(copr-cli build avengemedia/dms "$SRPM" --nowait 2>&1)
|
# BUILD_OUTPUT=$(copr-cli build avengemedia/dms "$SRPM" --nowait 2>&1)
|
||||||
echo "$BUILD_OUTPUT"
|
# echo "$BUILD_OUTPUT"
|
||||||
|
|
||||||
BUILD_ID=$(echo "$BUILD_OUTPUT" | grep -oP 'Build was added to.*\K[0-9]+' || echo "unknown")
|
# BUILD_ID=$(echo "$BUILD_OUTPUT" | grep -oP 'Build was added to.*\K[0-9]+' || echo "unknown")
|
||||||
|
|
||||||
if [ "$BUILD_ID" != "unknown" ]; then
|
# if [ "$BUILD_ID" != "unknown" ]; then
|
||||||
echo "Build submitted: https://copr.fedorainfracloud.org/coprs/avengemedia/dms/build/$BUILD_ID/"
|
# echo "Build submitted: https://copr.fedorainfracloud.org/coprs/avengemedia/dms/build/$BUILD_ID/"
|
||||||
fi
|
# fi
|
||||||
|
|||||||
33
.github/workflows/run-obs.yml
vendored
33
.github/workflows/run-obs.yml
vendored
@@ -215,13 +215,44 @@ jobs:
|
|||||||
# Update openSUSE dms spec (stable only)
|
# Update openSUSE dms spec (stable only)
|
||||||
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec
|
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec
|
||||||
|
|
||||||
# Update Debian _service files
|
# Update openSUSE spec changelog
|
||||||
|
DATE_STR=$(date "+%a %b %d %Y")
|
||||||
|
CHANGELOG_ENTRY="* $DATE_STR AvengeMedia <maintainer@avengemedia.com> - ${VERSION_NO_V}-1\\n- Update to stable $VERSION release\\n- Bug fixes and improvements"
|
||||||
|
sed -i "/%changelog/a\\$CHANGELOG_ENTRY\\n" distro/opensuse/dms.spec
|
||||||
|
|
||||||
|
# Update Debian _service files (both tar_scm and download_url formats)
|
||||||
for service in distro/debian/*/_service; do
|
for service in distro/debian/*/_service; do
|
||||||
if [[ -f "$service" ]]; then
|
if [[ -f "$service" ]]; then
|
||||||
|
# Update tar_scm revision parameter (for dms-git)
|
||||||
sed -i "s|<param name=\"revision\">v[0-9.]*</param>|<param name=\"revision\">$VERSION</param>|" "$service"
|
sed -i "s|<param name=\"revision\">v[0-9.]*</param>|<param name=\"revision\">$VERSION</param>|" "$service"
|
||||||
|
|
||||||
|
# Update download_url paths (for dms stable)
|
||||||
|
sed -i "s|/v[0-9.]\+/|/$VERSION/|g" "$service"
|
||||||
|
sed -i "s|/tags/v[0-9.]\+\.tar\.gz|/tags/$VERSION.tar.gz|g" "$service"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Update Debian changelog for dms stable
|
||||||
|
if [[ -f "distro/debian/dms/debian/changelog" ]]; then
|
||||||
|
CHANGELOG_DATE=$(date -R)
|
||||||
|
TEMP_CHANGELOG=$(mktemp)
|
||||||
|
|
||||||
|
cat > "$TEMP_CHANGELOG" << EOF
|
||||||
|
dms ($VERSION_NO_V) stable; urgency=medium
|
||||||
|
|
||||||
|
* Update to $VERSION stable release
|
||||||
|
* Bug fixes and improvements
|
||||||
|
|
||||||
|
-- Avenge Media <AvengeMedia.US@gmail.com> $CHANGELOG_DATE
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat "distro/debian/dms/debian/changelog" >> "$TEMP_CHANGELOG"
|
||||||
|
mv "$TEMP_CHANGELOG" "distro/debian/dms/debian/changelog"
|
||||||
|
|
||||||
|
echo "✓ Updated Debian changelog to $VERSION_NO_V"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
|
|||||||
6
CHANGELOG.MD
Normal file
6
CHANGELOG.MD
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# 1.2.0
|
||||||
|
|
||||||
|
- Added clipboard and clipboard history integration
|
||||||
|
- Added swipe to dismiss notification popups and from center
|
||||||
|
- Added paste from clipboard history view - requires wtype
|
||||||
|
- Optimize surface damage of OSD & Toast
|
||||||
@@ -340,7 +340,7 @@ func (a *ArchDistribution) InstallPackages(ctx context.Context, dependencies []d
|
|||||||
a.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
a.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.EnableDMSService(ctx); err != nil {
|
if err := a.EnableDMSService(ctx, wm); err != nil {
|
||||||
a.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
a.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -566,12 +566,24 @@ TERMINAL=%s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BaseDistribution) EnableDMSService(ctx context.Context) error {
|
func (b *BaseDistribution) EnableDMSService(ctx context.Context, wm deps.WindowManager) error {
|
||||||
cmd := exec.CommandContext(ctx, "systemctl", "--user", "enable", "--now", "dms")
|
cmd := exec.CommandContext(ctx, "systemctl", "--user", "enable", "--now", "dms")
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
return fmt.Errorf("failed to enable dms service: %w", err)
|
return fmt.Errorf("failed to enable dms service: %w", err)
|
||||||
}
|
}
|
||||||
b.log("Enabled dms systemd user service")
|
b.log("Enabled dms systemd user service")
|
||||||
|
|
||||||
|
switch wm {
|
||||||
|
case deps.WindowManagerNiri:
|
||||||
|
if err := exec.CommandContext(ctx, "systemctl", "--user", "add-wants", "niri.service", "dms").Run(); err != nil {
|
||||||
|
b.log("Warning: failed to add dms as a want for niri.service")
|
||||||
|
}
|
||||||
|
case deps.WindowManagerHyprland:
|
||||||
|
if err := exec.CommandContext(ctx, "systemctl", "--user", "add-wants", "hyprland-session.target", "dms").Run(); err != nil {
|
||||||
|
b.log("Warning: failed to add dms as a want for hyprland-session.target")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ func (d *DebianDistribution) InstallPackages(ctx context.Context, dependencies [
|
|||||||
d.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
d.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.EnableDMSService(ctx); err != nil {
|
if err := d.EnableDMSService(ctx, wm); err != nil {
|
||||||
d.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
d.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ func (f *FedoraDistribution) InstallPackages(ctx context.Context, dependencies [
|
|||||||
f.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
f.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := f.EnableDMSService(ctx); err != nil {
|
if err := f.EnableDMSService(ctx, wm); err != nil {
|
||||||
f.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
f.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -407,7 +407,7 @@ func (g *GentooDistribution) InstallPackages(ctx context.Context, dependencies [
|
|||||||
g.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
g.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := g.EnableDMSService(ctx); err != nil {
|
if err := g.EnableDMSService(ctx, wm); err != nil {
|
||||||
g.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
g.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ func (o *OpenSUSEDistribution) InstallPackages(ctx context.Context, dependencies
|
|||||||
o.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
o.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := o.EnableDMSService(ctx); err != nil {
|
if err := o.EnableDMSService(ctx, wm); err != nil {
|
||||||
o.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
o.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ func (u *UbuntuDistribution) InstallPackages(ctx context.Context, dependencies [
|
|||||||
u.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
u.log(fmt.Sprintf("Warning: failed to write window manager config: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := u.EnableDMSService(ctx); err != nil {
|
if err := u.EnableDMSService(ctx, wm); err != nil {
|
||||||
u.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
u.log(fmt.Sprintf("Warning: failed to enable dms service: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/keybinds"
|
||||||
@@ -156,6 +157,7 @@ func (n *NiriProvider) convertKeybind(kb *NiriKeyBinding, subcategory string, co
|
|||||||
Subcategory: subcategory,
|
Subcategory: subcategory,
|
||||||
Source: source,
|
Source: source,
|
||||||
HideOnOverlay: kb.HideOnOverlay,
|
HideOnOverlay: kb.HideOnOverlay,
|
||||||
|
CooldownMs: kb.CooldownMs,
|
||||||
}
|
}
|
||||||
|
|
||||||
if source == "dms" && conflicts != nil {
|
if source == "dms" && conflicts != nil {
|
||||||
@@ -313,7 +315,9 @@ func (n *NiriProvider) extractOptions(node *document.Node) map[string]any {
|
|||||||
opts["repeat"] = val.String() == "true"
|
opts["repeat"] = val.String() == "true"
|
||||||
}
|
}
|
||||||
if val, ok := node.Properties.Get("cooldown-ms"); ok {
|
if val, ok := node.Properties.Get("cooldown-ms"); ok {
|
||||||
opts["cooldown-ms"] = val.String()
|
if ms, err := strconv.Atoi(val.String()); err == nil {
|
||||||
|
opts["cooldown-ms"] = ms
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if val, ok := node.Properties.Get("allow-when-locked"); ok {
|
if val, ok := node.Properties.Get("allow-when-locked"); ok {
|
||||||
opts["allow-when-locked"] = val.String() == "true"
|
opts["allow-when-locked"] = val.String() == "true"
|
||||||
@@ -339,7 +343,14 @@ func (n *NiriProvider) buildBindNode(bind *overrideBind) *document.Node {
|
|||||||
node.AddProperty("repeat", false, "")
|
node.AddProperty("repeat", false, "")
|
||||||
}
|
}
|
||||||
if v, ok := bind.Options["cooldown-ms"]; ok {
|
if v, ok := bind.Options["cooldown-ms"]; ok {
|
||||||
node.AddProperty("cooldown-ms", v, "")
|
switch val := v.(type) {
|
||||||
|
case int:
|
||||||
|
node.AddProperty("cooldown-ms", val, "")
|
||||||
|
case string:
|
||||||
|
if ms, err := strconv.Atoi(val); err == nil {
|
||||||
|
node.AddProperty("cooldown-ms", ms, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if v, ok := bind.Options["allow-when-locked"]; ok && v == true {
|
if v, ok := bind.Options["allow-when-locked"]; ok && v == true {
|
||||||
node.AddProperty("allow-when-locked", true, "")
|
node.AddProperty("allow-when-locked", true, "")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sblinch/kdl-go"
|
"github.com/sblinch/kdl-go"
|
||||||
@@ -17,6 +18,7 @@ type NiriKeyBinding struct {
|
|||||||
Args []string
|
Args []string
|
||||||
Description string
|
Description string
|
||||||
HideOnOverlay bool
|
HideOnOverlay bool
|
||||||
|
CooldownMs int
|
||||||
Source string
|
Source string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +277,7 @@ func (p *NiriParser) parseKeybindNode(node *document.Node, _ string) *NiriKeyBin
|
|||||||
|
|
||||||
var description string
|
var description string
|
||||||
var hideOnOverlay bool
|
var hideOnOverlay bool
|
||||||
|
var cooldownMs int
|
||||||
if node.Properties != nil {
|
if node.Properties != nil {
|
||||||
if val, ok := node.Properties.Get("hotkey-overlay-title"); ok {
|
if val, ok := node.Properties.Get("hotkey-overlay-title"); ok {
|
||||||
switch val.ValueString() {
|
switch val.ValueString() {
|
||||||
@@ -284,6 +287,9 @@ func (p *NiriParser) parseKeybindNode(node *document.Node, _ string) *NiriKeyBin
|
|||||||
description = val.ValueString()
|
description = val.ValueString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if val, ok := node.Properties.Get("cooldown-ms"); ok {
|
||||||
|
cooldownMs, _ = strconv.Atoi(val.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &NiriKeyBinding{
|
return &NiriKeyBinding{
|
||||||
@@ -293,6 +299,7 @@ func (p *NiriParser) parseKeybindNode(node *document.Node, _ string) *NiriKeyBin
|
|||||||
Args: args,
|
Args: args,
|
||||||
Description: description,
|
Description: description,
|
||||||
HideOnOverlay: hideOnOverlay,
|
HideOnOverlay: hideOnOverlay,
|
||||||
|
CooldownMs: cooldownMs,
|
||||||
Source: p.currentSource,
|
Source: p.currentSource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ type Keybind struct {
|
|||||||
Subcategory string `json:"subcat,omitempty"`
|
Subcategory string `json:"subcat,omitempty"`
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
HideOnOverlay bool `json:"hideOnOverlay,omitempty"`
|
HideOnOverlay bool `json:"hideOnOverlay,omitempty"`
|
||||||
|
CooldownMs int `json:"cooldownMs,omitempty"`
|
||||||
Conflict *Keybind `json:"conflict,omitempty"`
|
Conflict *Keybind `json:"conflict,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,19 @@
|
|||||||
<service name="download_url">
|
<service name="download_url">
|
||||||
<param name="protocol">https</param>
|
<param name="protocol">https</param>
|
||||||
<param name="host">github.com</param>
|
<param name="host">github.com</param>
|
||||||
<param name="path">/AvengeMedia/DankMaterialShell/archive/refs/tags/v1.0.0.tar.gz</param>
|
<param name="path">/AvengeMedia/DankMaterialShell/archive/refs/tags/v1.0.2.tar.gz</param>
|
||||||
<param name="filename">dms-source.tar.gz</param>
|
<param name="filename">dms-source.tar.gz</param>
|
||||||
</service>
|
</service>
|
||||||
<!-- Download amd64 binary -->
|
<!-- Download amd64 binary -->
|
||||||
<service name="download_url">
|
<service name="download_url">
|
||||||
<param name="protocol">https</param>
|
<param name="protocol">https</param>
|
||||||
<param name="host">github.com</param>
|
<param name="host">github.com</param>
|
||||||
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.0/dms-distropkg-amd64.gz</param>
|
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.2/dms-distropkg-amd64.gz</param>
|
||||||
</service>
|
</service>
|
||||||
<!-- Download arm64 binary -->
|
<!-- Download arm64 binary -->
|
||||||
<service name="download_url">
|
<service name="download_url">
|
||||||
<param name="protocol">https</param>
|
<param name="protocol">https</param>
|
||||||
<param name="host">github.com</param>
|
<param name="host">github.com</param>
|
||||||
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.0/dms-distropkg-arm64.gz</param>
|
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.2/dms-distropkg-arm64.gz</param>
|
||||||
</service>
|
</service>
|
||||||
</services>
|
</services>
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
dms (1.0.2) stable; urgency=medium
|
||||||
|
|
||||||
|
* Update to v1.0.2 stable release
|
||||||
|
* Bug fixes and improvements
|
||||||
|
|
||||||
|
-- Avenge Media <AvengeMedia.US@gmail.com> Thu, 12 Dec 2025 14:30:00 -0500
|
||||||
|
|
||||||
dms (1.0.0) stable; urgency=medium
|
dms (1.0.0) stable; urgency=medium
|
||||||
|
|
||||||
* Update to v1.0.0 release
|
* Update to v1.0.0 release
|
||||||
|
|||||||
@@ -36,17 +36,19 @@ override_dh_auto_build:
|
|||||||
fi
|
fi
|
||||||
chmod +x dms
|
chmod +x dms
|
||||||
|
|
||||||
|
# Extract source if needed
|
||||||
if [ ! -d DankMaterialShell-$(UPSTREAM_VERSION) ]; then \
|
if [ ! -d DankMaterialShell-$(UPSTREAM_VERSION) ]; then \
|
||||||
if [ -f ../SOURCES/dms-source.tar.gz ]; then \
|
if [ -f ../SOURCES/dms-source.tar.gz ]; then \
|
||||||
tar -xzf ../SOURCES/dms-source.tar.gz; \
|
tar -xzf ../SOURCES/dms-source.tar.gz; \
|
||||||
elif [ -f dms-source.tar.gz ]; then \
|
elif [ -f dms-source.tar.gz ]; then \
|
||||||
tar -xzf dms-source.tar.gz; \
|
tar -xzf dms-source.tar.gz; \
|
||||||
fi; \
|
fi; \
|
||||||
|
fi
|
||||||
|
# Rename directory to match expected version
|
||||||
SOURCE_DIR=$$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" ! -name "DankMaterialShell-$(UPSTREAM_VERSION)" | head -n1); \
|
SOURCE_DIR=$$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" ! -name "DankMaterialShell-$(UPSTREAM_VERSION)" | head -n1); \
|
||||||
if [ -n "$$SOURCE_DIR" ] && [ "$$SOURCE_DIR" != "./DankMaterialShell-$(UPSTREAM_VERSION)" ]; then \
|
if [ -n "$$SOURCE_DIR" ]; then \
|
||||||
echo "Renaming $$SOURCE_DIR to DankMaterialShell-$(UPSTREAM_VERSION)"; \
|
echo "Renaming $$SOURCE_DIR to DankMaterialShell-$(UPSTREAM_VERSION)"; \
|
||||||
mv "$$SOURCE_DIR" DankMaterialShell-$(UPSTREAM_VERSION); \
|
mv "$$SOURCE_DIR" DankMaterialShell-$(UPSTREAM_VERSION); \
|
||||||
fi; \
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
@@ -54,13 +56,11 @@ override_dh_auto_install:
|
|||||||
install -Dm755 dms debian/dms/usr/bin/dms
|
install -Dm755 dms debian/dms/usr/bin/dms
|
||||||
|
|
||||||
mkdir -p debian/dms/usr/share/quickshell/dms debian/dms/usr/lib/systemd/user
|
mkdir -p debian/dms/usr/share/quickshell/dms debian/dms/usr/lib/systemd/user
|
||||||
# Handle directory name mismatch again for install step if needed
|
# Ensure directory has correct version name for install step
|
||||||
if [ ! -d DankMaterialShell-$(UPSTREAM_VERSION) ]; then \
|
SOURCE_DIR=$$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" ! -name "DankMaterialShell-$(UPSTREAM_VERSION)" | head -n1); \
|
||||||
SOURCE_DIR=$$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" | head -n1); \
|
|
||||||
if [ -n "$$SOURCE_DIR" ]; then \
|
if [ -n "$$SOURCE_DIR" ]; then \
|
||||||
echo "Renaming $$SOURCE_DIR to DankMaterialShell-$(UPSTREAM_VERSION) for install"; \
|
echo "Renaming $$SOURCE_DIR to DankMaterialShell-$(UPSTREAM_VERSION) for install"; \
|
||||||
mv "$$SOURCE_DIR" DankMaterialShell-$(UPSTREAM_VERSION); \
|
mv "$$SOURCE_DIR" DankMaterialShell-$(UPSTREAM_VERSION); \
|
||||||
fi; \
|
|
||||||
fi
|
fi
|
||||||
if [ -d DankMaterialShell-$(UPSTREAM_VERSION) ]; then \
|
if [ -d DankMaterialShell-$(UPSTREAM_VERSION) ]; then \
|
||||||
cp -r DankMaterialShell-$(UPSTREAM_VERSION)/quickshell/* debian/dms/usr/share/quickshell/dms/; \
|
cp -r DankMaterialShell-$(UPSTREAM_VERSION)/quickshell/* debian/dms/usr/share/quickshell/dms/; \
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ VCS: {{{ git_repo_vcs }}}
|
|||||||
Source0: {{{ git_repo_pack }}}
|
Source0: {{{ git_repo_pack }}}
|
||||||
|
|
||||||
BuildRequires: git-core
|
BuildRequires: git-core
|
||||||
BuildRequires: rpkg
|
|
||||||
# For the _tmpfilesdir macro.
|
# For the _tmpfilesdir macro.
|
||||||
BuildRequires: systemd-rpm-macros
|
BuildRequires: systemd-rpm-macros
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ VCS: {{{ git_repo_vcs }}}
|
|||||||
Source0: {{{ git_repo_pack }}}
|
Source0: {{{ git_repo_pack }}}
|
||||||
|
|
||||||
BuildRequires: git-core
|
BuildRequires: git-core
|
||||||
BuildRequires: rpkg
|
|
||||||
BuildRequires: gzip
|
BuildRequires: gzip
|
||||||
BuildRequires: golang >= 1.24
|
BuildRequires: golang >= 1.24
|
||||||
BuildRequires: make
|
BuildRequires: make
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
%global debug_package %{nil}
|
%global debug_package %{nil}
|
||||||
|
|
||||||
Name: dms
|
Name: dms
|
||||||
Version: 1.0.0
|
Version: 1.0.2
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: DankMaterialShell - Material 3 inspired shell for Wayland compositors
|
Summary: DankMaterialShell - Material 3 inspired shell for Wayland compositors
|
||||||
|
|
||||||
@@ -105,6 +105,10 @@ pkill -USR1 -x dms >/dev/null 2>&1 || :
|
|||||||
%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Dec 12 2025 AvengeMedia <maintainer@avengemedia.com> - 1.0.2-1
|
||||||
|
- Update to stable v1.0.2 release
|
||||||
|
- Bug fixes and improvements
|
||||||
|
|
||||||
* Fri Nov 22 2025 AvengeMedia <maintainer@avengemedia.com> - 0.6.2-1
|
* Fri Nov 22 2025 AvengeMedia <maintainer@avengemedia.com> - 0.6.2-1
|
||||||
- Stable release build with pre-built binaries
|
- Stable release build with pre-built binaries
|
||||||
- Multi-arch support (x86_64, aarch64)
|
- Multi-arch support (x86_64, aarch64)
|
||||||
|
|||||||
@@ -311,6 +311,12 @@ Singleton {
|
|||||||
property bool modalDarkenBackground: true
|
property bool modalDarkenBackground: true
|
||||||
|
|
||||||
property bool lockScreenShowPowerActions: true
|
property bool lockScreenShowPowerActions: true
|
||||||
|
property bool lockScreenShowSystemIcons: true
|
||||||
|
property bool lockScreenShowTime: true
|
||||||
|
property bool lockScreenShowDate: true
|
||||||
|
property bool lockScreenShowProfileImage: true
|
||||||
|
property bool lockScreenShowPasswordField: true
|
||||||
|
|
||||||
property bool enableFprint: false
|
property bool enableFprint: false
|
||||||
property int maxFprintTries: 15
|
property int maxFprintTries: 15
|
||||||
property bool fprintdAvailable: false
|
property bool fprintdAvailable: false
|
||||||
|
|||||||
@@ -210,6 +210,11 @@ var SPEC = {
|
|||||||
modalDarkenBackground: { def: true },
|
modalDarkenBackground: { def: true },
|
||||||
|
|
||||||
lockScreenShowPowerActions: { def: true },
|
lockScreenShowPowerActions: { def: true },
|
||||||
|
lockScreenShowSystemIcons: { def: true },
|
||||||
|
lockScreenShowTime: { def: true },
|
||||||
|
lockScreenShowDate: { def: true },
|
||||||
|
lockScreenShowProfileImage: { def: true },
|
||||||
|
lockScreenShowPasswordField: { def: true },
|
||||||
enableFprint: { def: false },
|
enableFprint: { def: false },
|
||||||
maxFprintTries: { def: 15 },
|
maxFprintTries: { def: 15 },
|
||||||
fprintdAvailable: { def: false, persist: false },
|
fprintdAvailable: { def: false, persist: false },
|
||||||
|
|||||||
@@ -158,5 +158,6 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
visible: modal.showKeyboardHints
|
visible: modal.showKeyboardHints
|
||||||
|
wtypeAvailable: modal.wtypeAvailable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
|
import Quickshell.Io
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -26,6 +27,50 @@ DankModal {
|
|||||||
property int activeImageLoads: 0
|
property int activeImageLoads: 0
|
||||||
readonly property int maxConcurrentLoads: 3
|
readonly property int maxConcurrentLoads: 3
|
||||||
readonly property bool clipboardAvailable: DMSService.isConnected && DMSService.capabilities.includes("clipboard")
|
readonly property bool clipboardAvailable: DMSService.isConnected && DMSService.capabilities.includes("clipboard")
|
||||||
|
property bool wtypeAvailable: false
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: wtypeCheck
|
||||||
|
command: ["which", "wtype"]
|
||||||
|
running: true
|
||||||
|
onExited: exitCode => {
|
||||||
|
clipboardHistoryModal.wtypeAvailable = (exitCode === 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: wtypeProcess
|
||||||
|
command: ["wtype", "-M", "ctrl", "-P", "v", "-p", "v", "-m", "ctrl"]
|
||||||
|
running: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: pasteTimer
|
||||||
|
interval: 200
|
||||||
|
repeat: false
|
||||||
|
onTriggered: wtypeProcess.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function pasteSelected() {
|
||||||
|
if (!keyboardNavigationActive || clipboardEntries.length === 0 || selectedIndex < 0 || selectedIndex >= clipboardEntries.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!wtypeAvailable) {
|
||||||
|
ToastService.showError(I18n.tr("wtype not available - install wtype for paste support"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const entry = clipboardEntries[selectedIndex];
|
||||||
|
DMSService.sendRequest("clipboard.copyEntry", {
|
||||||
|
"id": entry.id
|
||||||
|
}, function (response) {
|
||||||
|
if (response.error) {
|
||||||
|
ToastService.showError(I18n.tr("Failed to copy entry"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instantClose();
|
||||||
|
pasteTimer.start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function updateFilteredModel() {
|
function updateFilteredModel() {
|
||||||
const query = searchText.trim();
|
const query = searchText.trim();
|
||||||
|
|||||||
@@ -114,11 +114,21 @@ QtObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.modifiers & Qt.ShiftModifier && event.key === Qt.Key_Delete) {
|
if (event.modifiers & Qt.ShiftModifier) {
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_Delete:
|
||||||
modal.clearAll();
|
modal.clearAll();
|
||||||
modal.hide();
|
modal.hide();
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
return;
|
return;
|
||||||
|
case Qt.Key_Return:
|
||||||
|
case Qt.Key_Enter:
|
||||||
|
if (modal.keyboardNavigationActive) {
|
||||||
|
modal.pasteSelected();
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modal.keyboardNavigationActive) {
|
if (modal.keyboardNavigationActive) {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import qs.Widgets
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
id: keyboardHints
|
id: keyboardHints
|
||||||
|
|
||||||
readonly property string hintsText: I18n.tr("Shift+Del: Clear All • Esc: Close")
|
property bool wtypeAvailable: false
|
||||||
|
readonly property string hintsText: wtypeAvailable ? I18n.tr("Shift+Enter: Paste • Shift+Del: Clear All • Esc: Close") : I18n.tr("Shift+Del: Clear All • Esc: Close")
|
||||||
|
|
||||||
height: ClipboardConstants.keyboardHintsHeight
|
height: ClipboardConstants.keyboardHintsHeight
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
|
|||||||
@@ -79,10 +79,12 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (source) {
|
if (!source) {
|
||||||
|
isInitialized = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
|
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
|
||||||
setWallpaperImmediate(formattedSource);
|
setWallpaperImmediate(formattedSource);
|
||||||
}
|
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,22 +95,23 @@ Variants {
|
|||||||
property bool useNextForEffect: false
|
property bool useNextForEffect: false
|
||||||
|
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
const isColor = source.startsWith("#");
|
if (!source || source.startsWith("#")) {
|
||||||
|
setWallpaperImmediate("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
|
||||||
|
|
||||||
if (!source) {
|
|
||||||
setWallpaperImmediate("");
|
|
||||||
} else if (isColor) {
|
|
||||||
setWallpaperImmediate("");
|
|
||||||
} else {
|
|
||||||
if (!isInitialized || !currentWallpaper.source) {
|
if (!isInitialized || !currentWallpaper.source) {
|
||||||
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source);
|
setWallpaperImmediate(formattedSource);
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
} else if (CompositorService.isNiri && SessionData.isSwitchingMode) {
|
return;
|
||||||
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source);
|
|
||||||
} else {
|
|
||||||
changeWallpaper(source.startsWith("file://") ? source : "file://" + source);
|
|
||||||
}
|
}
|
||||||
|
if (CompositorService.isNiri && SessionData.isSwitchingMode) {
|
||||||
|
setWallpaperImmediate(formattedSource);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
changeWallpaper(formattedSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWallpaperImmediate(newSource) {
|
function setWallpaperImmediate(newSource) {
|
||||||
@@ -120,15 +123,18 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startTransition() {
|
function startTransition() {
|
||||||
currentWallpaper.cache = true;
|
|
||||||
nextWallpaper.cache = true;
|
|
||||||
root.useNextForEffect = true;
|
root.useNextForEffect = true;
|
||||||
root.effectActive = true;
|
root.effectActive = true;
|
||||||
if (srcNext.scheduleUpdate)
|
if (srcNext.scheduleUpdate)
|
||||||
srcNext.scheduleUpdate();
|
srcNext.scheduleUpdate();
|
||||||
Qt.callLater(() => {
|
transitionDelayTimer.start();
|
||||||
transitionAnimation.start();
|
}
|
||||||
});
|
|
||||||
|
Timer {
|
||||||
|
id: transitionDelayTimer
|
||||||
|
interval: 16
|
||||||
|
repeat: false
|
||||||
|
onTriggered: transitionAnimation.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeWallpaper(newPath) {
|
function changeWallpaper(newPath) {
|
||||||
@@ -143,7 +149,6 @@ Variants {
|
|||||||
currentWallpaper.source = nextWallpaper.source;
|
currentWallpaper.source = nextWallpaper.source;
|
||||||
nextWallpaper.source = "";
|
nextWallpaper.source = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentWallpaper.source) {
|
if (!currentWallpaper.source) {
|
||||||
setWallpaperImmediate(newPath);
|
setWallpaperImmediate(newPath);
|
||||||
return;
|
return;
|
||||||
@@ -151,10 +156,9 @@ Variants {
|
|||||||
|
|
||||||
nextWallpaper.source = newPath;
|
nextWallpaper.source = newPath;
|
||||||
|
|
||||||
if (nextWallpaper.status === Image.Ready) {
|
if (nextWallpaper.status === Image.Ready)
|
||||||
root.startTransition();
|
root.startTransition();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -166,9 +170,9 @@ Variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property real screenScale: CompositorService.getScreenScale(modelData)
|
readonly property int maxTextureSize: 8192
|
||||||
property int physicalWidth: Math.round(modelData.width * screenScale)
|
property int textureWidth: Math.min(modelData.width, maxTextureSize)
|
||||||
property int physicalHeight: Math.round(modelData.height * screenScale)
|
property int textureHeight: Math.min(modelData.height, maxTextureSize)
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: currentWallpaper
|
id: currentWallpaper
|
||||||
@@ -178,7 +182,7 @@ Variants {
|
|||||||
asynchronous: true
|
asynchronous: true
|
||||||
smooth: true
|
smooth: true
|
||||||
cache: true
|
cache: true
|
||||||
sourceSize: Qt.size(root.physicalWidth, root.physicalHeight)
|
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SettingsData.wallpaperFillMode)
|
fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SettingsData.wallpaperFillMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,8 +193,8 @@ Variants {
|
|||||||
opacity: 0
|
opacity: 0
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
smooth: true
|
smooth: true
|
||||||
cache: false
|
cache: true
|
||||||
sourceSize: Qt.size(root.physicalWidth, root.physicalHeight)
|
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SettingsData.wallpaperFillMode)
|
fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SettingsData.wallpaperFillMode)
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
@@ -209,7 +213,7 @@ Variants {
|
|||||||
live: root.effectActive
|
live: root.effectActive
|
||||||
mipmap: false
|
mipmap: false
|
||||||
recursive: false
|
recursive: false
|
||||||
textureSize: root.effectActive ? Qt.size(root.physicalWidth, root.physicalHeight) : Qt.size(1, 1)
|
textureSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -265,19 +269,12 @@ Variants {
|
|||||||
duration: 1000
|
duration: 1000
|
||||||
easing.type: Easing.InOutCubic
|
easing.type: Easing.InOutCubic
|
||||||
onFinished: {
|
onFinished: {
|
||||||
if (nextWallpaper.source && nextWallpaper.status === Image.Ready) {
|
if (nextWallpaper.source && nextWallpaper.status === Image.Ready)
|
||||||
currentWallpaper.source = nextWallpaper.source;
|
currentWallpaper.source = nextWallpaper.source;
|
||||||
}
|
|
||||||
root.useNextForEffect = false;
|
root.useNextForEffect = false;
|
||||||
Qt.callLater(() => {
|
|
||||||
nextWallpaper.source = "";
|
nextWallpaper.source = "";
|
||||||
Qt.callLater(() => {
|
|
||||||
root.effectActive = false;
|
|
||||||
currentWallpaper.cache = true;
|
|
||||||
nextWallpaper.cache = false;
|
|
||||||
root.transitionProgress = 0.0;
|
root.transitionProgress = 0.0;
|
||||||
});
|
root.effectActive = false;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ Item {
|
|||||||
anchors.verticalCenterOffset: -100
|
anchors.verticalCenterOffset: -100
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 140
|
height: 140
|
||||||
|
visible: SettingsData.lockScreenShowTime
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: clockText
|
id: clockText
|
||||||
@@ -331,6 +332,7 @@ Item {
|
|||||||
StyledText {
|
StyledText {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
anchors.verticalCenterOffset: -25
|
anchors.verticalCenterOffset: -25
|
||||||
|
visible: SettingsData.lockScreenShowDate
|
||||||
text: {
|
text: {
|
||||||
if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) {
|
if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) {
|
||||||
return systemClock.date.toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat);
|
return systemClock.date.toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat);
|
||||||
@@ -368,6 +370,7 @@ Item {
|
|||||||
return PortalService.profileImage;
|
return PortalService.profileImage;
|
||||||
}
|
}
|
||||||
fallbackIcon: "person"
|
fallbackIcon: "person"
|
||||||
|
visible: SettingsData.lockScreenShowProfileImage
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -379,6 +382,8 @@ Item {
|
|||||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9)
|
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9)
|
||||||
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3)
|
border.color: passwordField.activeFocus ? Theme.primary : Qt.rgba(1, 1, 1, 0.3)
|
||||||
border.width: passwordField.activeFocus ? 2 : 1
|
border.width: passwordField.activeFocus ? 2 : 1
|
||||||
|
visible: SettingsData.lockScreenShowPasswordField || root.passwordBuffer.length > 0
|
||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: lockIconContainer
|
id: lockIconContainer
|
||||||
@@ -797,6 +802,7 @@ Item {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: Theme.spacingXL
|
anchors.margins: Theme.spacingXL
|
||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
|
visible: SettingsData.lockScreenShowSystemIcons
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: keyboardLayoutRow.width
|
width: keyboardLayoutRow.width
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ DankListView {
|
|||||||
|
|
||||||
onIsUserScrollingChanged: {
|
onIsUserScrollingChanged: {
|
||||||
if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) {
|
if (isUserScrolling && keyboardController && keyboardController.keyboardNavigationActive) {
|
||||||
autoScrollDisabled = true
|
autoScrollDisabled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableAutoScroll() {
|
function enableAutoScroll() {
|
||||||
autoScrollDisabled = false
|
autoScrollDisabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -33,7 +33,7 @@ DankListView {
|
|||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
|
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
|
||||||
keyboardController.ensureVisible()
|
keyboardController.ensureVisible();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,49 +46,106 @@ DankListView {
|
|||||||
|
|
||||||
onModelChanged: {
|
onModelChanged: {
|
||||||
if (!keyboardController || !keyboardController.keyboardNavigationActive) {
|
if (!keyboardController || !keyboardController.keyboardNavigationActive) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
keyboardController.rebuildFlatNavigation()
|
keyboardController.rebuildFlatNavigation();
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
|
if (keyboardController && keyboardController.keyboardNavigationActive && !autoScrollDisabled) {
|
||||||
keyboardController.ensureVisible()
|
keyboardController.ensureVisible();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
|
id: delegateRoot
|
||||||
required property var modelData
|
required property var modelData
|
||||||
required property int index
|
required property int index
|
||||||
|
|
||||||
readonly property bool isExpanded: (NotificationService.expandedGroups[modelData && modelData.key] || false)
|
readonly property bool isExpanded: (NotificationService.expandedGroups[modelData && modelData.key] || false)
|
||||||
|
property real swipeOffset: 0
|
||||||
|
property bool isDismissing: false
|
||||||
|
readonly property real dismissThreshold: width * 0.35
|
||||||
|
|
||||||
width: ListView.view.width
|
width: ListView.view.width
|
||||||
height: notificationCard.height
|
height: isDismissing ? 0 : notificationCard.height
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationCard {
|
NotificationCard {
|
||||||
id: notificationCard
|
id: notificationCard
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
x: delegateRoot.swipeOffset
|
||||||
notificationGroup: modelData
|
notificationGroup: modelData
|
||||||
keyboardNavigationActive: listView.keyboardActive
|
keyboardNavigationActive: listView.keyboardActive
|
||||||
|
opacity: 1 - Math.abs(delegateRoot.swipeOffset) / (delegateRoot.width * 0.5)
|
||||||
|
|
||||||
isGroupSelected: {
|
isGroupSelected: {
|
||||||
if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive) {
|
if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive)
|
||||||
return false
|
return false;
|
||||||
}
|
keyboardController.selectionVersion;
|
||||||
keyboardController.selectionVersion
|
const selection = keyboardController.getCurrentSelection();
|
||||||
const selection = keyboardController.getCurrentSelection()
|
return selection.type === "group" && selection.groupIndex === index;
|
||||||
return selection.type === "group" && selection.groupIndex === index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedNotificationIndex: {
|
selectedNotificationIndex: {
|
||||||
if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive) {
|
if (!keyboardController || !keyboardController.keyboardNavigationActive || !listView.keyboardActive)
|
||||||
return -1
|
return -1;
|
||||||
|
keyboardController.selectionVersion;
|
||||||
|
const selection = keyboardController.getCurrentSelection();
|
||||||
|
return (selection.type === "notification" && selection.groupIndex === index) ? selection.notificationIndex : -1;
|
||||||
}
|
}
|
||||||
keyboardController.selectionVersion
|
|
||||||
const selection = keyboardController.getCurrentSelection()
|
Behavior on x {
|
||||||
return (selection.type === "notification" && selection.groupIndex === index) ? selection.notificationIndex : -1
|
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;
|
||||||
|
delegateRoot.swipeOffset = delegateRoot.swipeOffset > 0 ? delegateRoot.width : -delegateRoot.width;
|
||||||
|
dismissTimer.start();
|
||||||
|
} else {
|
||||||
|
delegateRoot.swipeOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTranslationChanged: {
|
||||||
|
if (delegateRoot.isDismissing)
|
||||||
|
return;
|
||||||
|
delegateRoot.swipeOffset = translation.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: dismissTimer
|
||||||
|
interval: Theme.shortDuration
|
||||||
|
onTriggered: NotificationService.dismissGroup(delegateRoot.modelData?.key || "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -96,22 +153,22 @@ DankListView {
|
|||||||
|
|
||||||
function onGroupedNotificationsChanged() {
|
function onGroupedNotificationsChanged() {
|
||||||
if (!keyboardController) {
|
if (!keyboardController) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboardController.isTogglingGroup) {
|
if (keyboardController.isTogglingGroup) {
|
||||||
keyboardController.rebuildFlatNavigation()
|
keyboardController.rebuildFlatNavigation();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
keyboardController.rebuildFlatNavigation()
|
keyboardController.rebuildFlatNavigation();
|
||||||
|
|
||||||
if (keyboardController.keyboardNavigationActive) {
|
if (keyboardController.keyboardNavigationActive) {
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (!autoScrollDisabled) {
|
if (!autoScrollDisabled) {
|
||||||
keyboardController.ensureVisible()
|
keyboardController.ensureVisible();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +176,9 @@ DankListView {
|
|||||||
if (keyboardController && keyboardController.keyboardNavigationActive) {
|
if (keyboardController && keyboardController.keyboardNavigationActive) {
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (!autoScrollDisabled) {
|
if (!autoScrollDisabled) {
|
||||||
keyboardController.ensureVisible()
|
keyboardController.ensureVisible();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +186,9 @@ DankListView {
|
|||||||
if (keyboardController && keyboardController.keyboardNavigationActive) {
|
if (keyboardController && keyboardController.keyboardNavigationActive) {
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (!autoScrollDisabled) {
|
if (!autoScrollDisabled) {
|
||||||
keyboardController.ensureVisible()
|
keyboardController.ensureVisible();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import QtQuick.Effects
|
|||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Widgets
|
|
||||||
import Quickshell.Services.Notifications
|
import Quickshell.Services.Notifications
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -29,63 +28,63 @@ PanelWindow {
|
|||||||
|
|
||||||
function startExit() {
|
function startExit() {
|
||||||
if (exiting || _isDestroying) {
|
if (exiting || _isDestroying) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
exiting = true
|
exiting = true;
|
||||||
exitAnim.restart()
|
exitAnim.restart();
|
||||||
exitWatchdog.restart()
|
exitWatchdog.restart();
|
||||||
if (NotificationService.removeFromVisibleNotifications)
|
if (NotificationService.removeFromVisibleNotifications)
|
||||||
NotificationService.removeFromVisibleNotifications(win.notificationData)
|
NotificationService.removeFromVisibleNotifications(win.notificationData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function forceExit() {
|
function forceExit() {
|
||||||
if (_isDestroying) {
|
if (_isDestroying) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
_isDestroying = true
|
_isDestroying = true;
|
||||||
exiting = true
|
exiting = true;
|
||||||
visible = false
|
visible = false;
|
||||||
exitWatchdog.stop()
|
exitWatchdog.stop();
|
||||||
finalizeExit("forced")
|
finalizeExit("forced");
|
||||||
}
|
}
|
||||||
|
|
||||||
function finalizeExit(reason) {
|
function finalizeExit(reason) {
|
||||||
if (_finalized) {
|
if (_finalized) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_finalized = true
|
_finalized = true;
|
||||||
_isDestroying = true
|
_isDestroying = true;
|
||||||
exitWatchdog.stop()
|
exitWatchdog.stop();
|
||||||
wrapperConn.enabled = false
|
wrapperConn.enabled = false;
|
||||||
wrapperConn.target = null
|
wrapperConn.target = null;
|
||||||
win.exitFinished()
|
win.exitFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: hasValidData
|
visible: hasValidData
|
||||||
WlrLayershell.layer: {
|
WlrLayershell.layer: {
|
||||||
const envLayer = Quickshell.env("DMS_NOTIFICATION_LAYER")
|
const envLayer = Quickshell.env("DMS_NOTIFICATION_LAYER");
|
||||||
if (envLayer) {
|
if (envLayer) {
|
||||||
switch (envLayer) {
|
switch (envLayer) {
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return WlrLayershell.Bottom
|
return WlrLayershell.Bottom;
|
||||||
case "overlay":
|
case "overlay":
|
||||||
return WlrLayershell.Overlay
|
return WlrLayershell.Overlay;
|
||||||
case "background":
|
case "background":
|
||||||
return WlrLayershell.Background
|
return WlrLayershell.Background;
|
||||||
case "top":
|
case "top":
|
||||||
return WlrLayershell.Top
|
return WlrLayershell.Top;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!notificationData)
|
if (!notificationData)
|
||||||
return WlrLayershell.Top
|
return WlrLayershell.Top;
|
||||||
|
|
||||||
SettingsData.notificationOverlayEnabled
|
SettingsData.notificationOverlayEnabled;
|
||||||
|
|
||||||
const shouldUseOverlay = (SettingsData.notificationOverlayEnabled) || (notificationData.urgency === NotificationUrgency.Critical)
|
const shouldUseOverlay = (SettingsData.notificationOverlayEnabled) || (notificationData.urgency === NotificationUrgency.Critical);
|
||||||
|
|
||||||
return shouldUseOverlay ? WlrLayershell.Overlay : WlrLayershell.Top
|
return shouldUseOverlay ? WlrLayershell.Overlay : WlrLayershell.Top;
|
||||||
}
|
}
|
||||||
WlrLayershell.exclusiveZone: -1
|
WlrLayershell.exclusiveZone: -1
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
@@ -94,32 +93,32 @@ PanelWindow {
|
|||||||
implicitHeight: 122
|
implicitHeight: 122
|
||||||
onHasValidDataChanged: {
|
onHasValidDataChanged: {
|
||||||
if (!hasValidData && !exiting && !_isDestroying) {
|
if (!hasValidData && !exiting && !_isDestroying) {
|
||||||
forceExit()
|
forceExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (hasValidData) {
|
if (hasValidData) {
|
||||||
Qt.callLater(() => enterX.restart())
|
Qt.callLater(() => enterX.restart());
|
||||||
} else {
|
} else {
|
||||||
forceExit()
|
forceExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onNotificationDataChanged: {
|
onNotificationDataChanged: {
|
||||||
if (!_isDestroying) {
|
if (!_isDestroying) {
|
||||||
wrapperConn.target = win.notificationData || null
|
wrapperConn.target = win.notificationData || null;
|
||||||
notificationConn.target = (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null
|
notificationConn.target = (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if (!_isDestroying) {
|
if (!_isDestroying) {
|
||||||
enterDelay.start()
|
enterDelay.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
_isDestroying = true
|
_isDestroying = true;
|
||||||
exitWatchdog.stop()
|
exitWatchdog.stop();
|
||||||
if (notificationData && notificationData.timer) {
|
if (notificationData && notificationData.timer) {
|
||||||
notificationData.timer.stop()
|
notificationData.timer.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,54 +137,66 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getBarInfo() {
|
function getBarInfo() {
|
||||||
if (!screen) return { topBar: 0, bottomBar: 0, leftBar: 0, rightBar: 0 }
|
if (!screen)
|
||||||
|
return {
|
||||||
|
topBar: 0,
|
||||||
|
bottomBar: 0,
|
||||||
|
leftBar: 0,
|
||||||
|
rightBar: 0
|
||||||
|
};
|
||||||
return SettingsData.getAdjacentBarInfo(screen, SettingsData.notificationPopupPosition, {
|
return SettingsData.getAdjacentBarInfo(screen, SettingsData.notificationPopupPosition, {
|
||||||
id: "notification-popup",
|
id: "notification-popup",
|
||||||
screenPreferences: [screen.name],
|
screenPreferences: [screen.name],
|
||||||
autoHide: false
|
autoHide: false
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTopMargin() {
|
function getTopMargin() {
|
||||||
const popupPos = SettingsData.notificationPopupPosition
|
const popupPos = SettingsData.notificationPopupPosition;
|
||||||
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left
|
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left;
|
||||||
if (!isTop) return 0
|
if (!isTop)
|
||||||
|
return 0;
|
||||||
|
|
||||||
const barInfo = getBarInfo()
|
const barInfo = getBarInfo();
|
||||||
const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance
|
const base = barInfo.topBar > 0 ? barInfo.topBar : Theme.popupDistance;
|
||||||
return base + screenY
|
return base + screenY;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBottomMargin() {
|
function getBottomMargin() {
|
||||||
const popupPos = SettingsData.notificationPopupPosition
|
const popupPos = SettingsData.notificationPopupPosition;
|
||||||
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right
|
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right;
|
||||||
if (!isBottom) return 0
|
if (!isBottom)
|
||||||
|
return 0;
|
||||||
|
|
||||||
const barInfo = getBarInfo()
|
const barInfo = getBarInfo();
|
||||||
const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance
|
const base = barInfo.bottomBar > 0 ? barInfo.bottomBar : Theme.popupDistance;
|
||||||
return base + screenY
|
return base + screenY;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLeftMargin() {
|
function getLeftMargin() {
|
||||||
if (isTopCenter) return (screen.width - implicitWidth) / 2
|
if (isTopCenter)
|
||||||
|
return (screen.width - implicitWidth) / 2;
|
||||||
|
|
||||||
const popupPos = SettingsData.notificationPopupPosition
|
const popupPos = SettingsData.notificationPopupPosition;
|
||||||
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom
|
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom;
|
||||||
if (!isLeft) return 0
|
if (!isLeft)
|
||||||
|
return 0;
|
||||||
|
|
||||||
const barInfo = getBarInfo()
|
const barInfo = getBarInfo();
|
||||||
return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance
|
return barInfo.leftBar > 0 ? barInfo.leftBar : Theme.popupDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRightMargin() {
|
function getRightMargin() {
|
||||||
if (isTopCenter) return 0
|
if (isTopCenter)
|
||||||
|
return 0;
|
||||||
|
|
||||||
const popupPos = SettingsData.notificationPopupPosition
|
const popupPos = SettingsData.notificationPopupPosition;
|
||||||
const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right
|
const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right;
|
||||||
if (!isRight) return 0
|
if (!isRight)
|
||||||
|
return 0;
|
||||||
|
|
||||||
const barInfo = getBarInfo()
|
const barInfo = getBarInfo();
|
||||||
return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance
|
return barInfo.rightBar > 0 ? barInfo.rightBar : Theme.popupDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real dpr: CompositorService.getScreenScale(win.screen)
|
readonly property real dpr: CompositorService.getScreenScale(win.screen)
|
||||||
@@ -201,6 +212,11 @@ PanelWindow {
|
|||||||
height: alignedHeight
|
height: alignedHeight
|
||||||
visible: win.hasValidData
|
visible: win.hasValidData
|
||||||
|
|
||||||
|
property real swipeOffset: 0
|
||||||
|
readonly property real dismissThreshold: isTopCenter ? height * 0.4 : width * 0.35
|
||||||
|
readonly property bool swipeActive: swipeDragHandler.active
|
||||||
|
property bool swipeDismissing: false
|
||||||
|
|
||||||
property real shadowBlurPx: 10
|
property real shadowBlurPx: 10
|
||||||
property real shadowSpreadPx: 0
|
property real shadowSpreadPx: 0
|
||||||
property real shadowBaseAlpha: 0.60
|
property real shadowBaseAlpha: 0.60
|
||||||
@@ -227,8 +243,8 @@ PanelWindow {
|
|||||||
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / bgShadowLayer.blurMax))
|
shadowBlur: Math.max(0, Math.min(1, content.shadowBlurPx / bgShadowLayer.blurMax))
|
||||||
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
|
shadowScale: 1 + (2 * content.shadowSpreadPx) / Math.max(1, Math.min(bgShadowLayer.width, bgShadowLayer.height))
|
||||||
shadowColor: {
|
shadowColor: {
|
||||||
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest
|
const baseColor = Theme.isLightMode ? Qt.rgba(0, 0, 0, 1) : Theme.surfaceContainerHighest;
|
||||||
return Theme.withAlpha(baseColor, content.effectiveShadowAlpha)
|
return Theme.withAlpha(baseColor, content.effectiveShadowAlpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,14 +266,46 @@ PanelWindow {
|
|||||||
startX: backgroundShape.radius
|
startX: backgroundShape.radius
|
||||||
startY: 0
|
startY: 0
|
||||||
|
|
||||||
PathLine { x: backgroundShape.width - backgroundShape.radius; y: 0 }
|
PathLine {
|
||||||
PathQuad { x: backgroundShape.width; y: backgroundShape.radius; controlX: backgroundShape.width; controlY: 0 }
|
x: backgroundShape.width - backgroundShape.radius
|
||||||
PathLine { x: backgroundShape.width; y: backgroundShape.height - backgroundShape.radius }
|
y: 0
|
||||||
PathQuad { x: backgroundShape.width - backgroundShape.radius; y: backgroundShape.height; controlX: backgroundShape.width; controlY: backgroundShape.height }
|
}
|
||||||
PathLine { x: backgroundShape.radius; y: backgroundShape.height }
|
PathQuad {
|
||||||
PathQuad { x: 0; y: backgroundShape.height - backgroundShape.radius; controlX: 0; controlY: backgroundShape.height }
|
x: backgroundShape.width
|
||||||
PathLine { x: 0; y: backgroundShape.radius }
|
y: backgroundShape.radius
|
||||||
PathQuad { x: backgroundShape.radius; y: 0; controlX: 0; controlY: 0 }
|
controlX: backgroundShape.width
|
||||||
|
controlY: 0
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
x: backgroundShape.width
|
||||||
|
y: backgroundShape.height - backgroundShape.radius
|
||||||
|
}
|
||||||
|
PathQuad {
|
||||||
|
x: backgroundShape.width - backgroundShape.radius
|
||||||
|
y: backgroundShape.height
|
||||||
|
controlX: backgroundShape.width
|
||||||
|
controlY: backgroundShape.height
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
x: backgroundShape.radius
|
||||||
|
y: backgroundShape.height
|
||||||
|
}
|
||||||
|
PathQuad {
|
||||||
|
x: 0
|
||||||
|
y: backgroundShape.height - backgroundShape.radius
|
||||||
|
controlX: 0
|
||||||
|
controlY: backgroundShape.height
|
||||||
|
}
|
||||||
|
PathLine {
|
||||||
|
x: 0
|
||||||
|
y: backgroundShape.radius
|
||||||
|
}
|
||||||
|
PathQuad {
|
||||||
|
x: backgroundShape.radius
|
||||||
|
y: 0
|
||||||
|
controlX: 0
|
||||||
|
controlY: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,26 +366,26 @@ PanelWindow {
|
|||||||
|
|
||||||
imageSource: {
|
imageSource: {
|
||||||
if (!notificationData)
|
if (!notificationData)
|
||||||
return ""
|
return "";
|
||||||
|
|
||||||
if (hasNotificationImage)
|
if (hasNotificationImage)
|
||||||
return notificationData.cleanImage || ""
|
return notificationData.cleanImage || "";
|
||||||
|
|
||||||
if (notificationData.appIcon) {
|
if (notificationData.appIcon) {
|
||||||
const appIcon = notificationData.appIcon
|
const appIcon = notificationData.appIcon;
|
||||||
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://"))
|
if (appIcon.startsWith("file://") || appIcon.startsWith("http://") || appIcon.startsWith("https://"))
|
||||||
return appIcon
|
return appIcon;
|
||||||
|
|
||||||
return Quickshell.iconPath(appIcon, true)
|
return Quickshell.iconPath(appIcon, true);
|
||||||
}
|
}
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
hasImage: hasNotificationImage
|
hasImage: hasNotificationImage
|
||||||
fallbackIcon: ""
|
fallbackIcon: ""
|
||||||
fallbackText: {
|
fallbackText: {
|
||||||
const appName = notificationData?.appName || "?"
|
const appName = notificationData?.appName || "?";
|
||||||
return appName.charAt(0).toUpperCase()
|
return appName.charAt(0).toUpperCase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,14 +415,14 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
text: {
|
text: {
|
||||||
if (!notificationData)
|
if (!notificationData)
|
||||||
return ""
|
return "";
|
||||||
|
|
||||||
const appName = notificationData.appName || ""
|
const appName = notificationData.appName || "";
|
||||||
const timeStr = notificationData.timeStr || ""
|
const timeStr = notificationData.timeStr || "";
|
||||||
if (timeStr.length > 0)
|
if (timeStr.length > 0)
|
||||||
return appName + " • " + timeStr
|
return appName + " • " + timeStr;
|
||||||
else
|
else
|
||||||
return appName
|
return appName;
|
||||||
}
|
}
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
@@ -405,7 +453,7 @@ PanelWindow {
|
|||||||
visible: text.length > 0
|
visible: text.length > 0
|
||||||
linkColor: Theme.primary
|
linkColor: Theme.primary
|
||||||
onLinkActivated: link => {
|
onLinkActivated: link => {
|
||||||
return Qt.openUrlExternally(link)
|
return Qt.openUrlExternally(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -432,7 +480,7 @@ PanelWindow {
|
|||||||
z: 15
|
z: 15
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (notificationData && !win.exiting)
|
if (notificationData && !win.exiting)
|
||||||
notificationData.popup = false
|
notificationData.popup = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,10 +523,10 @@ PanelWindow {
|
|||||||
onExited: parent.isHovered = false
|
onExited: parent.isHovered = false
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -519,7 +567,7 @@ PanelWindow {
|
|||||||
onExited: clearButton.isHovered = false
|
onExited: clearButton.isHovered = false
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (notificationData && !win.exiting)
|
if (notificationData && !win.exiting)
|
||||||
NotificationService.dismissNotification(notificationData)
|
NotificationService.dismissNotification(notificationData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -534,40 +582,108 @@ PanelWindow {
|
|||||||
z: -1
|
z: -1
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if (notificationData && notificationData.timer)
|
if (notificationData && notificationData.timer)
|
||||||
notificationData.timer.stop()
|
notificationData.timer.stop();
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
if (notificationData && notificationData.popup && notificationData.timer)
|
if (notificationData && notificationData.popup && notificationData.timer)
|
||||||
notificationData.timer.restart()
|
notificationData.timer.restart();
|
||||||
}
|
}
|
||||||
onClicked: (mouse) => {
|
onClicked: mouse => {
|
||||||
if (!notificationData || win.exiting)
|
if (!notificationData || win.exiting)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
NotificationService.dismissNotification(notificationData)
|
NotificationService.dismissNotification(notificationData);
|
||||||
} else if (mouse.button === Qt.LeftButton) {
|
} else if (mouse.button === Qt.LeftButton) {
|
||||||
if (notificationData.actions && notificationData.actions.length > 0) {
|
if (notificationData.actions && notificationData.actions.length > 0) {
|
||||||
notificationData.actions[0].invoke()
|
notificationData.actions[0].invoke();
|
||||||
NotificationService.dismissNotification(notificationData)
|
NotificationService.dismissNotification(notificationData);
|
||||||
} else {
|
} else {
|
||||||
notificationData.popup = false
|
notificationData.popup = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transform: Translate {
|
DragHandler {
|
||||||
|
id: swipeDragHandler
|
||||||
|
target: null
|
||||||
|
xAxis.enabled: !isTopCenter
|
||||||
|
yAxis.enabled: isTopCenter
|
||||||
|
|
||||||
|
onActiveChanged: {
|
||||||
|
if (active || win.exiting || content.swipeDismissing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Math.abs(content.swipeOffset) > content.dismissThreshold) {
|
||||||
|
content.swipeDismissing = true;
|
||||||
|
swipeDismissAnim.start();
|
||||||
|
} else {
|
||||||
|
content.swipeOffset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onTranslationChanged: {
|
||||||
|
if (win.exiting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const raw = isTopCenter ? translation.y : translation.x;
|
||||||
|
if (isTopCenter) {
|
||||||
|
content.swipeOffset = Math.min(0, raw);
|
||||||
|
} else {
|
||||||
|
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
|
||||||
|
content.swipeOffset = isLeft ? Math.min(0, raw) : Math.max(0, raw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opacity: 1 - Math.abs(content.swipeOffset) / (isTopCenter ? content.height : content.width * 0.6)
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
enabled: !content.swipeActive
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on swipeOffset {
|
||||||
|
enabled: !content.swipeActive && !content.swipeDismissing
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: swipeDismissAnim
|
||||||
|
target: content
|
||||||
|
property: "swipeOffset"
|
||||||
|
to: isTopCenter ? -content.height : (SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom ? -content.width : content.width)
|
||||||
|
duration: Anims.durShort
|
||||||
|
easing.type: Easing.OutCubic
|
||||||
|
onStopped: {
|
||||||
|
NotificationService.dismissNotification(notificationData);
|
||||||
|
win.forceExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transform: [
|
||||||
|
Translate {
|
||||||
|
id: swipeTx
|
||||||
|
x: isTopCenter ? 0 : content.swipeOffset
|
||||||
|
y: isTopCenter ? content.swipeOffset : 0
|
||||||
|
},
|
||||||
|
Translate {
|
||||||
id: tx
|
id: tx
|
||||||
|
|
||||||
x: {
|
x: {
|
||||||
if (isTopCenter) return 0
|
if (isTopCenter)
|
||||||
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
return 0;
|
||||||
return isLeft ? -Anims.slidePx : Anims.slidePx
|
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
|
||||||
|
return isLeft ? -Anims.slidePx : Anims.slidePx;
|
||||||
}
|
}
|
||||||
y: isTopCenter ? -Anims.slidePx : 0
|
y: isTopCenter ? -Anims.slidePx : 0
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -576,9 +692,10 @@ PanelWindow {
|
|||||||
target: tx
|
target: tx
|
||||||
property: isTopCenter ? "y" : "x"
|
property: isTopCenter ? "y" : "x"
|
||||||
from: {
|
from: {
|
||||||
if (isTopCenter) return -Anims.slidePx
|
if (isTopCenter)
|
||||||
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
return -Anims.slidePx;
|
||||||
return isLeft ? -Anims.slidePx : Anims.slidePx
|
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
|
||||||
|
return isLeft ? -Anims.slidePx : Anims.slidePx;
|
||||||
}
|
}
|
||||||
to: 0
|
to: 0
|
||||||
duration: Anims.durMed
|
duration: Anims.durMed
|
||||||
@@ -587,9 +704,11 @@ PanelWindow {
|
|||||||
onStopped: {
|
onStopped: {
|
||||||
if (!win.exiting && !win._isDestroying) {
|
if (!win.exiting && !win._isDestroying) {
|
||||||
if (isTopCenter) {
|
if (isTopCenter) {
|
||||||
if (Math.abs(tx.y) < 0.5) win.entered()
|
if (Math.abs(tx.y) < 0.5)
|
||||||
|
win.entered();
|
||||||
} else {
|
} else {
|
||||||
if (Math.abs(tx.x) < 0.5) win.entered()
|
if (Math.abs(tx.x) < 0.5)
|
||||||
|
win.entered();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -605,9 +724,10 @@ PanelWindow {
|
|||||||
property: isTopCenter ? "y" : "x"
|
property: isTopCenter ? "y" : "x"
|
||||||
from: 0
|
from: 0
|
||||||
to: {
|
to: {
|
||||||
if (isTopCenter) return -Anims.slidePx
|
if (isTopCenter)
|
||||||
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
return -Anims.slidePx;
|
||||||
return isLeft ? -Anims.slidePx : Anims.slidePx
|
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom;
|
||||||
|
return isLeft ? -Anims.slidePx : Anims.slidePx;
|
||||||
}
|
}
|
||||||
duration: Anims.durShort
|
duration: Anims.durShort
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
@@ -640,10 +760,9 @@ PanelWindow {
|
|||||||
|
|
||||||
function onPopupChanged() {
|
function onPopupChanged() {
|
||||||
if (!win.notificationData || win._isDestroying)
|
if (!win.notificationData || win._isDestroying)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (!win.notificationData.popup && !win.exiting)
|
if (!win.notificationData.popup && !win.exiting)
|
||||||
startExit()
|
startExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
target: win.notificationData || null
|
target: win.notificationData || null
|
||||||
@@ -656,7 +775,7 @@ PanelWindow {
|
|||||||
|
|
||||||
function onDropped() {
|
function onDropped() {
|
||||||
if (!win._isDestroying && !win.exiting)
|
if (!win._isDestroying && !win.exiting)
|
||||||
forceExit()
|
forceExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
target: (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null
|
target: (win.notificationData && win.notificationData.notification && win.notificationData.notification.Retainable) || null
|
||||||
@@ -671,7 +790,7 @@ PanelWindow {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (notificationData && notificationData.timer && !exiting && !_isDestroying)
|
if (notificationData && notificationData.timer && !exiting && !_isDestroying)
|
||||||
notificationData.timer.start()
|
notificationData.timer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,15 +23,51 @@ Item {
|
|||||||
SettingsCard {
|
SettingsCard {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "lock"
|
iconName: "lock"
|
||||||
title: I18n.tr("Lock Screen")
|
title: I18n.tr("Lock Screen layout")
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
text: I18n.tr("Show Power Actions")
|
text: I18n.tr("Show Power Actions", "Enable power action icon on the lock screen window")
|
||||||
description: I18n.tr("Show power, restart, and logout buttons on the lock screen")
|
|
||||||
checked: SettingsData.lockScreenShowPowerActions
|
checked: SettingsData.lockScreenShowPowerActions
|
||||||
onToggled: checked => SettingsData.set("lockScreenShowPowerActions", checked)
|
onToggled: checked => SettingsData.set("lockScreenShowPowerActions", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show System Icons", "Enable system status icons on the lock screen window")
|
||||||
|
checked: SettingsData.lockScreenShowSystemIcons
|
||||||
|
onToggled: checked => SettingsData.set("lockScreenShowSystemIcons", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show System Time", "Enable system time display on the lock screen window")
|
||||||
|
checked: SettingsData.lockScreenShowTime
|
||||||
|
onToggled: checked => SettingsData.set("lockScreenShowTime", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show System Date", "Enable system date display on the lock screen window")
|
||||||
|
checked: SettingsData.lockScreenShowDate
|
||||||
|
onToggled: checked => SettingsData.set("lockScreenShowDate", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show Profile Image", "Enable profile image display on the lock screen window")
|
||||||
|
checked: SettingsData.lockScreenShowProfileImage
|
||||||
|
onToggled: checked => SettingsData.set("lockScreenShowProfileImage", checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsToggleRow {
|
||||||
|
text: I18n.tr("Show Password Field", "Enable password field display on the lock screen window")
|
||||||
|
description: I18n.tr("If the field is hidden, it will appear as soon as a key is pressed.")
|
||||||
|
checked: SettingsData.lockScreenShowPasswordField
|
||||||
|
onToggled: checked => SettingsData.set("lockScreenShowPasswordField", checked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsCard {
|
||||||
|
width: parent.width
|
||||||
|
iconName: "lock"
|
||||||
|
title: I18n.tr("Lock Screen behaviour")
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: I18n.tr("loginctl not available - lock integration requires DMS socket connection")
|
text: I18n.tr("loginctl not available - lock integration requires DMS socket connection")
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ PanelWindow {
|
|||||||
property real frozenWidth: 0
|
property real frozenWidth: 0
|
||||||
readonly property string copiedText: I18n.tr("Copied!")
|
readonly property string copiedText: I18n.tr("Copied!")
|
||||||
|
|
||||||
|
readonly property real dpr: modelData ? CompositorService.getScreenScale(modelData) : 1
|
||||||
|
readonly property real shadowBuffer: 5
|
||||||
|
readonly property real toastY: Theme.barHeight - 4 + (SettingsData.barConfigs[0]?.spacing ?? 4) + 2
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: ToastService
|
target: ToastService
|
||||||
function onToastVisibleChanged() {
|
function onToastVisibleChanged() {
|
||||||
@@ -23,7 +27,6 @@ PanelWindow {
|
|||||||
shouldBeVisible = true;
|
shouldBeVisible = true;
|
||||||
visible = true;
|
visible = true;
|
||||||
} else {
|
} else {
|
||||||
// Freeze the width before starting exit animation
|
|
||||||
frozenWidth = toast.width;
|
frozenWidth = toast.width;
|
||||||
shouldBeVisible = false;
|
shouldBeVisible = false;
|
||||||
closeTimer.restart();
|
closeTimer.restart();
|
||||||
@@ -48,13 +51,22 @@ PanelWindow {
|
|||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
|
readonly property real toastWidth: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth
|
||||||
|
readonly property real toastHeight: toastContent.height + Theme.spacingL * 2
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
left: true
|
left: true
|
||||||
right: true
|
|
||||||
bottom: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WlrLayershell.margins {
|
||||||
|
left: Math.max(0, Theme.snap((modelData?.width ?? 1920) / 2 - toastWidth / 2 - shadowBuffer, dpr))
|
||||||
|
top: Math.max(0, Theme.snap(toastY - shadowBuffer, dpr))
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: toastWidth + (shadowBuffer * 2)
|
||||||
|
implicitHeight: toastHeight + (shadowBuffer * 2)
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: toast
|
id: toast
|
||||||
|
|
||||||
@@ -67,10 +79,10 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
width: shouldBeVisible ? Math.min(900, messageText.implicitWidth + statusIcon.width + Theme.spacingM + (ToastService.hasDetails ? (expandButton.width + closeButton.width + 4) : (ToastService.currentLevel === ToastService.levelError ? closeButton.width + Theme.spacingS : 0)) + Theme.spacingL * 2 + Theme.spacingM * 2) : frozenWidth
|
x: shadowBuffer
|
||||||
height: toastContent.height + Theme.spacingL * 2
|
y: shadowBuffer
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
width: root.toastWidth
|
||||||
y: Theme.barHeight - 4 + (SettingsData.barConfigs[0]?.spacing ?? 4) + 2
|
height: root.toastHeight
|
||||||
color: {
|
color: {
|
||||||
switch (ToastService.currentLevel) {
|
switch (ToastService.currentLevel) {
|
||||||
case ToastService.levelError:
|
case ToastService.levelError:
|
||||||
|
|||||||
@@ -57,15 +57,11 @@ Variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onTransitionTypeChanged: {
|
onTransitionTypeChanged: {
|
||||||
if (transitionType === "random") {
|
if (transitionType !== "random") {
|
||||||
if (SessionData.includedTransitions.length === 0) {
|
|
||||||
actualTransitionType = "none";
|
|
||||||
} else {
|
|
||||||
actualTransitionType = SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
actualTransitionType = transitionType;
|
actualTransitionType = transitionType;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
actualTransitionType = SessionData.includedTransitions.length === 0 ? "none" : SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
property real transitionProgress: 0
|
property real transitionProgress: 0
|
||||||
@@ -108,30 +104,33 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (source) {
|
if (!source) {
|
||||||
|
isInitialized = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
|
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
|
||||||
setWallpaperImmediate(formattedSource);
|
setWallpaperImmediate(formattedSource);
|
||||||
}
|
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
const isColor = source.startsWith("#");
|
if (!source || source.startsWith("#")) {
|
||||||
|
setWallpaperImmediate("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formattedSource = source.startsWith("file://") ? source : "file://" + source;
|
||||||
|
|
||||||
if (!source) {
|
|
||||||
setWallpaperImmediate("");
|
|
||||||
} else if (isColor) {
|
|
||||||
setWallpaperImmediate("");
|
|
||||||
} else {
|
|
||||||
if (!isInitialized || !currentWallpaper.source) {
|
if (!isInitialized || !currentWallpaper.source) {
|
||||||
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source);
|
setWallpaperImmediate(formattedSource);
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
} else if (CompositorService.isNiri && SessionData.isSwitchingMode) {
|
return;
|
||||||
setWallpaperImmediate(source.startsWith("file://") ? source : "file://" + source);
|
|
||||||
} else {
|
|
||||||
changeWallpaper(source.startsWith("file://") ? source : "file://" + source);
|
|
||||||
}
|
}
|
||||||
|
if (CompositorService.isNiri && SessionData.isSwitchingMode) {
|
||||||
|
setWallpaperImmediate(formattedSource);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
changeWallpaper(formattedSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWallpaperImmediate(newSource) {
|
function setWallpaperImmediate(newSource) {
|
||||||
@@ -143,8 +142,6 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startTransition() {
|
function startTransition() {
|
||||||
currentWallpaper.cache = true;
|
|
||||||
nextWallpaper.cache = true;
|
|
||||||
currentWallpaper.layer.enabled = true;
|
currentWallpaper.layer.enabled = true;
|
||||||
nextWallpaper.layer.enabled = true;
|
nextWallpaper.layer.enabled = true;
|
||||||
root.useNextForEffect = true;
|
root.useNextForEffect = true;
|
||||||
@@ -153,9 +150,14 @@ Variants {
|
|||||||
srcCurrent.scheduleUpdate();
|
srcCurrent.scheduleUpdate();
|
||||||
if (srcNext.scheduleUpdate)
|
if (srcNext.scheduleUpdate)
|
||||||
srcNext.scheduleUpdate();
|
srcNext.scheduleUpdate();
|
||||||
Qt.callLater(() => {
|
transitionDelayTimer.start();
|
||||||
transitionAnimation.start();
|
}
|
||||||
});
|
|
||||||
|
Timer {
|
||||||
|
id: transitionDelayTimer
|
||||||
|
interval: 16
|
||||||
|
repeat: false
|
||||||
|
onTriggered: transitionAnimation.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeWallpaper(newPath, force) {
|
function changeWallpaper(newPath, force) {
|
||||||
@@ -163,23 +165,17 @@ Variants {
|
|||||||
return;
|
return;
|
||||||
if (!newPath || newPath.startsWith("#"))
|
if (!newPath || newPath.startsWith("#"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (root.transitioning || root.effectActive) {
|
if (root.transitioning || root.effectActive) {
|
||||||
root.pendingWallpaper = newPath;
|
root.pendingWallpaper = newPath;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentWallpaper.source) {
|
if (!currentWallpaper.source) {
|
||||||
setWallpaperImmediate(newPath);
|
setWallpaperImmediate(newPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.transitionType === "random") {
|
if (root.transitionType === "random") {
|
||||||
if (SessionData.includedTransitions.length === 0) {
|
root.actualTransitionType = SessionData.includedTransitions.length === 0 ? "none" : SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)];
|
||||||
root.actualTransitionType = "none";
|
|
||||||
} else {
|
|
||||||
root.actualTransitionType = SessionData.includedTransitions[Math.floor(Math.random() * SessionData.includedTransitions.length)];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.actualTransitionType === "none") {
|
if (root.actualTransitionType === "none") {
|
||||||
@@ -187,22 +183,27 @@ Variants {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.actualTransitionType === "wipe") {
|
switch (root.actualTransitionType) {
|
||||||
|
case "wipe":
|
||||||
root.wipeDirection = Math.random() * 4;
|
root.wipeDirection = Math.random() * 4;
|
||||||
} else if (root.actualTransitionType === "disc" || root.actualTransitionType === "pixelate" || root.actualTransitionType === "portal") {
|
break;
|
||||||
|
case "disc":
|
||||||
|
case "pixelate":
|
||||||
|
case "portal":
|
||||||
root.discCenterX = Math.random();
|
root.discCenterX = Math.random();
|
||||||
root.discCenterY = Math.random();
|
root.discCenterY = Math.random();
|
||||||
} else if (root.actualTransitionType === "stripes") {
|
break;
|
||||||
|
case "stripes":
|
||||||
root.stripesCount = Math.round(Math.random() * 20 + 4);
|
root.stripesCount = Math.round(Math.random() * 20 + 4);
|
||||||
root.stripesAngle = Math.random() * 360;
|
root.stripesAngle = Math.random() * 360;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextWallpaper.source = newPath;
|
nextWallpaper.source = newPath;
|
||||||
|
|
||||||
if (nextWallpaper.status === Image.Ready) {
|
if (nextWallpaper.status === Image.Ready)
|
||||||
root.startTransition();
|
root.startTransition();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -214,9 +215,9 @@ Variants {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property real screenScale: CompositorService.getScreenScale(modelData)
|
readonly property int maxTextureSize: 8192
|
||||||
property int physicalWidth: Math.round(modelData.width * screenScale)
|
property int textureWidth: Math.min(modelData.width, maxTextureSize)
|
||||||
property int physicalHeight: Math.round(modelData.height * screenScale)
|
property int textureHeight: Math.min(modelData.height, maxTextureSize)
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: currentWallpaper
|
id: currentWallpaper
|
||||||
@@ -227,7 +228,7 @@ Variants {
|
|||||||
asynchronous: true
|
asynchronous: true
|
||||||
smooth: true
|
smooth: true
|
||||||
cache: true
|
cache: true
|
||||||
sourceSize: Qt.size(root.physicalWidth, root.physicalHeight)
|
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,8 +240,8 @@ Variants {
|
|||||||
layer.enabled: false
|
layer.enabled: false
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
smooth: true
|
smooth: true
|
||||||
cache: false
|
cache: true
|
||||||
sourceSize: Qt.size(root.physicalWidth, root.physicalHeight)
|
sourceSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
fillMode: root.getFillMode(SettingsData.wallpaperFillMode)
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
@@ -263,7 +264,7 @@ Variants {
|
|||||||
live: root.effectActive
|
live: root.effectActive
|
||||||
mipmap: false
|
mipmap: false
|
||||||
recursive: false
|
recursive: false
|
||||||
textureSize: root.effectActive ? Qt.size(root.physicalWidth, root.physicalHeight) : Qt.size(1, 1)
|
textureSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderEffectSource {
|
ShaderEffectSource {
|
||||||
@@ -273,7 +274,7 @@ Variants {
|
|||||||
live: root.effectActive
|
live: root.effectActive
|
||||||
mipmap: false
|
mipmap: false
|
||||||
recursive: false
|
recursive: false
|
||||||
textureSize: root.effectActive ? Qt.size(root.physicalWidth, root.physicalHeight) : Qt.size(1, 1)
|
textureSize: Qt.size(root.textureWidth, root.textureHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -297,8 +298,9 @@ Variants {
|
|||||||
id: effectLoader
|
id: effectLoader
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: root.effectActive
|
active: root.effectActive
|
||||||
sourceComponent: {
|
|
||||||
switch (root.actualTransitionType) {
|
function getTransitionComponent(type) {
|
||||||
|
switch (type) {
|
||||||
case "fade":
|
case "fade":
|
||||||
return fadeComp;
|
return fadeComp;
|
||||||
case "wipe":
|
case "wipe":
|
||||||
@@ -317,6 +319,8 @@ Variants {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceComponent: getTransitionComponent(root.actualTransitionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
@@ -491,17 +495,13 @@ Variants {
|
|||||||
root.transitionProgress = 0.0;
|
root.transitionProgress = 0.0;
|
||||||
currentWallpaper.layer.enabled = false;
|
currentWallpaper.layer.enabled = false;
|
||||||
nextWallpaper.layer.enabled = false;
|
nextWallpaper.layer.enabled = false;
|
||||||
currentWallpaper.cache = true;
|
|
||||||
nextWallpaper.cache = false;
|
|
||||||
root.effectActive = false;
|
root.effectActive = false;
|
||||||
|
|
||||||
if (root.pendingWallpaper) {
|
if (!root.pendingWallpaper)
|
||||||
|
return;
|
||||||
var pending = root.pendingWallpaper;
|
var pending = root.pendingWallpaper;
|
||||||
root.pendingWallpaper = "";
|
root.pendingWallpaper = "";
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => root.changeWallpaper(pending, true));
|
||||||
root.changeWallpaper(pending, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,7 +314,8 @@ Singleton {
|
|||||||
const keyData = {
|
const keyData = {
|
||||||
key: bind.key || "",
|
key: bind.key || "",
|
||||||
source: bind.source || "config",
|
source: bind.source || "config",
|
||||||
isOverride: bind.source === "dms"
|
isOverride: bind.source === "dms",
|
||||||
|
cooldownMs: bind.cooldownMs || 0
|
||||||
};
|
};
|
||||||
if (actionMap[action]) {
|
if (actionMap[action]) {
|
||||||
actionMap[action].keys.push(keyData);
|
actionMap[action].keys.push(keyData);
|
||||||
@@ -378,6 +379,8 @@ Singleton {
|
|||||||
const cmd = ["dms", "keybinds", "set", currentProvider, bindData.key, bindData.action, "--desc", bindData.desc || ""];
|
const cmd = ["dms", "keybinds", "set", currentProvider, bindData.key, bindData.action, "--desc", bindData.desc || ""];
|
||||||
if (originalKey && originalKey !== bindData.key)
|
if (originalKey && originalKey !== bindData.key)
|
||||||
cmd.push("--replace-key", originalKey);
|
cmd.push("--replace-key", originalKey);
|
||||||
|
if (bindData.cooldownMs > 0)
|
||||||
|
cmd.push("--cooldown-ms", String(bindData.cooldownMs));
|
||||||
saveProcess.command = cmd;
|
saveProcess.command = cmd;
|
||||||
saveProcess.running = true;
|
saveProcess.running = true;
|
||||||
bindSaved(bindData.key);
|
bindSaved(bindData.key);
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ PanelWindow {
|
|||||||
readonly property real dpr: CompositorService.getScreenScale(screen)
|
readonly property real dpr: CompositorService.getScreenScale(screen)
|
||||||
readonly property real screenWidth: screen.width
|
readonly property real screenWidth: screen.width
|
||||||
readonly property real screenHeight: screen.height
|
readonly property real screenHeight: screen.height
|
||||||
|
readonly property real shadowBuffer: 5
|
||||||
readonly property real alignedWidth: Theme.px(osdWidth, dpr)
|
readonly property real alignedWidth: Theme.px(osdWidth, dpr)
|
||||||
readonly property real alignedHeight: Theme.px(osdHeight, dpr)
|
readonly property real alignedHeight: Theme.px(osdHeight, dpr)
|
||||||
|
|
||||||
@@ -172,10 +173,16 @@ PanelWindow {
|
|||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
left: true
|
left: true
|
||||||
right: true
|
|
||||||
bottom: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WlrLayershell.margins {
|
||||||
|
left: Math.max(0, Theme.snap(alignedX - shadowBuffer, dpr))
|
||||||
|
top: Math.max(0, Theme.snap(alignedY - shadowBuffer, dpr))
|
||||||
|
}
|
||||||
|
|
||||||
|
implicitWidth: alignedWidth + (shadowBuffer * 2)
|
||||||
|
implicitHeight: alignedHeight + (shadowBuffer * 2)
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: hideTimer
|
id: hideTimer
|
||||||
|
|
||||||
@@ -203,8 +210,8 @@ PanelWindow {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: osdContainer
|
id: osdContainer
|
||||||
x: alignedX
|
x: shadowBuffer
|
||||||
y: alignedY
|
y: shadowBuffer
|
||||||
width: alignedWidth
|
width: alignedWidth
|
||||||
height: alignedHeight
|
height: alignedHeight
|
||||||
opacity: shouldBeVisible ? 1 : 0
|
opacity: shouldBeVisible ? 1 : 0
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ Item {
|
|||||||
property string editKey: ""
|
property string editKey: ""
|
||||||
property string editAction: ""
|
property string editAction: ""
|
||||||
property string editDesc: ""
|
property string editDesc: ""
|
||||||
|
property int editCooldownMs: 0
|
||||||
|
property int _savedCooldownMs: -1
|
||||||
property bool hasChanges: false
|
property bool hasChanges: false
|
||||||
property string _actionType: ""
|
property string _actionType: ""
|
||||||
property bool addingNewKey: false
|
property bool addingNewKey: false
|
||||||
@@ -90,6 +92,12 @@ Item {
|
|||||||
editKey = keyToFind;
|
editKey = keyToFind;
|
||||||
editAction = bindData.action || "";
|
editAction = bindData.action || "";
|
||||||
editDesc = bindData.desc || "";
|
editDesc = bindData.desc || "";
|
||||||
|
if (_savedCooldownMs >= 0) {
|
||||||
|
editCooldownMs = _savedCooldownMs;
|
||||||
|
_savedCooldownMs = -1;
|
||||||
|
} else {
|
||||||
|
editCooldownMs = keys[i].cooldownMs || 0;
|
||||||
|
}
|
||||||
hasChanges = false;
|
hasChanges = false;
|
||||||
_actionType = Actions.getActionType(editAction);
|
_actionType = Actions.getActionType(editAction);
|
||||||
useCustomCompositor = _actionType === "compositor" && editAction && !Actions.isKnownCompositorAction(editAction);
|
useCustomCompositor = _actionType === "compositor" && editAction && !Actions.isKnownCompositorAction(editAction);
|
||||||
@@ -109,6 +117,7 @@ Item {
|
|||||||
editKey = editingKeyIndex >= 0 ? keys[editingKeyIndex].key : "";
|
editKey = editingKeyIndex >= 0 ? keys[editingKeyIndex].key : "";
|
||||||
editAction = bindData.action || "";
|
editAction = bindData.action || "";
|
||||||
editDesc = bindData.desc || "";
|
editDesc = bindData.desc || "";
|
||||||
|
editCooldownMs = editingKeyIndex >= 0 ? (keys[editingKeyIndex].cooldownMs || 0) : 0;
|
||||||
hasChanges = false;
|
hasChanges = false;
|
||||||
_actionType = Actions.getActionType(editAction);
|
_actionType = Actions.getActionType(editAction);
|
||||||
useCustomCompositor = _actionType === "compositor" && editAction && !Actions.isKnownCompositorAction(editAction);
|
useCustomCompositor = _actionType === "compositor" && editAction && !Actions.isKnownCompositorAction(editAction);
|
||||||
@@ -127,6 +136,7 @@ Item {
|
|||||||
addingNewKey = false;
|
addingNewKey = false;
|
||||||
editingKeyIndex = index;
|
editingKeyIndex = index;
|
||||||
editKey = keys[index].key;
|
editKey = keys[index].key;
|
||||||
|
editCooldownMs = keys[index].cooldownMs || 0;
|
||||||
hasChanges = false;
|
hasChanges = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,8 +147,11 @@ Item {
|
|||||||
editAction = changes.action;
|
editAction = changes.action;
|
||||||
if (changes.desc !== undefined)
|
if (changes.desc !== undefined)
|
||||||
editDesc = changes.desc;
|
editDesc = changes.desc;
|
||||||
|
if (changes.cooldownMs !== undefined)
|
||||||
|
editCooldownMs = changes.cooldownMs;
|
||||||
const origKey = editingKeyIndex >= 0 && editingKeyIndex < keys.length ? keys[editingKeyIndex].key : "";
|
const origKey = editingKeyIndex >= 0 && editingKeyIndex < keys.length ? keys[editingKeyIndex].key : "";
|
||||||
hasChanges = editKey !== origKey || editAction !== (bindData.action || "") || editDesc !== (bindData.desc || "");
|
const origCooldown = editingKeyIndex >= 0 && editingKeyIndex < keys.length ? (keys[editingKeyIndex].cooldownMs || 0) : 0;
|
||||||
|
hasChanges = editKey !== origKey || editAction !== (bindData.action || "") || editDesc !== (bindData.desc || "") || editCooldownMs !== origCooldown;
|
||||||
}
|
}
|
||||||
|
|
||||||
function canSave() {
|
function canSave() {
|
||||||
@@ -156,10 +169,12 @@ Item {
|
|||||||
let desc = editDesc;
|
let desc = editDesc;
|
||||||
if (expandedLoader.item?.currentTitle !== undefined)
|
if (expandedLoader.item?.currentTitle !== undefined)
|
||||||
desc = expandedLoader.item.currentTitle;
|
desc = expandedLoader.item.currentTitle;
|
||||||
|
_savedCooldownMs = editCooldownMs;
|
||||||
saveBind(origKey, {
|
saveBind(origKey, {
|
||||||
key: editKey,
|
key: editKey,
|
||||||
action: editAction,
|
action: editAction,
|
||||||
desc: desc
|
desc: desc,
|
||||||
|
cooldownMs: editCooldownMs
|
||||||
});
|
});
|
||||||
hasChanges = false;
|
hasChanges = false;
|
||||||
addingNewKey = false;
|
addingNewKey = false;
|
||||||
@@ -1431,6 +1446,57 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("Cooldown")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
Layout.preferredWidth: 60
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: cooldownField
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.preferredHeight: 40
|
||||||
|
placeholderText: "0"
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onEditCooldownMsChanged() {
|
||||||
|
const newText = root.editCooldownMs > 0 ? String(root.editCooldownMs) : "";
|
||||||
|
if (cooldownField.text !== newText)
|
||||||
|
cooldownField.text = newText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
text = root.editCooldownMs > 0 ? String(root.editCooldownMs) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
const val = parseInt(text) || 0;
|
||||||
|
if (val !== root.editCooldownMs)
|
||||||
|
root.updateEdit({
|
||||||
|
cooldownMs: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: I18n.tr("ms")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: 1
|
Layout.preferredHeight: 1
|
||||||
|
|||||||
Reference in New Issue
Block a user