mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-15 08:42:47 -04:00
Compare commits
9 Commits
1bec20ecef
...
7f15227de1
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f15227de1 | |||
| bb45240665 | |||
| 29f84aeab5 | |||
| 5a52edcad8 | |||
| b078e23aa1 | |||
| 7fa87125b5 | |||
| f618df46d8 | |||
| ee03853901 | |||
| 6c4a9bcfb8 |
@@ -18,9 +18,117 @@ on:
|
||||
- cron: '0 */3 * * *' # Every 3 hours for dms-git builds
|
||||
|
||||
jobs:
|
||||
update-obs:
|
||||
check-updates:
|
||||
name: Check for updates
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
outputs:
|
||||
has_updates: ${{ steps.check.outputs.has_updates }}
|
||||
packages: ${{ steps.check.outputs.packages }}
|
||||
version: ${{ steps.check.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install OSC
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y osc
|
||||
|
||||
mkdir -p ~/.config/osc
|
||||
cat > ~/.config/osc/oscrc << EOF
|
||||
[general]
|
||||
apiurl = https://api.opensuse.org
|
||||
|
||||
[https://api.opensuse.org]
|
||||
user = ${{ secrets.OBS_USERNAME }}
|
||||
pass = ${{ secrets.OBS_PASSWORD }}
|
||||
EOF
|
||||
chmod 600 ~/.config/osc/oscrc
|
||||
|
||||
- name: Check for updates
|
||||
id: check
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/ ]]; then
|
||||
echo "packages=dms" >> $GITHUB_OUTPUT
|
||||
VERSION="${GITHUB_REF#refs/tags/}"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "Triggered by tag: $VERSION (always update)"
|
||||
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
|
||||
echo "packages=dms-git" >> $GITHUB_OUTPUT
|
||||
echo "Checking if dms-git source has changed..."
|
||||
|
||||
# Get latest commit hash from master branch
|
||||
LATEST_COMMIT=$(git rev-parse origin/master 2>/dev/null || git rev-parse master 2>/dev/null || echo "")
|
||||
|
||||
if [[ -z "$LATEST_COMMIT" ]]; then
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "Could not determine git commit, proceeding with update"
|
||||
else
|
||||
# Check OBS for last uploaded commit
|
||||
OBS_BASE="$HOME/.cache/osc-checkouts"
|
||||
mkdir -p "$OBS_BASE"
|
||||
OBS_PROJECT="home:AvengeMedia:dms-git"
|
||||
|
||||
if [[ -d "$OBS_BASE/$OBS_PROJECT/dms-git" ]]; then
|
||||
cd "$OBS_BASE/$OBS_PROJECT/dms-git"
|
||||
osc up -q 2>/dev/null || true
|
||||
|
||||
# Check tarball age - if older than 3 hours, update needed
|
||||
if [[ -f "dms-git-source.tar.gz" ]]; then
|
||||
TARBALL_MTIME=$(stat -c%Y "dms-git-source.tar.gz" 2>/dev/null || echo "0")
|
||||
CURRENT_TIME=$(date +%s)
|
||||
AGE_SECONDS=$((CURRENT_TIME - TARBALL_MTIME))
|
||||
AGE_HOURS=$((AGE_SECONDS / 3600))
|
||||
|
||||
# If tarball is older than 3 hours, check for new commits
|
||||
if [[ $AGE_HOURS -ge 3 ]]; then
|
||||
# Check if there are new commits in the last 3 hours
|
||||
cd "${{ github.workspace }}"
|
||||
NEW_COMMITS=$(git log --since="3 hours ago" --oneline origin/master 2>/dev/null | wc -l)
|
||||
|
||||
if [[ $NEW_COMMITS -gt 0 ]]; then
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "📋 New commits detected in last 3 hours, update needed"
|
||||
else
|
||||
echo "has_updates=false" >> $GITHUB_OUTPUT
|
||||
echo "📋 No new commits in last 3 hours, skipping update"
|
||||
fi
|
||||
else
|
||||
echo "has_updates=false" >> $GITHUB_OUTPUT
|
||||
echo "📋 Recent upload exists (< 3 hours), skipping update"
|
||||
fi
|
||||
else
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "📋 No existing tarball in OBS, update needed"
|
||||
fi
|
||||
cd "${{ github.workspace }}"
|
||||
else
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "📋 First upload to OBS, update needed"
|
||||
fi
|
||||
fi
|
||||
elif [[ -n "${{ github.event.inputs.package }}" ]]; then
|
||||
echo "packages=${{ github.event.inputs.package }}" >> $GITHUB_OUTPUT
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "Manual trigger: ${{ github.event.inputs.package }}"
|
||||
else
|
||||
echo "packages=all" >> $GITHUB_OUTPUT
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
update-obs:
|
||||
name: Upload to OBS
|
||||
needs: check-updates
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
needs.check-updates.outputs.has_updates == 'true'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -36,13 +144,13 @@ jobs:
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Triggered by tag: $VERSION"
|
||||
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
|
||||
echo "packages=dms-git" >> $GITHUB_OUTPUT
|
||||
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
|
||||
echo "Triggered by schedule: updating git package"
|
||||
elif [[ -n "${{ github.event.inputs.package }}" ]]; then
|
||||
echo "packages=${{ github.event.inputs.package }}" >> $GITHUB_OUTPUT
|
||||
echo "Manual trigger: ${{ github.event.inputs.package }}"
|
||||
else
|
||||
echo "packages=all" >> $GITHUB_OUTPUT
|
||||
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Update version in packaging files
|
||||
@@ -85,6 +193,7 @@ jobs:
|
||||
|
||||
- name: Upload to OBS
|
||||
env:
|
||||
FORCE_REBUILD: ${{ github.event_name == 'workflow_dispatch' && 'true' || '' }}
|
||||
REBUILD_RELEASE: ${{ github.event.inputs.rebuild_release }}
|
||||
run: |
|
||||
PACKAGES="${{ steps.packages.outputs.packages }}"
|
||||
@@ -111,4 +220,7 @@ jobs:
|
||||
if [[ -n "${{ steps.packages.outputs.version }}" ]]; then
|
||||
echo "- **Version**: ${{ steps.packages.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
if [[ "${{ needs.check-updates.outputs.has_updates }}" == "false" ]]; then
|
||||
echo "- **Status**: Skipped (no changes detected)" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
echo "- **Project**: https://build.opensuse.org/project/show/home:AvengeMedia" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -39,6 +39,9 @@ override_dh_auto_build:
|
||||
elif [ -f dms-source.tar.gz ]; then \
|
||||
tar -xzf dms-source.tar.gz; \
|
||||
fi; \
|
||||
if [ ! -d DankMaterialShell-$(UPSTREAM_VERSION) ] && [ -d DankMaterialShell-0.6.2 ]; then \
|
||||
mv DankMaterialShell-0.6.2 DankMaterialShell-$(UPSTREAM_VERSION); \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
|
||||
@@ -46,6 +49,10 @@ override_dh_auto_install:
|
||||
install -Dm755 dms debian/dms/usr/bin/dms
|
||||
|
||||
mkdir -p debian/dms/usr/share/quickshell/dms debian/dms/usr/lib/systemd/user
|
||||
# Handle directory name mismatch again for install step if needed
|
||||
if [ ! -d DankMaterialShell-$(UPSTREAM_VERSION) ] && [ -d DankMaterialShell-0.6.2 ]; then \
|
||||
mv DankMaterialShell-0.6.2 DankMaterialShell-$(UPSTREAM_VERSION); \
|
||||
fi
|
||||
if [ -d DankMaterialShell-$(UPSTREAM_VERSION) ]; then \
|
||||
cp -r DankMaterialShell-$(UPSTREAM_VERSION)/quickshell/* debian/dms/usr/share/quickshell/dms/; \
|
||||
install -Dm644 DankMaterialShell-$(UPSTREAM_VERSION)/quickshell/assets/systemd/dms.service debian/dms/usr/lib/systemd/user/dms.service; \
|
||||
|
||||
+364
-229
@@ -37,8 +37,6 @@ done
|
||||
|
||||
OBS_BASE_PROJECT="home:AvengeMedia"
|
||||
OBS_BASE="$HOME/.cache/osc-checkouts"
|
||||
|
||||
# Available packages
|
||||
AVAILABLE_PACKAGES=(dms dms-git)
|
||||
|
||||
if [[ -z "$PACKAGE" ]]; then
|
||||
@@ -65,11 +63,9 @@ if [[ -z "$MESSAGE" ]]; then
|
||||
MESSAGE="Update packaging"
|
||||
fi
|
||||
|
||||
# Get repo root (2 levels up from distro/scripts/)
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Ensure we're in repo root
|
||||
if [[ ! -d "distro/debian" ]]; then
|
||||
echo "Error: Run this script from the repository root"
|
||||
exit 1
|
||||
@@ -143,7 +139,6 @@ esac
|
||||
OBS_PROJECT="${OBS_BASE_PROJECT}:${PROJECT}"
|
||||
|
||||
echo "==> Target: $OBS_PROJECT / $PACKAGE"
|
||||
echo "==> Message: $MESSAGE"
|
||||
if [[ "$UPLOAD_DEBIAN" == true && "$UPLOAD_OPENSUSE" == true ]]; then
|
||||
echo "==> Distributions: Debian + OpenSUSE"
|
||||
elif [[ "$UPLOAD_DEBIAN" == true ]]; then
|
||||
@@ -152,10 +147,8 @@ elif [[ "$UPLOAD_OPENSUSE" == true ]]; then
|
||||
echo "==> Distribution: OpenSUSE only"
|
||||
fi
|
||||
|
||||
# Create .obs directory if it doesn't exist
|
||||
mkdir -p "$OBS_BASE"
|
||||
|
||||
# Check out package if not already present
|
||||
if [[ ! -d "$OBS_BASE/$OBS_PROJECT/$PACKAGE" ]]; then
|
||||
echo "Checking out $OBS_PROJECT/$PACKAGE..."
|
||||
cd "$OBS_BASE"
|
||||
@@ -167,29 +160,35 @@ WORK_DIR="$OBS_BASE/$OBS_PROJECT/$PACKAGE"
|
||||
|
||||
echo "==> Preparing $PACKAGE for OBS upload"
|
||||
|
||||
# Clean working directory (keep osc metadata)
|
||||
find "$WORK_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.spec" -o -name "_service" -o -name "*.dsc" \) -delete 2>/dev/null || true
|
||||
find "$WORK_DIR" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.tar.xz" -o -name "*.tar.bz2" -o -name "*.tar" -o -name "*.spec" -o -name "_service" -o -name "*.dsc" \) -delete 2>/dev/null || true
|
||||
|
||||
if [[ -f "distro/debian/$PACKAGE/_service" ]]; then
|
||||
echo " - Copying _service (for binary downloads)"
|
||||
cp "distro/debian/$PACKAGE/_service" "$WORK_DIR/"
|
||||
fi
|
||||
|
||||
# Copy OpenSUSE spec if it exists and handle auto-increment
|
||||
CHANGELOG_VERSION=""
|
||||
if [[ -d "distro/debian/$PACKAGE/debian" ]]; then
|
||||
CHANGELOG_VERSION=$(grep -m1 "^$PACKAGE" "distro/debian/$PACKAGE/debian/changelog" 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/' || echo "")
|
||||
if [[ -n "$CHANGELOG_VERSION" ]] && [[ "$CHANGELOG_VERSION" == *"-"* ]]; then
|
||||
SOURCE_FORMAT_CHECK=$(cat "distro/debian/$PACKAGE/debian/source/format" 2>/dev/null || echo "3.0 (quilt)")
|
||||
if [[ "$SOURCE_FORMAT_CHECK" == *"native"* ]]; then
|
||||
CHANGELOG_VERSION=$(echo "$CHANGELOG_VERSION" | sed 's/-[0-9]*$//')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ -f "distro/opensuse/$PACKAGE.spec" ]]; then
|
||||
echo " - Copying $PACKAGE.spec for OpenSUSE"
|
||||
cp "distro/opensuse/$PACKAGE.spec" "$WORK_DIR/"
|
||||
|
||||
# Auto-increment Release if same Version is being rebuilt
|
||||
if [[ -f "$WORK_DIR/.osc/$PACKAGE.spec" ]]; then
|
||||
NEW_VERSION=$(grep "^Version:" "$WORK_DIR/$PACKAGE.spec" | awk '{print $2}' | head -1)
|
||||
NEW_RELEASE=$(grep "^Release:" "$WORK_DIR/$PACKAGE.spec" | sed 's/^Release:[[:space:]]*//' | sed 's/%{?dist}//' | head -1)
|
||||
|
||||
OLD_VERSION=$(grep "^Version:" "$WORK_DIR/.osc/$PACKAGE.spec" | awk '{print $2}' | head -1)
|
||||
OLD_RELEASE=$(grep "^Release:" "$WORK_DIR/.osc/$PACKAGE.spec" | sed 's/^Release:[[:space:]]*//' | sed 's/%{?dist}//' | head -1)
|
||||
|
||||
if [[ "$NEW_VERSION" == "$OLD_VERSION" ]]; then
|
||||
# Same version - increment release number
|
||||
if [[ "$OLD_RELEASE" =~ ^([0-9]+) ]]; then
|
||||
BASE_RELEASE="${BASH_REMATCH[1]}"
|
||||
NEXT_RELEASE=$((BASE_RELEASE + 1))
|
||||
@@ -206,38 +205,33 @@ elif [[ "$UPLOAD_OPENSUSE" == true ]]; then
|
||||
echo " - Warning: OpenSUSE spec file not found, skipping OpenSUSE upload"
|
||||
fi
|
||||
|
||||
# Handle OpenSUSE-only uploads (create tarball without Debian processing)
|
||||
if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ "$UPLOAD_DEBIAN" == false ]] && [[ -f "distro/opensuse/$PACKAGE.spec" ]]; then
|
||||
echo " - OpenSUSE-only upload: creating source tarball"
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
|
||||
# Check _service file to determine how to get source
|
||||
if [[ -f "distro/debian/$PACKAGE/_service" ]]; then
|
||||
# Check for tar_scm (git source)
|
||||
if grep -q "tar_scm" "distro/debian/$PACKAGE/_service"; then
|
||||
GIT_URL=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "url" | sed 's/.*<param name="url">\(.*\)<\/param>.*/\1/')
|
||||
GIT_REVISION=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "revision" | sed 's/.*<param name="revision">\(.*\)<\/param>.*/\1/')
|
||||
if [[ -f "distro/debian/$PACKAGE/_service" ]] && grep -q "tar_scm" "distro/debian/$PACKAGE/_service"; then
|
||||
GIT_URL=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "url" | sed 's/.*<param name="url">\(.*\)<\/param>.*/\1/')
|
||||
GIT_REVISION=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "revision" | sed 's/.*<param name="revision">\(.*\)<\/param>.*/\1/')
|
||||
|
||||
if [[ -n "$GIT_URL" ]]; then
|
||||
echo " Cloning git source from: $GIT_URL (revision: ${GIT_REVISION:-master})"
|
||||
SOURCE_DIR="$TEMP_DIR/dms-git-source"
|
||||
if git clone --depth 1 --branch "${GIT_REVISION:-master}" "$GIT_URL" "$SOURCE_DIR" 2>/dev/null || \
|
||||
git clone --depth 1 "$GIT_URL" "$SOURCE_DIR" 2>/dev/null; then
|
||||
cd "$SOURCE_DIR"
|
||||
if [[ -n "$GIT_REVISION" ]]; then
|
||||
git checkout "$GIT_REVISION" 2>/dev/null || true
|
||||
fi
|
||||
SOURCE_DIR=$(pwd)
|
||||
cd "$REPO_ROOT"
|
||||
if [[ -n "$GIT_URL" ]]; then
|
||||
echo " Cloning git source from: $GIT_URL (revision: ${GIT_REVISION:-master})"
|
||||
SOURCE_DIR="$TEMP_DIR/dms-git-source"
|
||||
if git clone --depth 1 --branch "${GIT_REVISION:-master}" "$GIT_URL" "$SOURCE_DIR" 2>/dev/null || \
|
||||
git clone --depth 1 "$GIT_URL" "$SOURCE_DIR" 2>/dev/null; then
|
||||
cd "$SOURCE_DIR"
|
||||
if [[ -n "$GIT_REVISION" ]]; then
|
||||
git checkout "$GIT_REVISION" 2>/dev/null || true
|
||||
fi
|
||||
rm -rf .git
|
||||
SOURCE_DIR=$(pwd)
|
||||
cd "$REPO_ROOT"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$SOURCE_DIR" && -d "$SOURCE_DIR" ]]; then
|
||||
# Extract Source0 from spec file
|
||||
SOURCE0=$(grep "^Source0:" "distro/opensuse/$PACKAGE.spec" | awk '{print $2}' | head -1)
|
||||
|
||||
if [[ -n "$SOURCE0" ]]; then
|
||||
@@ -273,32 +267,33 @@ fi
|
||||
|
||||
# Generate .dsc file and handle source format (for Debian only)
|
||||
if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; then
|
||||
# Get version from changelog
|
||||
CHANGELOG_VERSION=$(grep -m1 "^$PACKAGE" distro/debian/$PACKAGE/debian/changelog 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/' || echo "0.1.11")
|
||||
# Use CHANGELOG_VERSION already set above, or get it if not set
|
||||
if [[ -z "$CHANGELOG_VERSION" ]]; then
|
||||
CHANGELOG_VERSION=$(grep -m1 "^$PACKAGE" distro/debian/$PACKAGE/debian/changelog 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/' || echo "0.1.11")
|
||||
fi
|
||||
|
||||
# Determine source format
|
||||
SOURCE_FORMAT=$(cat "distro/debian/$PACKAGE/debian/source/format" 2>/dev/null || echo "3.0 (quilt)")
|
||||
|
||||
# Handle native format (3.0 native)
|
||||
# For native format, remove any Debian revision (-N) from version
|
||||
# Native format cannot have revisions, so strip them if present
|
||||
if [[ "$SOURCE_FORMAT" == *"native"* ]] && [[ "$CHANGELOG_VERSION" == *"-"* ]]; then
|
||||
# Remove Debian revision (everything from - onwards)
|
||||
CHANGELOG_VERSION=$(echo "$CHANGELOG_VERSION" | sed 's/-[0-9]*$//')
|
||||
echo " Warning: Removed Debian revision from version for native format: $CHANGELOG_VERSION"
|
||||
fi
|
||||
|
||||
if [[ "$SOURCE_FORMAT" == *"native"* ]]; then
|
||||
echo " - Native format detected: creating combined tarball"
|
||||
|
||||
VERSION="$CHANGELOG_VERSION"
|
||||
|
||||
# Create temp directory for building combined tarball
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
|
||||
# Determine tarball name for native format (use version without revision)
|
||||
COMBINED_TARBALL="${PACKAGE}_${VERSION}.tar.gz"
|
||||
|
||||
SOURCE_DIR=""
|
||||
|
||||
# Check _service file to determine how to get source
|
||||
if [[ -f "distro/debian/$PACKAGE/_service" ]]; then
|
||||
# Check for tar_scm first (git source) - this takes priority for git packages
|
||||
if grep -q "tar_scm" "distro/debian/$PACKAGE/_service"; then
|
||||
# For dms-git, use tar_scm to get git source
|
||||
GIT_URL=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "url" | sed 's/.*<param name="url">\(.*\)<\/param>.*/\1/')
|
||||
GIT_REVISION=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "revision" | sed 's/.*<param name="revision">\(.*\)<\/param>.*/\1/')
|
||||
|
||||
@@ -311,6 +306,7 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
if [[ -n "$GIT_REVISION" ]]; then
|
||||
git checkout "$GIT_REVISION" 2>/dev/null || true
|
||||
fi
|
||||
rm -rf .git
|
||||
SOURCE_DIR=$(pwd)
|
||||
cd "$REPO_ROOT"
|
||||
else
|
||||
@@ -319,16 +315,10 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
fi
|
||||
fi
|
||||
elif grep -q "download_url" "distro/debian/$PACKAGE/_service" && [[ "$PACKAGE" != "dms-git" ]]; then
|
||||
# Extract download_url for source (skip binary downloads)
|
||||
# Look for download_url with "source" in path or .tar.gz/.tar.xz archives
|
||||
# Skip binaries (distropkg, standalone .gz files, etc.)
|
||||
|
||||
# Extract all paths from download_url services
|
||||
ALL_PATHS=$(grep -A 5 '<service name="download_url">' "distro/debian/$PACKAGE/_service" | \
|
||||
grep '<param name="path">' | \
|
||||
sed 's/.*<param name="path">\(.*\)<\/param>.*/\1/')
|
||||
|
||||
# Find source path (has "source" or ends with .tar.gz/.tar.xz, but not distropkg)
|
||||
SOURCE_PATH=""
|
||||
for path in $ALL_PATHS; do
|
||||
if echo "$path" | grep -qE "(source|archive|\.tar\.(gz|xz|bz2))" && \
|
||||
@@ -338,7 +328,6 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
fi
|
||||
done
|
||||
|
||||
# If no source found, try first path that ends with .tar.gz/.tar.xz
|
||||
if [[ -z "$SOURCE_PATH" ]]; then
|
||||
for path in $ALL_PATHS; do
|
||||
if echo "$path" | grep -qE "\.tar\.(gz|xz|bz2)$"; then
|
||||
@@ -349,7 +338,6 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
fi
|
||||
|
||||
if [[ -n "$SOURCE_PATH" ]]; then
|
||||
# Extract the service block containing this path
|
||||
SOURCE_BLOCK=$(awk -v target="$SOURCE_PATH" '
|
||||
/<service name="download_url">/ { in_block=1; block="" }
|
||||
in_block { block=block"\n"$0 }
|
||||
@@ -371,17 +359,16 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
SOURCE_URL="${URL_PROTOCOL}://${URL_HOST}${URL_PATH}"
|
||||
echo " Downloading source from: $SOURCE_URL"
|
||||
|
||||
if wget -q -O "$TEMP_DIR/source-archive" "$SOURCE_URL"; then
|
||||
if wget -q -O "$TEMP_DIR/source-archive" "$SOURCE_URL" 2>/dev/null || \
|
||||
curl -L -f -s -o "$TEMP_DIR/source-archive" "$SOURCE_URL" 2>/dev/null; then
|
||||
cd "$TEMP_DIR"
|
||||
if [[ "$SOURCE_URL" == *.tar.xz ]]; then
|
||||
tar -xJf source-archive
|
||||
elif [[ "$SOURCE_URL" == *.tar.gz ]] || [[ "$SOURCE_URL" == *.tgz ]]; then
|
||||
tar -xzf source-archive
|
||||
fi
|
||||
# GitHub archives extract to DankMaterialShell-VERSION/ or similar
|
||||
SOURCE_DIR=$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" | head -1)
|
||||
if [[ -z "$SOURCE_DIR" ]]; then
|
||||
# Try to find any extracted directory
|
||||
SOURCE_DIR=$(find . -maxdepth 1 -type d ! -name "." | head -1)
|
||||
fi
|
||||
if [[ -z "$SOURCE_DIR" || ! -d "$SOURCE_DIR" ]]; then
|
||||
@@ -391,11 +378,11 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
cd "$REPO_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
# Convert to absolute path
|
||||
SOURCE_DIR=$(cd "$SOURCE_DIR" && pwd)
|
||||
cd "$REPO_ROOT"
|
||||
else
|
||||
echo "Error: Failed to download source from $SOURCE_URL"
|
||||
echo "Tried both wget and curl. Please check the URL and network connectivity."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -417,216 +404,120 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
# Create OpenSUSE-compatible source tarballs BEFORE adding debian/ directory
|
||||
# (OpenSUSE doesn't need debian/ directory)
|
||||
if [[ "$UPLOAD_OPENSUSE" == true ]] && [[ -f "distro/opensuse/$PACKAGE.spec" ]]; then
|
||||
# If SOURCE_DIR is not set (OpenSUSE-only upload), detect source now
|
||||
if [[ -z "$SOURCE_DIR" || ! -d "$SOURCE_DIR" ]]; then
|
||||
echo " - Detecting source for OpenSUSE-only upload"
|
||||
if [[ -z "$TEMP_DIR" ]]; then
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
fi
|
||||
|
||||
# Check _service file to determine how to get source
|
||||
if [[ -f "distro/debian/$PACKAGE/_service" ]]; then
|
||||
# Check for tar_scm first (git source) - this takes priority for git packages
|
||||
if grep -q "tar_scm" "distro/debian/$PACKAGE/_service"; then
|
||||
# For dms-git, use tar_scm to get git source
|
||||
GIT_URL=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "url" | sed 's/.*<param name="url">\(.*\)<\/param>.*/\1/')
|
||||
GIT_REVISION=$(grep -A 5 'name="tar_scm"' "distro/debian/$PACKAGE/_service" | grep "revision" | sed 's/.*<param name="revision">\(.*\)<\/param>.*/\1/')
|
||||
|
||||
if [[ -n "$GIT_URL" ]]; then
|
||||
echo " Cloning git source from: $GIT_URL (revision: ${GIT_REVISION:-master})"
|
||||
SOURCE_DIR="$TEMP_DIR/dms-git-source"
|
||||
if git clone --depth 1 --branch "${GIT_REVISION:-master}" "$GIT_URL" "$SOURCE_DIR" 2>/dev/null || \
|
||||
git clone --depth 1 "$GIT_URL" "$SOURCE_DIR" 2>/dev/null; then
|
||||
cd "$SOURCE_DIR"
|
||||
if [[ -n "$GIT_REVISION" ]]; then
|
||||
git checkout "$GIT_REVISION" 2>/dev/null || true
|
||||
fi
|
||||
SOURCE_DIR=$(pwd)
|
||||
cd "$REPO_ROOT"
|
||||
else
|
||||
echo "Error: Failed to clone git repository"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
elif grep -q "download_url" "distro/debian/$PACKAGE/_service" && [[ "$PACKAGE" != "dms-git" ]]; then
|
||||
# Extract download_url for source (skip binary downloads)
|
||||
ALL_PATHS=$(grep -A 5 '<service name="download_url">' "distro/debian/$PACKAGE/_service" | \
|
||||
grep '<param name="path">' | \
|
||||
sed 's/.*<param name="path">\(.*\)<\/param>.*/\1/')
|
||||
|
||||
# Find source path (has "source" or ends with .tar.gz/.tar.xz, but not distropkg)
|
||||
SOURCE_PATH=""
|
||||
for path in $ALL_PATHS; do
|
||||
if echo "$path" | grep -qE "(source|archive|\.tar\.(gz|xz|bz2))" && \
|
||||
! echo "$path" | grep -qE "(distropkg|binary)"; then
|
||||
SOURCE_PATH="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If no source found, try first path that ends with .tar.gz/.tar.xz
|
||||
if [[ -z "$SOURCE_PATH" ]]; then
|
||||
for path in $ALL_PATHS; do
|
||||
if echo "$path" | grep -qE "\.tar\.(gz|xz|bz2)$"; then
|
||||
SOURCE_PATH="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -n "$SOURCE_PATH" ]]; then
|
||||
# Extract the service block containing this path
|
||||
SOURCE_BLOCK=$(awk -v target="$SOURCE_PATH" '
|
||||
/<service name="download_url">/ { in_block=1; block="" }
|
||||
in_block { block=block"\n"$0 }
|
||||
/<\/service>/ {
|
||||
if (in_block && block ~ target) {
|
||||
print block
|
||||
exit
|
||||
}
|
||||
in_block=0
|
||||
}
|
||||
' "distro/debian/$PACKAGE/_service")
|
||||
|
||||
URL_PROTOCOL=$(echo "$SOURCE_BLOCK" | grep "protocol" | sed 's/.*<param name="protocol">\(.*\)<\/param>.*/\1/' | head -1)
|
||||
URL_HOST=$(echo "$SOURCE_BLOCK" | grep "host" | sed 's/.*<param name="host">\(.*\)<\/param>.*/\1/' | head -1)
|
||||
URL_PATH="$SOURCE_PATH"
|
||||
fi
|
||||
|
||||
if [[ -n "$URL_PROTOCOL" && -n "$URL_HOST" && -n "$URL_PATH" ]]; then
|
||||
SOURCE_URL="${URL_PROTOCOL}://${URL_HOST}${URL_PATH}"
|
||||
echo " Downloading source from: $SOURCE_URL"
|
||||
|
||||
if wget -q -O "$TEMP_DIR/source-archive" "$SOURCE_URL"; then
|
||||
cd "$TEMP_DIR"
|
||||
if [[ "$SOURCE_URL" == *.tar.xz ]]; then
|
||||
tar -xJf source-archive
|
||||
elif [[ "$SOURCE_URL" == *.tar.gz ]] || [[ "$SOURCE_URL" == *.tgz ]]; then
|
||||
tar -xzf source-archive
|
||||
fi
|
||||
# GitHub archives extract to DankMaterialShell-VERSION/ or similar
|
||||
SOURCE_DIR=$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" | head -1)
|
||||
if [[ -z "$SOURCE_DIR" ]]; then
|
||||
# Try to find any extracted directory
|
||||
SOURCE_DIR=$(find . -maxdepth 1 -type d ! -name "." | head -1)
|
||||
fi
|
||||
if [[ -z "$SOURCE_DIR" || ! -d "$SOURCE_DIR" ]]; then
|
||||
echo "Error: Failed to extract source archive or find source directory"
|
||||
echo "Contents of $TEMP_DIR:"
|
||||
ls -la "$TEMP_DIR"
|
||||
cd "$REPO_ROOT"
|
||||
exit 1
|
||||
fi
|
||||
# Convert to absolute path
|
||||
SOURCE_DIR=$(cd "$SOURCE_DIR" && pwd)
|
||||
cd "$REPO_ROOT"
|
||||
else
|
||||
echo "Error: Failed to download source from $SOURCE_URL"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$SOURCE_DIR" || ! -d "$SOURCE_DIR" ]]; then
|
||||
echo "Error: Could not determine or obtain source for $PACKAGE (OpenSUSE-only upload)"
|
||||
echo "SOURCE_DIR: $SOURCE_DIR"
|
||||
if [[ -d "$TEMP_DIR" ]]; then
|
||||
echo "Contents of temp directory:"
|
||||
ls -la "$TEMP_DIR"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " Found source directory: $SOURCE_DIR"
|
||||
fi
|
||||
echo " - Creating OpenSUSE-compatible source tarballs"
|
||||
|
||||
# Extract Source0 from spec file
|
||||
SOURCE0=$(grep "^Source0:" "distro/opensuse/$PACKAGE.spec" | awk '{print $2}' | head -1); if [[ -z "$SOURCE0" && "$PACKAGE" == "dms-git" ]]; then SOURCE0="dms-git-source.tar.gz"; fi
|
||||
SOURCE0=$(grep "^Source0:" "distro/opensuse/$PACKAGE.spec" | awk '{print $2}' | head -1)
|
||||
if [[ -z "$SOURCE0" && "$PACKAGE" == "dms-git" ]]; then
|
||||
SOURCE0="dms-git-source.tar.gz"
|
||||
fi
|
||||
|
||||
if [[ -n "$SOURCE0" ]]; then
|
||||
# Create a separate temporary directory for OpenSUSE tarball creation to avoid conflicts
|
||||
OBS_TARBALL_DIR=$(mktemp -d -t obs-tarball-XXXXXX)
|
||||
cd "$OBS_TARBALL_DIR"
|
||||
|
||||
case "$PACKAGE" in
|
||||
dms)
|
||||
# dms spec expects DankMaterialShell-%{version} directory (from %setup -q -n DankMaterialShell-%{version})
|
||||
# Extract version from spec file
|
||||
DMS_VERSION=$(grep "^Version:" "$REPO_ROOT/distro/opensuse/$PACKAGE.spec" | sed 's/^Version:[[:space:]]*//' | head -1)
|
||||
if [[ -n "$CHANGELOG_VERSION" ]]; then
|
||||
DMS_VERSION="$CHANGELOG_VERSION"
|
||||
else
|
||||
DMS_VERSION=$(grep "^Version:" "$REPO_ROOT/distro/opensuse/$PACKAGE.spec" | sed 's/^Version:[[:space:]]*//' | head -1)
|
||||
fi
|
||||
EXPECTED_DIR="DankMaterialShell-${DMS_VERSION}"
|
||||
echo " Creating $SOURCE0 (directory: $EXPECTED_DIR)"
|
||||
cp -r "$SOURCE_DIR" "$EXPECTED_DIR"
|
||||
if [[ "$SOURCE0" == *.tar.xz ]]; then
|
||||
tar -cJf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -cJf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
elif [[ "$SOURCE0" == *.tar.bz2 ]]; then
|
||||
tar -cjf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -cjf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
else
|
||||
tar -czf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
fi
|
||||
rm -rf "$EXPECTED_DIR"
|
||||
echo " Created $SOURCE0 ($(stat -c%s "$WORK_DIR/$SOURCE0" 2>/dev/null || echo 0) bytes)"
|
||||
;;
|
||||
dms-git)
|
||||
# dms-git spec expects dms-git-source directory (from %setup -q -n dms-git-source)
|
||||
EXPECTED_DIR="dms-git-source"
|
||||
echo " Creating $SOURCE0 (directory: $EXPECTED_DIR)"
|
||||
cp -r "$SOURCE_DIR" "$EXPECTED_DIR"
|
||||
if [[ "$SOURCE0" == *.tar.xz ]]; then
|
||||
tar -cJf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -cJf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
elif [[ "$SOURCE0" == *.tar.bz2 ]]; then
|
||||
tar -cjf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -cjf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
else
|
||||
tar -czf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$SOURCE0" "$EXPECTED_DIR"
|
||||
fi
|
||||
rm -rf "$EXPECTED_DIR"
|
||||
echo " Created $SOURCE0 ($(stat -c%s "$WORK_DIR/$SOURCE0" 2>/dev/null || echo 0) bytes)"
|
||||
;;
|
||||
*)
|
||||
# Generic handling
|
||||
DIR_NAME=$(basename "$SOURCE_DIR")
|
||||
echo " Creating $SOURCE0 (directory: $DIR_NAME)"
|
||||
cp -r "$SOURCE_DIR" "$DIR_NAME"
|
||||
if [[ "$SOURCE0" == *.tar.xz ]]; then
|
||||
tar -cJf "$WORK_DIR/$SOURCE0" "$DIR_NAME"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' -cJf "$WORK_DIR/$SOURCE0" "$DIR_NAME"
|
||||
elif [[ "$SOURCE0" == *.tar.bz2 ]]; then
|
||||
tar -cjf "$WORK_DIR/$SOURCE0" "$DIR_NAME"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' -cjf "$WORK_DIR/$SOURCE0" "$DIR_NAME"
|
||||
else
|
||||
tar -czf "$WORK_DIR/$SOURCE0" "$DIR_NAME"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' -czf "$WORK_DIR/$SOURCE0" "$DIR_NAME"
|
||||
fi
|
||||
rm -rf "$DIR_NAME"
|
||||
echo " Created $SOURCE0 ($(stat -c%s "$WORK_DIR/$SOURCE0" 2>/dev/null || echo 0) bytes)"
|
||||
;;
|
||||
esac
|
||||
# Clean up the tarball work directory
|
||||
cd "$REPO_ROOT"
|
||||
rm -rf "$OBS_TARBALL_DIR"
|
||||
echo " - OpenSUSE source tarballs created"
|
||||
fi
|
||||
|
||||
# Copy spec file
|
||||
cp "distro/opensuse/$PACKAGE.spec" "$WORK_DIR/"
|
||||
fi
|
||||
|
||||
# Copy debian/ directory into source (for Debian builds only)
|
||||
if [[ "$UPLOAD_DEBIAN" == true ]]; then
|
||||
echo " Copying debian/ directory into source"
|
||||
cp -r "distro/debian/$PACKAGE/debian" "$SOURCE_DIR/"
|
||||
|
||||
# Create combined tarball
|
||||
# For dms, rename directory to match what debian/rules expects
|
||||
# debian/rules uses UPSTREAM_VERSION which is the full version from changelog
|
||||
if [[ "$PACKAGE" == "dms" ]]; then
|
||||
CHANGELOG_IN_SOURCE="$SOURCE_DIR/debian/changelog"
|
||||
if [[ -f "$CHANGELOG_IN_SOURCE" ]]; then
|
||||
ACTUAL_VERSION=$(grep -m1 "^$PACKAGE" "$CHANGELOG_IN_SOURCE" 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/' || echo "$VERSION")
|
||||
CURRENT_DIR=$(basename "$SOURCE_DIR")
|
||||
EXPECTED_DIR="DankMaterialShell-${ACTUAL_VERSION}"
|
||||
if [[ "$CURRENT_DIR" != "$EXPECTED_DIR" ]]; then
|
||||
echo " Renaming directory from $CURRENT_DIR to $EXPECTED_DIR to match debian/rules"
|
||||
cd "$(dirname "$SOURCE_DIR")"
|
||||
mv "$CURRENT_DIR" "$EXPECTED_DIR"
|
||||
SOURCE_DIR="$(pwd)/$EXPECTED_DIR"
|
||||
cd "$REPO_ROOT"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -f "$WORK_DIR/$COMBINED_TARBALL"
|
||||
|
||||
echo " Creating combined tarball: $COMBINED_TARBALL"
|
||||
cd "$(dirname "$SOURCE_DIR")"
|
||||
TARBALL_BASE=$(basename "$SOURCE_DIR")
|
||||
tar -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Generate .dsc file for native format
|
||||
if [[ "$PACKAGE" == "dms" ]]; then
|
||||
TARBALL_DIR=$(tar -tzf "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null | head -1 | cut -d'/' -f1)
|
||||
EXPECTED_TARBALL_DIR="DankMaterialShell-${VERSION}"
|
||||
if [[ "$TARBALL_DIR" != "$EXPECTED_TARBALL_DIR" ]]; then
|
||||
echo " Warning: Tarball directory name mismatch: $TARBALL_DIR != $EXPECTED_TARBALL_DIR"
|
||||
echo " This may cause build failures. Recreating tarball..."
|
||||
cd "$(dirname "$SOURCE_DIR")"
|
||||
rm -f "$WORK_DIR/$COMBINED_TARBALL"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE"
|
||||
cd "$REPO_ROOT"
|
||||
fi
|
||||
fi
|
||||
|
||||
TARBALL_SIZE=$(stat -c%s "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null || stat -f%z "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null)
|
||||
TARBALL_MD5=$(md5sum "$WORK_DIR/$COMBINED_TARBALL" | cut -d' ' -f1)
|
||||
|
||||
# Extract Build-Depends from control file
|
||||
BUILD_DEPS="debhelper-compat (= 13)"
|
||||
if [[ -f "distro/debian/$PACKAGE/debian/control" ]]; then
|
||||
CONTROL_DEPS=$(sed -n '/^Build-Depends:/,/^[A-Z]/p' "distro/debian/$PACKAGE/debian/control" | \
|
||||
@@ -654,9 +545,7 @@ EOF
|
||||
echo " - Generated $PACKAGE.dsc for native format"
|
||||
fi
|
||||
else
|
||||
# Quilt format (legacy) - for Debian only
|
||||
if [[ "$UPLOAD_DEBIAN" == true ]]; then
|
||||
# For quilt format, version can have revision
|
||||
if [[ "$CHANGELOG_VERSION" == *"-"* ]]; then
|
||||
VERSION="$CHANGELOG_VERSION"
|
||||
else
|
||||
@@ -683,13 +572,246 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# Change to working directory and commit
|
||||
cd "$WORK_DIR"
|
||||
|
||||
echo "==> Updating working copy"
|
||||
if ! osc up; then
|
||||
echo "Error: Failed to update working copy"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Only auto-increment on manual runs (REBUILD_RELEASE set or not in CI), not automated workflows
|
||||
OLD_DSC_FILE=""
|
||||
if [[ -f "$WORK_DIR/$PACKAGE.dsc" ]]; then
|
||||
OLD_DSC_FILE="$WORK_DIR/$PACKAGE.dsc"
|
||||
elif [[ -f "$WORK_DIR/.osc/sources/$PACKAGE.dsc" ]]; then
|
||||
OLD_DSC_FILE="$WORK_DIR/.osc/sources/$PACKAGE.dsc"
|
||||
fi
|
||||
|
||||
if [[ "$UPLOAD_DEBIAN" == true ]] && [[ "$SOURCE_FORMAT" == *"native"* ]] && [[ -n "$OLD_DSC_FILE" ]]; then
|
||||
OLD_DSC_VERSION=$(grep "^Version:" "$OLD_DSC_FILE" 2>/dev/null | awk '{print $2}' | head -1)
|
||||
|
||||
IS_MANUAL=false
|
||||
if [[ -n "${REBUILD_RELEASE:-}" ]]; then
|
||||
IS_MANUAL=true
|
||||
echo "==> Manual rebuild detected (REBUILD_RELEASE=$REBUILD_RELEASE)"
|
||||
elif [[ -n "${FORCE_REBUILD:-}" ]] && [[ "${FORCE_REBUILD}" == "true" ]]; then
|
||||
IS_MANUAL=true
|
||||
echo "==> Manual workflow trigger detected (FORCE_REBUILD=true)"
|
||||
elif [[ -z "${GITHUB_ACTIONS:-}" ]] && [[ -z "${CI:-}" ]]; then
|
||||
IS_MANUAL=true
|
||||
echo "==> Local/manual run detected (not in CI)"
|
||||
fi
|
||||
|
||||
if [[ -n "$OLD_DSC_VERSION" ]] && [[ "$OLD_DSC_VERSION" == "$CHANGELOG_VERSION" ]] && [[ "$IS_MANUAL" == true ]]; then
|
||||
echo "==> Detected rebuild of same version $CHANGELOG_VERSION, incrementing version"
|
||||
|
||||
if [[ "$CHANGELOG_VERSION" =~ ^([0-9.]+)\+git$ ]]; then
|
||||
BASE_VERSION="${BASH_REMATCH[1]}"
|
||||
NEW_VERSION="${BASE_VERSION}+git1"
|
||||
echo " Incrementing git number: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
elif [[ "$CHANGELOG_VERSION" =~ ^([0-9.]+)\+git([0-9]+)$ ]]; then
|
||||
BASE_VERSION="${BASH_REMATCH[1]}"
|
||||
GIT_NUM="${BASH_REMATCH[2]}"
|
||||
NEW_GIT_NUM=$((GIT_NUM + 1))
|
||||
NEW_VERSION="${BASE_VERSION}+git${NEW_GIT_NUM}"
|
||||
echo " Incrementing git number: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
elif [[ "$CHANGELOG_VERSION" =~ ^([0-9.]+)ppa([0-9]+)$ ]]; then
|
||||
BASE_VERSION="${BASH_REMATCH[1]}"
|
||||
PPA_NUM="${BASH_REMATCH[2]}"
|
||||
NEW_PPA_NUM=$((PPA_NUM + 1))
|
||||
NEW_VERSION="${BASE_VERSION}ppa${NEW_PPA_NUM}"
|
||||
echo " Incrementing PPA number: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
elif [[ "$CHANGELOG_VERSION" =~ ^([0-9.]+)\+git([0-9]+)(\.[a-f0-9]+)?(ppa([0-9]+))?$ ]]; then
|
||||
BASE_VERSION="${BASH_REMATCH[1]}"
|
||||
GIT_NUM="${BASH_REMATCH[2]}"
|
||||
GIT_HASH="${BASH_REMATCH[3]}"
|
||||
PPA_NUM="${BASH_REMATCH[5]}"
|
||||
if [[ -n "$PPA_NUM" ]]; then
|
||||
NEW_PPA_NUM=$((PPA_NUM + 1))
|
||||
NEW_VERSION="${BASE_VERSION}+git${GIT_NUM}${GIT_HASH}ppa${NEW_PPA_NUM}"
|
||||
echo " Incrementing PPA number: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
else
|
||||
NEW_VERSION="${BASE_VERSION}+git${GIT_NUM}${GIT_HASH}ppa1"
|
||||
echo " Adding PPA number: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
fi
|
||||
elif [[ "$CHANGELOG_VERSION" =~ ^([0-9.]+)(-([0-9]+))?$ ]]; then
|
||||
BASE_VERSION="${BASH_REMATCH[1]}"
|
||||
NEW_VERSION="${BASE_VERSION}ppa1"
|
||||
echo " Warning: Native format cannot have Debian revision, converting to PPA format: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
else
|
||||
NEW_VERSION="${CHANGELOG_VERSION}ppa1"
|
||||
echo " Warning: Could not parse version format, appending ppa1: $CHANGELOG_VERSION -> $NEW_VERSION"
|
||||
fi
|
||||
|
||||
if [[ -z "$SOURCE_DIR" ]] || [[ ! -d "$SOURCE_DIR" ]] || [[ ! -d "$SOURCE_DIR/debian" ]]; then
|
||||
echo " Error: Source directory with debian/ not found for version increment"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SOURCE_CHANGELOG="$SOURCE_DIR/debian/changelog"
|
||||
if [[ ! -f "$SOURCE_CHANGELOG" ]]; then
|
||||
echo " Error: Changelog not found in source directory: $SOURCE_CHANGELOG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_CHANGELOG="$REPO_ROOT/distro/debian/$PACKAGE/debian/changelog"
|
||||
TEMP_CHANGELOG=$(mktemp)
|
||||
{
|
||||
echo "$PACKAGE ($NEW_VERSION) unstable; urgency=medium"
|
||||
echo ""
|
||||
echo " * Rebuild to fix repository metadata issues"
|
||||
echo ""
|
||||
echo " -- Avenge Media <AvengeMedia.US@gmail.com> $(date -R)"
|
||||
echo ""
|
||||
if [[ -f "$REPO_CHANGELOG" ]]; then
|
||||
OLD_ENTRY_START=$(grep -n "^$PACKAGE (" "$REPO_CHANGELOG" | sed -n '2p' | cut -d: -f1)
|
||||
if [[ -n "$OLD_ENTRY_START" ]]; then
|
||||
tail -n +$OLD_ENTRY_START "$REPO_CHANGELOG"
|
||||
fi
|
||||
fi
|
||||
} > "$TEMP_CHANGELOG"
|
||||
cp "$TEMP_CHANGELOG" "$SOURCE_CHANGELOG"
|
||||
rm -f "$TEMP_CHANGELOG"
|
||||
|
||||
CHANGELOG_VERSION="$NEW_VERSION"
|
||||
VERSION="$NEW_VERSION"
|
||||
COMBINED_TARBALL="${PACKAGE}_${VERSION}.tar.gz"
|
||||
|
||||
for old_tarball in "${PACKAGE}"_*.tar.gz; do
|
||||
if [[ -f "$old_tarball" ]] && [[ "$old_tarball" != "${PACKAGE}_${NEW_VERSION}.tar.gz" ]]; then
|
||||
echo " Removing old tarball from OBS: $old_tarball"
|
||||
osc rm -f "$old_tarball" 2>/dev/null || rm -f "$old_tarball"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$PACKAGE" == "dms" ]] && [[ -f "$WORK_DIR/dms-source.tar.gz" ]]; then
|
||||
echo " Recreating dms-source.tar.gz with new directory name for incremented version"
|
||||
EXPECTED_SOURCE_DIR="DankMaterialShell-${NEW_VERSION}"
|
||||
TEMP_SOURCE_DIR=$(mktemp -d)
|
||||
cd "$TEMP_SOURCE_DIR"
|
||||
tar -xzf "$WORK_DIR/dms-source.tar.gz" 2>/dev/null || tar -xJf "$WORK_DIR/dms-source.tar.gz" 2>/dev/null || tar -xjf "$WORK_DIR/dms-source.tar.gz" 2>/dev/null
|
||||
EXTRACTED=$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" | head -1)
|
||||
if [[ -n "$EXTRACTED" ]] && [[ "$EXTRACTED" != "./$EXPECTED_SOURCE_DIR" ]]; then
|
||||
echo " Renaming $EXTRACTED to $EXPECTED_SOURCE_DIR"
|
||||
mv "$EXTRACTED" "$EXPECTED_SOURCE_DIR"
|
||||
rm -f "$WORK_DIR/dms-source.tar.gz"
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/dms-source.tar.gz" "$EXPECTED_SOURCE_DIR"
|
||||
ROOT_DIR=$(tar -tf "$WORK_DIR/dms-source.tar.gz" | head -1 | cut -d/ -f1)
|
||||
if [[ "$ROOT_DIR" != "$EXPECTED_SOURCE_DIR" ]]; then
|
||||
echo " Error: Recreated tarball has wrong root directory: $ROOT_DIR (expected $EXPECTED_SOURCE_DIR)"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
cd "$REPO_ROOT"
|
||||
rm -rf "$TEMP_SOURCE_DIR"
|
||||
fi
|
||||
|
||||
echo " Recreating tarball with new version: $COMBINED_TARBALL"
|
||||
if [[ -n "$SOURCE_DIR" ]] && [[ -d "$SOURCE_DIR" ]] && [[ -d "$SOURCE_DIR/debian" ]]; then
|
||||
if [[ "$PACKAGE" == "dms" ]]; then
|
||||
cd "$(dirname "$SOURCE_DIR")"
|
||||
CURRENT_DIR=$(basename "$SOURCE_DIR")
|
||||
EXPECTED_DIR="DankMaterialShell-${NEW_VERSION}"
|
||||
if [[ "$CURRENT_DIR" != "$EXPECTED_DIR" ]]; then
|
||||
echo " Renaming directory from $CURRENT_DIR to $EXPECTED_DIR to match debian/rules"
|
||||
if [[ -d "$CURRENT_DIR" ]]; then
|
||||
mv "$CURRENT_DIR" "$EXPECTED_DIR"
|
||||
SOURCE_DIR="$(pwd)/$EXPECTED_DIR"
|
||||
else
|
||||
echo " Warning: Source directory $CURRENT_DIR not found, extracting from existing tarball"
|
||||
OLD_TARBALL=$(ls "${PACKAGE}"_*.tar.gz 2>/dev/null | head -1)
|
||||
if [[ -f "$OLD_TARBALL" ]]; then
|
||||
EXTRACT_DIR=$(mktemp -d)
|
||||
cd "$EXTRACT_DIR"
|
||||
tar -xzf "$WORK_DIR/$OLD_TARBALL"
|
||||
EXTRACTED_DIR=$(find . -maxdepth 1 -type d -name "DankMaterialShell-*" | head -1)
|
||||
if [[ -n "$EXTRACTED_DIR" ]] && [[ "$EXTRACTED_DIR" != "./$EXPECTED_DIR" ]]; then
|
||||
mv "$EXTRACTED_DIR" "$EXPECTED_DIR"
|
||||
if [[ -f "$EXPECTED_DIR/debian/changelog" ]]; then
|
||||
ACTUAL_VER=$(grep -m1 "^$PACKAGE" "$EXPECTED_DIR/debian/changelog" 2>/dev/null | sed 's/.*(\([^)]*\)).*/\1/')
|
||||
if [[ "$ACTUAL_VER" != "$NEW_VERSION" ]]; then
|
||||
echo " Updating changelog version in extracted directory"
|
||||
REPO_CHANGELOG="$REPO_ROOT/distro/debian/$PACKAGE/debian/changelog"
|
||||
TEMP_CHANGELOG=$(mktemp)
|
||||
{
|
||||
echo "$PACKAGE ($NEW_VERSION) unstable; urgency=medium"
|
||||
echo ""
|
||||
echo " * Rebuild to fix repository metadata issues"
|
||||
echo ""
|
||||
echo " -- Avenge Media <AvengeMedia.US@gmail.com> $(date -R)"
|
||||
echo ""
|
||||
if [[ -f "$REPO_CHANGELOG" ]]; then
|
||||
OLD_ENTRY_START=$(grep -n "^$PACKAGE (" "$REPO_CHANGELOG" | sed -n '2p' | cut -d: -f1)
|
||||
if [[ -n "$OLD_ENTRY_START" ]]; then
|
||||
tail -n +$OLD_ENTRY_START "$REPO_CHANGELOG"
|
||||
fi
|
||||
fi
|
||||
} > "$TEMP_CHANGELOG"
|
||||
cp "$TEMP_CHANGELOG" "$EXPECTED_DIR/debian/changelog"
|
||||
rm -f "$TEMP_CHANGELOG"
|
||||
fi
|
||||
fi
|
||||
SOURCE_DIR="$(pwd)/$EXPECTED_DIR"
|
||||
cd "$REPO_ROOT"
|
||||
else
|
||||
echo " Error: Could not extract or find source directory"
|
||||
rm -rf "$EXTRACT_DIR"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " Error: No existing tarball found to extract"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
cd "$(dirname "$SOURCE_DIR")"
|
||||
TARBALL_BASE=$(basename "$SOURCE_DIR")
|
||||
tar --sort=name --mtime='2000-01-01 00:00:00' --owner=0 --group=0 -czf "$WORK_DIR/$COMBINED_TARBALL" "$TARBALL_BASE"
|
||||
cd "$WORK_DIR"
|
||||
|
||||
TARBALL_SIZE=$(stat -c%s "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null || stat -f%z "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null)
|
||||
TARBALL_MD5=$(md5sum "$WORK_DIR/$COMBINED_TARBALL" | cut -d' ' -f1)
|
||||
|
||||
BUILD_DEPS="debhelper-compat (= 13)"
|
||||
if [[ -f "distro/debian/$PACKAGE/debian/control" ]]; then
|
||||
CONTROL_DEPS=$(sed -n '/^Build-Depends:/,/^[A-Z]/p' "distro/debian/$PACKAGE/debian/control" | \
|
||||
sed '/^Build-Depends:/s/^Build-Depends: *//' | \
|
||||
sed '/^[A-Z]/d' | \
|
||||
tr '\n' ' ' | \
|
||||
sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/[[:space:]]\+/ /g')
|
||||
if [[ -n "$CONTROL_DEPS" && "$CONTROL_DEPS" != "" ]]; then
|
||||
BUILD_DEPS="$CONTROL_DEPS"
|
||||
fi
|
||||
fi
|
||||
|
||||
cat > "$WORK_DIR/$PACKAGE.dsc" << EOF
|
||||
Format: 3.0 (native)
|
||||
Source: $PACKAGE
|
||||
Binary: $PACKAGE
|
||||
Architecture: any
|
||||
Version: $VERSION
|
||||
Maintainer: Avenge Media <AvengeMedia.US@gmail.com>
|
||||
Build-Depends: $BUILD_DEPS
|
||||
Files:
|
||||
$TARBALL_MD5 $TARBALL_SIZE $COMBINED_TARBALL
|
||||
EOF
|
||||
echo " - Updated changelog and recreated tarball with version $NEW_VERSION"
|
||||
else
|
||||
echo " Error: Source directory not found, cannot recreate tarball"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
find . -maxdepth 1 -type f \( -name "*.dsc" -o -name "*.spec" \) -exec grep -l "^<<<<<<< " {} \; 2>/dev/null | while read -r conflicted_file; do
|
||||
echo " Removing conflicted text file: $conflicted_file"
|
||||
rm -f "$conflicted_file"
|
||||
done
|
||||
|
||||
echo "==> Staging changes"
|
||||
# List files to be uploaded
|
||||
echo "Files to upload:"
|
||||
# Only list files relevant to the selected upload type
|
||||
if [[ "$UPLOAD_DEBIAN" == true ]] && [[ "$UPLOAD_OPENSUSE" == true ]]; then
|
||||
ls -lh *.tar.gz *.tar.xz *.tar *.spec *.dsc _service 2>/dev/null | awk '{print " " $9 " (" $5 ")"}'
|
||||
elif [[ "$UPLOAD_DEBIAN" == true ]]; then
|
||||
@@ -699,35 +821,48 @@ elif [[ "$UPLOAD_OPENSUSE" == true ]]; then
|
||||
fi
|
||||
echo ""
|
||||
|
||||
osc addremove
|
||||
osc addremove 2>&1 | grep -v "Git SCM package" || true
|
||||
|
||||
echo "==> Committing to OBS"
|
||||
osc commit -m "$MESSAGE"
|
||||
SOURCE_TARBALL="${PACKAGE}-source.tar.gz"
|
||||
if [[ -f "$SOURCE_TARBALL" ]]; then
|
||||
echo "==> Ensuring $SOURCE_TARBALL is tracked by OBS"
|
||||
osc add "$SOURCE_TARBALL" 2>&1 | grep -v "already added\|already tracked\|Git SCM package" || true
|
||||
elif [[ -f "$WORK_DIR/$SOURCE_TARBALL" ]]; then
|
||||
echo "==> Copying $SOURCE_TARBALL from WORK_DIR and adding to OBS"
|
||||
cp "$WORK_DIR/$SOURCE_TARBALL" "$SOURCE_TARBALL"
|
||||
osc add "$SOURCE_TARBALL" 2>&1 | grep -v "already added\|already tracked\|Git SCM package" || true
|
||||
fi
|
||||
ADDREMOVE_EXIT=${PIPESTATUS[0]}
|
||||
if [[ $ADDREMOVE_EXIT -ne 0 ]] && [[ $ADDREMOVE_EXIT -ne 1 ]]; then
|
||||
echo "Warning: osc addremove returned exit code $ADDREMOVE_EXIT"
|
||||
fi
|
||||
|
||||
if osc status | grep -q '^C'; then
|
||||
echo "==> Resolving conflicts"
|
||||
osc status | grep '^C' | awk '{print $2}' | xargs -r osc resolved
|
||||
fi
|
||||
|
||||
if ! osc status 2>/dev/null | grep -qE '^[MAD]|^[?]'; then
|
||||
echo "==> No changes to commit (package already up to date)"
|
||||
else
|
||||
echo "==> Committing to OBS"
|
||||
set +e
|
||||
osc commit -m "$MESSAGE" 2>&1 | grep -v "Git SCM package" | grep -v "apiurl\|project\|_ObsPrj\|_manifest\|git-obs"
|
||||
COMMIT_EXIT=${PIPESTATUS[0]}
|
||||
set -e
|
||||
if [[ $COMMIT_EXIT -ne 0 ]]; then
|
||||
echo "Error: Upload failed with exit code $COMMIT_EXIT"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "==> Checking build status"
|
||||
osc results
|
||||
|
||||
echo ""
|
||||
echo "Upload complete! Monitor builds with:"
|
||||
echo " cd $WORK_DIR && osc results"
|
||||
echo " cd $WORK_DIR && osc buildlog <repo> <arch>"
|
||||
echo ""
|
||||
|
||||
# Don't cleanup - keep checkout for status checking
|
||||
echo ""
|
||||
echo "Upload complete! Build status:"
|
||||
echo "✅ Upload complete!"
|
||||
cd "$WORK_DIR"
|
||||
osc results 2>&1 | head -10
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
echo ""
|
||||
echo "To check detailed status:"
|
||||
echo " cd $WORK_DIR && osc results"
|
||||
echo " cd $WORK_DIR && osc remotebuildlog $OBS_PROJECT $PACKAGE Debian_13 x86_64"
|
||||
echo ""
|
||||
echo "NOTE: Checkout kept at $WORK_DIR for status checking"
|
||||
echo ""
|
||||
echo "✅ Upload complete!"
|
||||
echo ""
|
||||
echo "Check build status with:"
|
||||
echo " ./distro/scripts/obs-status.sh $PACKAGE"
|
||||
|
||||
@@ -159,6 +159,7 @@ Singleton {
|
||||
property bool showWorkspaceApps: false
|
||||
property int maxWorkspaceIcons: 3
|
||||
property bool workspacesPerMonitor: true
|
||||
property bool showOccupiedWorkspacesOnly: false
|
||||
property bool dwlShowAllTags: false
|
||||
property var workspaceNameIcons: ({})
|
||||
property bool waveProgressEnabled: true
|
||||
@@ -243,6 +244,8 @@ Singleton {
|
||||
property bool lockBeforeSuspend: false
|
||||
property bool preventIdleForMedia: false
|
||||
property bool loginctlLockIntegration: true
|
||||
property bool fadeToLockEnabled: false
|
||||
property int fadeToLockGracePeriod: 5
|
||||
property string launchPrefix: ""
|
||||
property var brightnessDevicePins: ({})
|
||||
property var wifiNetworkPins: ({})
|
||||
|
||||
@@ -74,6 +74,7 @@ var SPEC = {
|
||||
showWorkspaceApps: { def: false },
|
||||
maxWorkspaceIcons: { def: 3 },
|
||||
workspacesPerMonitor: { def: true },
|
||||
showOccupiedWorkspacesOnly: { def: false },
|
||||
dwlShowAllTags: { def: false },
|
||||
workspaceNameIcons: { def: {} },
|
||||
waveProgressEnabled: { def: true },
|
||||
@@ -145,6 +146,8 @@ var SPEC = {
|
||||
lockBeforeSuspend: { def: false },
|
||||
preventIdleForMedia: { def: false },
|
||||
loginctlLockIntegration: { def: true },
|
||||
fadeToLockEnabled: { def: false },
|
||||
fadeToLockGracePeriod: { def: 5 },
|
||||
launchPrefix: { def: "" },
|
||||
brightnessDevicePins: { def: {} },
|
||||
wifiNetworkPins: { def: {} },
|
||||
|
||||
@@ -63,6 +63,46 @@ Item {
|
||||
id: lock
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
|
||||
delegate: Loader {
|
||||
id: fadeWindowLoader
|
||||
required property var modelData
|
||||
active: SettingsData.fadeToLockEnabled
|
||||
asynchronous: false
|
||||
|
||||
sourceComponent: FadeToLockWindow {
|
||||
screen: fadeWindowLoader.modelData
|
||||
|
||||
onFadeCompleted: {
|
||||
IdleService.lockRequested();
|
||||
}
|
||||
|
||||
onFadeCancelled: {
|
||||
console.log("Fade to lock cancelled by user on screen:", fadeWindowLoader.modelData.name);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: IdleService
|
||||
enabled: fadeWindowLoader.item !== null
|
||||
|
||||
function onFadeToLockRequested() {
|
||||
if (fadeWindowLoader.item) {
|
||||
fadeWindowLoader.item.startFade();
|
||||
}
|
||||
}
|
||||
|
||||
function onCancelFadeToLock() {
|
||||
if (fadeWindowLoader.item) {
|
||||
fadeWindowLoader.item.cancelFade();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: dankBarRepeater
|
||||
model: ScriptModel {
|
||||
|
||||
@@ -49,10 +49,7 @@ Item {
|
||||
signal dialogClosed
|
||||
signal backgroundClicked
|
||||
|
||||
readonly property bool useBackgroundWindow: {
|
||||
const layerOverride = Quickshell.env("DMS_MODAL_LAYER");
|
||||
return !layerOverride || layerOverride === "overlay";
|
||||
}
|
||||
readonly property bool useBackgroundWindow: true
|
||||
|
||||
function open() {
|
||||
ModalManager.openModal(root);
|
||||
@@ -146,6 +143,16 @@ Item {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
mask: Region {
|
||||
item: Rectangle {
|
||||
x: root.alignedX
|
||||
y: root.alignedY
|
||||
width: root.shouldBeVisible ? root.alignedWidth : 0
|
||||
height: root.shouldBeVisible ? root.alignedHeight : 0
|
||||
}
|
||||
intersection: Intersection.Xor
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: root.closeOnBackgroundClick && root.shouldBeVisible
|
||||
@@ -186,13 +193,15 @@ Item {
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_MODAL_LAYER")) {
|
||||
case "bottom":
|
||||
return WlrLayershell.Bottom;
|
||||
case "top":
|
||||
console.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer.");
|
||||
return WlrLayershell.Top;
|
||||
case "background":
|
||||
return WlrLayershell.Background;
|
||||
default:
|
||||
console.error("DankModal: 'background' layer is not valid for modals. Defaulting to 'top' layer.");
|
||||
return WlrLayershell.Top;
|
||||
case "overlay":
|
||||
return WlrLayershell.Overlay;
|
||||
default:
|
||||
return WlrLayershell.Top;
|
||||
}
|
||||
}
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
|
||||
@@ -10,12 +10,13 @@ Item {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: Theme.spacingL
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
@@ -76,10 +77,10 @@ Item {
|
||||
checked: SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration
|
||||
enabled: SessionService.loginctlAvailable
|
||||
onToggled: checked => {
|
||||
if (SessionService.loginctlAvailable) {
|
||||
SettingsData.set("loginctlLockIntegration", checked)
|
||||
}
|
||||
}
|
||||
if (SessionService.loginctlAvailable) {
|
||||
SettingsData.set("loginctlLockIntegration", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -160,6 +161,40 @@ Item {
|
||||
onToggled: checked => SettingsData.set("preventIdleForMedia", checked)
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Fade to lock screen")
|
||||
description: I18n.tr("Gradually fade the screen before locking with a configurable grace period")
|
||||
checked: SettingsData.fadeToLockEnabled
|
||||
onToggled: checked => SettingsData.set("fadeToLockEnabled", checked)
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
id: fadeGracePeriodDropdown
|
||||
property var periodOptions: ["1 second", "2 seconds", "3 seconds", "4 seconds", "5 seconds", "10 seconds", "15 seconds", "20 seconds", "30 seconds"]
|
||||
property var periodValues: [1, 2, 3, 4, 5, 10, 15, 20, 30]
|
||||
|
||||
width: parent.width
|
||||
addHorizontalPadding: true
|
||||
text: I18n.tr("Fade grace period")
|
||||
options: periodOptions
|
||||
visible: SettingsData.fadeToLockEnabled
|
||||
enabled: SettingsData.fadeToLockEnabled
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentPeriod = SettingsData.fadeToLockGracePeriod;
|
||||
const index = periodValues.indexOf(currentPeriod);
|
||||
currentValue = index >= 0 ? periodOptions[index] : "5 seconds";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = periodOptions.indexOf(value);
|
||||
if (index >= 0) {
|
||||
SettingsData.set("fadeToLockGracePeriod", periodValues[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
id: lockDropdown
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
@@ -172,29 +207,29 @@ Item {
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout
|
||||
const index = lockDropdown.timeoutValues.indexOf(currentTimeout)
|
||||
lockDropdown.currentValue = index >= 0 ? lockDropdown.timeoutOptions[index] : "Never"
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout;
|
||||
const index = lockDropdown.timeoutValues.indexOf(currentTimeout);
|
||||
lockDropdown.currentValue = index >= 0 ? lockDropdown.timeoutOptions[index] : "Never";
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout
|
||||
const index = timeoutValues.indexOf(currentTimeout)
|
||||
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acLockTimeout : SettingsData.batteryLockTimeout;
|
||||
const index = timeoutValues.indexOf(currentTimeout);
|
||||
currentValue = index >= 0 ? timeoutOptions[index] : "Never";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = timeoutOptions.indexOf(value)
|
||||
if (index >= 0) {
|
||||
const timeout = timeoutValues[index]
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acLockTimeout", timeout)
|
||||
} else {
|
||||
SettingsData.set("batteryLockTimeout", timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
const index = timeoutOptions.indexOf(value);
|
||||
if (index >= 0) {
|
||||
const timeout = timeoutValues[index];
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acLockTimeout", timeout);
|
||||
} else {
|
||||
SettingsData.set("batteryLockTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
@@ -209,29 +244,29 @@ Item {
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout
|
||||
const index = monitorDropdown.timeoutValues.indexOf(currentTimeout)
|
||||
monitorDropdown.currentValue = index >= 0 ? monitorDropdown.timeoutOptions[index] : "Never"
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout;
|
||||
const index = monitorDropdown.timeoutValues.indexOf(currentTimeout);
|
||||
monitorDropdown.currentValue = index >= 0 ? monitorDropdown.timeoutOptions[index] : "Never";
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout
|
||||
const index = timeoutValues.indexOf(currentTimeout)
|
||||
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acMonitorTimeout : SettingsData.batteryMonitorTimeout;
|
||||
const index = timeoutValues.indexOf(currentTimeout);
|
||||
currentValue = index >= 0 ? timeoutOptions[index] : "Never";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = timeoutOptions.indexOf(value)
|
||||
if (index >= 0) {
|
||||
const timeout = timeoutValues[index]
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acMonitorTimeout", timeout)
|
||||
} else {
|
||||
SettingsData.set("batteryMonitorTimeout", timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
const index = timeoutOptions.indexOf(value);
|
||||
if (index >= 0) {
|
||||
const timeout = timeoutValues[index];
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acMonitorTimeout", timeout);
|
||||
} else {
|
||||
SettingsData.set("batteryMonitorTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
@@ -246,29 +281,29 @@ Item {
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout
|
||||
const index = suspendDropdown.timeoutValues.indexOf(currentTimeout)
|
||||
suspendDropdown.currentValue = index >= 0 ? suspendDropdown.timeoutOptions[index] : "Never"
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout;
|
||||
const index = suspendDropdown.timeoutValues.indexOf(currentTimeout);
|
||||
suspendDropdown.currentValue = index >= 0 ? suspendDropdown.timeoutOptions[index] : "Never";
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout
|
||||
const index = timeoutValues.indexOf(currentTimeout)
|
||||
currentValue = index >= 0 ? timeoutOptions[index] : "Never"
|
||||
const currentTimeout = powerCategory.currentIndex === 0 ? SettingsData.acSuspendTimeout : SettingsData.batterySuspendTimeout;
|
||||
const index = timeoutValues.indexOf(currentTimeout);
|
||||
currentValue = index >= 0 ? timeoutOptions[index] : "Never";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = timeoutOptions.indexOf(value)
|
||||
if (index >= 0) {
|
||||
const timeout = timeoutValues[index]
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acSuspendTimeout", timeout)
|
||||
} else {
|
||||
SettingsData.set("batterySuspendTimeout", timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
const index = timeoutOptions.indexOf(value);
|
||||
if (index >= 0) {
|
||||
const timeout = timeoutValues[index];
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acSuspendTimeout", timeout);
|
||||
} else {
|
||||
SettingsData.set("batterySuspendTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -293,25 +328,25 @@ Item {
|
||||
Connections {
|
||||
target: powerCategory
|
||||
function onCurrentIndexChanged() {
|
||||
const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior
|
||||
suspendBehaviorSelector.currentIndex = behavior
|
||||
const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior;
|
||||
suspendBehaviorSelector.currentIndex = behavior;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior
|
||||
currentIndex = behavior
|
||||
const behavior = powerCategory.currentIndex === 0 ? SettingsData.acSuspendBehavior : SettingsData.batterySuspendBehavior;
|
||||
currentIndex = behavior;
|
||||
}
|
||||
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (selected) {
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acSuspendBehavior", index)
|
||||
} else {
|
||||
SettingsData.set("batterySuspendBehavior", index)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selected) {
|
||||
if (powerCategory.currentIndex === 0) {
|
||||
SettingsData.set("acSuspendBehavior", index);
|
||||
} else {
|
||||
SettingsData.set("batterySuspendBehavior", index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,17 +419,17 @@ Item {
|
||||
property var actionValues: ["reboot", "logout", "poweroff", "lock", "suspend", "restart", "hibernate"]
|
||||
|
||||
Component.onCompleted: {
|
||||
const currentAction = SettingsData.powerMenuDefaultAction || "logout"
|
||||
const index = actionValues.indexOf(currentAction)
|
||||
currentValue = index >= 0 ? options[index] : "Log Out"
|
||||
const currentAction = SettingsData.powerMenuDefaultAction || "logout";
|
||||
const index = actionValues.indexOf(currentAction);
|
||||
currentValue = index >= 0 ? options[index] : "Log Out";
|
||||
}
|
||||
|
||||
onValueChanged: value => {
|
||||
const index = options.indexOf(value)
|
||||
if (index >= 0) {
|
||||
SettingsData.set("powerMenuDefaultAction", actionValues[index])
|
||||
}
|
||||
}
|
||||
const index = options.indexOf(value);
|
||||
if (index >= 0) {
|
||||
SettingsData.set("powerMenuDefaultAction", actionValues[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -406,14 +441,14 @@ Item {
|
||||
text: I18n.tr("Show Reboot")
|
||||
checked: SettingsData.powerMenuActions.includes("reboot")
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("reboot")) {
|
||||
actions.push("reboot")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "reboot")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("reboot")) {
|
||||
actions.push("reboot");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "reboot");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -421,14 +456,14 @@ Item {
|
||||
text: I18n.tr("Show Log Out")
|
||||
checked: SettingsData.powerMenuActions.includes("logout")
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("logout")) {
|
||||
actions.push("logout")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "logout")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("logout")) {
|
||||
actions.push("logout");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "logout");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -436,14 +471,14 @@ Item {
|
||||
text: I18n.tr("Show Power Off")
|
||||
checked: SettingsData.powerMenuActions.includes("poweroff")
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("poweroff")) {
|
||||
actions.push("poweroff")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "poweroff")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("poweroff")) {
|
||||
actions.push("poweroff");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "poweroff");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -451,14 +486,14 @@ Item {
|
||||
text: I18n.tr("Show Lock")
|
||||
checked: SettingsData.powerMenuActions.includes("lock")
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("lock")) {
|
||||
actions.push("lock")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "lock")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("lock")) {
|
||||
actions.push("lock");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "lock");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -466,14 +501,14 @@ Item {
|
||||
text: I18n.tr("Show Suspend")
|
||||
checked: SettingsData.powerMenuActions.includes("suspend")
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("suspend")) {
|
||||
actions.push("suspend")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "suspend")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("suspend")) {
|
||||
actions.push("suspend");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "suspend");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -482,14 +517,14 @@ Item {
|
||||
description: I18n.tr("Restart the DankMaterialShell")
|
||||
checked: SettingsData.powerMenuActions.includes("restart")
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("restart")) {
|
||||
actions.push("restart")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "restart")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("restart")) {
|
||||
actions.push("restart");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "restart");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -499,14 +534,14 @@ Item {
|
||||
checked: SettingsData.powerMenuActions.includes("hibernate")
|
||||
visible: SessionService.hibernateSupported
|
||||
onToggled: checked => {
|
||||
let actions = [...SettingsData.powerMenuActions]
|
||||
if (checked && !actions.includes("hibernate")) {
|
||||
actions.push("hibernate")
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "hibernate")
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions)
|
||||
}
|
||||
let actions = [...SettingsData.powerMenuActions];
|
||||
if (checked && !actions.includes("hibernate")) {
|
||||
actions.push("hibernate");
|
||||
} else if (!checked) {
|
||||
actions = actions.filter(a => a !== "hibernate");
|
||||
}
|
||||
SettingsData.set("powerMenuActions", actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -612,12 +647,12 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.customPowerActionLock) {
|
||||
text = SettingsData.customPowerActionLock
|
||||
text = SettingsData.customPowerActionLock;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("customPowerActionLock", text.trim())
|
||||
SettingsData.set("customPowerActionLock", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -644,12 +679,12 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.customPowerActionLogout) {
|
||||
text = SettingsData.customPowerActionLogout
|
||||
text = SettingsData.customPowerActionLogout;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("customPowerActionLogout", text.trim())
|
||||
SettingsData.set("customPowerActionLogout", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,12 +711,12 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.customPowerActionSuspend) {
|
||||
text = SettingsData.customPowerActionSuspend
|
||||
text = SettingsData.customPowerActionSuspend;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("customPowerActionSuspend", text.trim())
|
||||
SettingsData.set("customPowerActionSuspend", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -708,12 +743,12 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.customPowerActionHibernate) {
|
||||
text = SettingsData.customPowerActionHibernate
|
||||
text = SettingsData.customPowerActionHibernate;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("customPowerActionHibernate", text.trim())
|
||||
SettingsData.set("customPowerActionHibernate", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -740,12 +775,12 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.customPowerActionReboot) {
|
||||
text = SettingsData.customPowerActionReboot
|
||||
text = SettingsData.customPowerActionReboot;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("customPowerActionReboot", text.trim())
|
||||
SettingsData.set("customPowerActionReboot", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -772,12 +807,12 @@ Item {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.customPowerActionPowerOff) {
|
||||
text = SettingsData.customPowerActionPowerOff
|
||||
text = SettingsData.customPowerActionPowerOff;
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
SettingsData.set("customPowerActionPowerOff", text.trim())
|
||||
SettingsData.set("customPowerActionPowerOff", text.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -81,7 +80,6 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -105,11 +103,8 @@ Rectangle {
|
||||
return PortalService.setProfileImage("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -121,7 +116,6 @@ Rectangle {
|
||||
propagateComposedEvents: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -145,9 +139,6 @@ Rectangle {
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ FocusScope {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: 0
|
||||
anchors.rightMargin: (parentModal && parentModal.isCompactMode) ? Theme.spacingS : (32 + Theme.spacingS)
|
||||
anchors.bottomMargin: 0
|
||||
anchors.topMargin: 0
|
||||
color: "transparent"
|
||||
@@ -30,15 +30,13 @@ FocusScope {
|
||||
PersonalizationTab {
|
||||
parentModal: root.parentModal
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -49,15 +47,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: TimeWeatherTab {
|
||||
}
|
||||
sourceComponent: TimeWeatherTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -74,10 +70,9 @@ FocusScope {
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -88,15 +83,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: WidgetTweaksTab {
|
||||
}
|
||||
sourceComponent: WidgetTweaksTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -108,17 +101,14 @@ FocusScope {
|
||||
focus: active
|
||||
|
||||
sourceComponent: Component {
|
||||
DockTab {
|
||||
}
|
||||
|
||||
DockTab {}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -129,15 +119,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: DisplaysTab {
|
||||
}
|
||||
sourceComponent: DisplaysTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -148,15 +136,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: LauncherTab {
|
||||
}
|
||||
sourceComponent: LauncherTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -167,15 +153,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: ThemeColorsTab {
|
||||
}
|
||||
sourceComponent: ThemeColorsTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -186,15 +170,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: PowerSettings {
|
||||
}
|
||||
sourceComponent: PowerSettings {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -211,10 +193,9 @@ FocusScope {
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -225,17 +206,13 @@ FocusScope {
|
||||
visible: active
|
||||
focus: active
|
||||
|
||||
sourceComponent: AboutTab {
|
||||
}
|
||||
sourceComponent: AboutTab {}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active && item) {
|
||||
Qt.callLater(() => item.forceActiveFocus())
|
||||
Qt.callLater(() => item.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -234,9 +234,7 @@ FloatingWindow {
|
||||
SettingsContent {
|
||||
id: content
|
||||
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
height: parent.height
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.fill: parent
|
||||
parentModal: settingsModal
|
||||
currentIndex: settingsModal.currentTabIndex
|
||||
}
|
||||
|
||||
@@ -20,19 +20,50 @@ Item {
|
||||
Ref {
|
||||
service: CavaService
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
readonly property real maxBarHeight: Theme.iconSize - 2
|
||||
readonly property real minBarHeight: 3
|
||||
readonly property real heightRange: maxBarHeight - minBarHeight
|
||||
property var barHeights: [minBarHeight, minBarHeight, minBarHeight, minBarHeight, minBarHeight, minBarHeight]
|
||||
|
||||
Timer {
|
||||
id: fallbackTimer
|
||||
|
||||
running: !CavaService.cavaAvailable && isPlaying
|
||||
interval: 256
|
||||
interval: 500
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25];
|
||||
CavaService.values = [Math.random() * 20 + 5, Math.random() * 25 + 8, Math.random() * 22 + 6, Math.random() * 20 + 5, Math.random() * 22 + 6, Math.random() * 25 + 8];
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CavaService
|
||||
function onValuesChanged() {
|
||||
if (!root.isPlaying) {
|
||||
root.barHeights = [root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight, root.minBarHeight];
|
||||
return;
|
||||
}
|
||||
|
||||
const newHeights = [];
|
||||
for (let i = 0; i < 6; i++) {
|
||||
if (CavaService.values.length <= i) {
|
||||
newHeights.push(root.minBarHeight);
|
||||
continue;
|
||||
}
|
||||
|
||||
const rawLevel = CavaService.values[i];
|
||||
if (rawLevel <= 0) {
|
||||
newHeights.push(root.minBarHeight);
|
||||
} else if (rawLevel >= 100) {
|
||||
newHeights.push(root.maxBarHeight);
|
||||
} else {
|
||||
newHeights.push(root.minBarHeight + Math.sqrt(rawLevel * 0.01) * root.heightRange);
|
||||
}
|
||||
}
|
||||
root.barHeights = newHeights;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,33 +76,19 @@ Item {
|
||||
|
||||
Rectangle {
|
||||
width: 2
|
||||
height: {
|
||||
if (root.isPlaying && CavaService.values.length > index) {
|
||||
const rawLevel = CavaService.values[index] || 0;
|
||||
const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100;
|
||||
const maxHeight = Theme.iconSize - 2;
|
||||
const minHeight = 3;
|
||||
return minHeight + (scaledLevel / 100) * (maxHeight - minHeight);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
height: root.barHeights[index]
|
||||
radius: 1.5
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Behavior on height {
|
||||
enabled: root.isPlaying && !CavaService.cavaAvailable
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.standardDecel
|
||||
duration: 100
|
||||
easing.type: Easing.Linear
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? cpuColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuContent.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? cpuColumn.implicitHeight : cpuContent.implicitHeight
|
||||
|
||||
Column {
|
||||
id: cpuColumn
|
||||
@@ -65,79 +65,72 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: cpuContentRoot
|
||||
Row {
|
||||
id: cpuContent
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
implicitWidth: cpuRow.implicitWidth
|
||||
implicitHeight: cpuRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: cpuRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: cpuIcon
|
||||
name: "memory"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuUsage > 80) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (DgopService.cpuUsage > 60) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
DankIcon {
|
||||
id: cpuIcon
|
||||
name: "memory"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuUsage > 80) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
if (DgopService.cpuUsage > 60) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(cpuBaseline.width, cpuText.paintedWidth) : cpuText.paintedWidth
|
||||
implicitHeight: cpuText.implicitHeight
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
implicitWidth: root.minimumWidth ? Math.max(cpuBaseline.width, cpuText.paintedWidth) : cpuText.paintedWidth
|
||||
implicitHeight: cpuText.implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: cpuBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88%"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: cpuText
|
||||
text: {
|
||||
const v = DgopService.cpuUsage;
|
||||
if (v === undefined || v === null || v === 0) {
|
||||
return "--%";
|
||||
}
|
||||
return v.toFixed(0) + "%";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
StyledTextMetrics {
|
||||
id: cpuBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88%"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: cpuText
|
||||
text: {
|
||||
const v = DgopService.cpuUsage;
|
||||
if (v === undefined || v === null || v === 0) {
|
||||
return "--%";
|
||||
}
|
||||
return v.toFixed(0) + "%";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuTempContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? cpuTempColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuTempRow.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? cpuTempColumn.implicitHeight : cpuTempRow.implicitHeight
|
||||
|
||||
Column {
|
||||
id: cpuTempColumn
|
||||
@@ -65,79 +65,72 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: cpuTempContentRoot
|
||||
Row {
|
||||
id: cpuTempRow
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
implicitWidth: cpuTempRow.implicitWidth
|
||||
implicitHeight: cpuTempRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: cpuTempRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: cpuTempIcon
|
||||
name: "device_thermostat"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuTemperature > 85) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (DgopService.cpuTemperature > 69) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
DankIcon {
|
||||
id: cpuTempIcon
|
||||
name: "device_thermostat"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuTemperature > 85) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
if (DgopService.cpuTemperature > 69) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(tempBaseline.width, cpuTempText.paintedWidth) : cpuTempText.paintedWidth
|
||||
implicitHeight: cpuTempText.implicitHeight
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
implicitWidth: root.minimumWidth ? Math.max(tempBaseline.width, cpuTempText.paintedWidth) : cpuTempText.paintedWidth
|
||||
implicitHeight: cpuTempText.implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: tempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88°"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: cpuTempText
|
||||
text: {
|
||||
if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) {
|
||||
return "--°";
|
||||
}
|
||||
|
||||
return Math.round(DgopService.cpuTemperature) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
StyledTextMetrics {
|
||||
id: tempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88°"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: cpuTempText
|
||||
text: {
|
||||
if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) {
|
||||
return "--°";
|
||||
}
|
||||
|
||||
return Math.round(DgopService.cpuTemperature) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +93,8 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : gpuTempContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? gpuTempColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : gpuTempRow.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? gpuTempColumn.implicitHeight : gpuTempRow.implicitHeight
|
||||
|
||||
Column {
|
||||
id: gpuTempColumn
|
||||
@@ -133,79 +133,72 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: gpuTempContentRoot
|
||||
Row {
|
||||
id: gpuTempRow
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
implicitWidth: gpuTempRow.implicitWidth
|
||||
implicitHeight: gpuTempRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: gpuTempRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: gpuTempIcon
|
||||
name: "auto_awesome_mosaic"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (root.displayTemp > 80) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (root.displayTemp > 65) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
DankIcon {
|
||||
id: gpuTempIcon
|
||||
name: "auto_awesome_mosaic"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (root.displayTemp > 80) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
if (root.displayTemp > 65) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(gpuTempBaseline.width, gpuTempText.paintedWidth) : gpuTempText.paintedWidth
|
||||
implicitHeight: gpuTempText.implicitHeight
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
implicitWidth: root.minimumWidth ? Math.max(gpuTempBaseline.width, gpuTempText.paintedWidth) : gpuTempText.paintedWidth
|
||||
implicitHeight: gpuTempText.implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: gpuTempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88°"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: gpuTempText
|
||||
text: {
|
||||
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
|
||||
return "--°";
|
||||
}
|
||||
|
||||
return Math.round(root.displayTemp) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
StyledTextMetrics {
|
||||
id: gpuTempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88°"
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: gpuTempText
|
||||
text: {
|
||||
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
|
||||
return "--°";
|
||||
}
|
||||
|
||||
return Math.round(root.displayTemp) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,9 +101,24 @@ BasePill {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
AudioVisualization {
|
||||
Item {
|
||||
width: 20
|
||||
height: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
AudioVisualization {
|
||||
anchors.fill: parent
|
||||
visible: CavaService.cavaAvailable
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.fill: parent
|
||||
name: "music_note"
|
||||
size: 20
|
||||
color: Theme.primary
|
||||
visible: !CavaService.cavaAvailable
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -165,28 +180,38 @@ BasePill {
|
||||
id: mediaInfo
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
AudioVisualization {
|
||||
Item {
|
||||
width: 20
|
||||
height: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
AudioVisualization {
|
||||
anchors.fill: parent
|
||||
visible: CavaService.cavaAvailable
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.fill: parent
|
||||
name: "music_note"
|
||||
size: 20
|
||||
color: Theme.primary
|
||||
visible: !CavaService.cavaAvailable
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: textContainer
|
||||
readonly property string cachedIdentity: activePlayer ? (activePlayer.identity || "") : ""
|
||||
readonly property string lowerIdentity: cachedIdentity.toLowerCase()
|
||||
readonly property bool isWebMedia: lowerIdentity.includes("firefox") || lowerIdentity.includes("chrome") || lowerIdentity.includes("chromium") || lowerIdentity.includes("edge") || lowerIdentity.includes("safari")
|
||||
|
||||
property string displayText: {
|
||||
if (!activePlayer || !activePlayer.trackTitle) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let identity = activePlayer.identity || "";
|
||||
let isWebMedia = identity.toLowerCase().includes("firefox") || identity.toLowerCase().includes("chrome") || identity.toLowerCase().includes("chromium") || identity.toLowerCase().includes("edge") || identity.toLowerCase().includes("safari");
|
||||
let title = "";
|
||||
let subtitle = "";
|
||||
if (isWebMedia && activePlayer.trackTitle) {
|
||||
title = activePlayer.trackTitle;
|
||||
subtitle = activePlayer.trackArtist || identity;
|
||||
} else {
|
||||
title = activePlayer.trackTitle || "Unknown Track";
|
||||
subtitle = activePlayer.trackArtist || "";
|
||||
}
|
||||
const title = isWebMedia ? activePlayer.trackTitle : (activePlayer.trackTitle || "Unknown Track");
|
||||
const subtitle = isWebMedia ? (activePlayer.trackArtist || cachedIdentity) : (activePlayer.trackArtist || "");
|
||||
return subtitle.length > 0 ? title + " • " + subtitle : title;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : ramContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? ramColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : ramContent.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? ramColumn.implicitHeight : ramContent.implicitHeight
|
||||
|
||||
Column {
|
||||
id: ramColumn
|
||||
@@ -75,93 +75,86 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: ramContentRoot
|
||||
Row {
|
||||
id: ramContent
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
implicitWidth: ramRow.implicitWidth
|
||||
implicitHeight: ramRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: ramRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: ramIcon
|
||||
name: "developer_board"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.memoryUsage > 90) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (DgopService.memoryUsage > 75) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
DankIcon {
|
||||
id: ramIcon
|
||||
name: "developer_board"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.memoryUsage > 90) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
if (DgopService.memoryUsage > 75) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(ramBaseline.width, ramText.paintedWidth) : ramText.paintedWidth
|
||||
implicitHeight: ramText.implicitHeight
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
implicitWidth: root.minimumWidth ? Math.max(ramBaseline.width, ramText.paintedWidth) : ramText.paintedWidth
|
||||
implicitHeight: ramText.implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: ramBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: {
|
||||
if (!root.showSwap) {
|
||||
return "88%";
|
||||
}
|
||||
if (root.swapUsage < 10) {
|
||||
return "88% · 0%";
|
||||
}
|
||||
return "88% · 88%";
|
||||
StyledTextMetrics {
|
||||
id: ramBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: {
|
||||
if (!root.showSwap) {
|
||||
return "88%";
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: ramText
|
||||
text: {
|
||||
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
|
||||
return "--%";
|
||||
}
|
||||
|
||||
let ramText = DgopService.memoryUsage.toFixed(0) + "%";
|
||||
if (root.showSwap && DgopService.totalSwapKB > 0) {
|
||||
return ramText + " · " + root.swapUsage.toFixed(0) + "%";
|
||||
}
|
||||
return ramText;
|
||||
if (root.swapUsage < 10) {
|
||||
return "88% · 0%";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
wrapMode: Text.NoWrap
|
||||
return "88% · 88%";
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: ramText
|
||||
text: {
|
||||
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
|
||||
return "--%";
|
||||
}
|
||||
|
||||
let ramText = DgopService.memoryUsage.toFixed(0) + "%";
|
||||
if (root.showSwap && DgopService.totalSwapKB > 0) {
|
||||
return ramText + " · " + root.swapUsage.toFixed(0) + "%";
|
||||
}
|
||||
return ramText;
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,34 +115,48 @@ Item {
|
||||
|
||||
function getHyprlandWorkspaces() {
|
||||
const workspaces = Hyprland.workspaces?.values || [];
|
||||
if (workspaces.length === 0)
|
||||
if (workspaces.length === 0) {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
name: "1"
|
||||
}
|
||||
];
|
||||
|
||||
const filtered = workspaces.filter(ws => ws.id > -1);
|
||||
if (filtered.length === 0)
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
name: "1"
|
||||
}
|
||||
];
|
||||
|
||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
return filtered.slice().sort((a, b) => a.id - b.id);
|
||||
}
|
||||
|
||||
const monitorWorkspaces = filtered.filter(ws => ws.monitor?.name === root.screenName);
|
||||
return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.id - b.id) : [
|
||||
{
|
||||
id: 1,
|
||||
name: "1"
|
||||
}
|
||||
];
|
||||
let filtered = workspaces.filter(ws => ws.id > -1);
|
||||
if (filtered.length === 0) {
|
||||
return [
|
||||
{
|
||||
id: 1,
|
||||
name: "1"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
filtered = filtered.slice().sort((a, b) => a.id - b.id);
|
||||
} else {
|
||||
const monitorWorkspaces = filtered.filter(ws => ws.monitor?.name === root.screenName);
|
||||
filtered = monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.id - b.id) : [
|
||||
{
|
||||
id: 1,
|
||||
name: "1"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
if (!SettingsData.showOccupiedWorkspacesOnly) {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || []);
|
||||
const activeWsId = root.currentWorkspace;
|
||||
return filtered.filter(ws => {
|
||||
if (ws.id === activeWsId)
|
||||
return true;
|
||||
return hyprlandToplevels.some(tl => tl.workspace?.id === ws.id);
|
||||
});
|
||||
}
|
||||
|
||||
function getHyprlandActiveWorkspace() {
|
||||
@@ -287,12 +301,26 @@ Item {
|
||||
return [1, 2];
|
||||
}
|
||||
|
||||
let workspaces;
|
||||
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
|
||||
return NiriService.getCurrentOutputWorkspaceNumbers();
|
||||
workspaces = NiriService.getCurrentOutputWorkspaceNumbers();
|
||||
} else {
|
||||
const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName).map(ws => ws.idx + 1);
|
||||
workspaces = displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2];
|
||||
}
|
||||
|
||||
const displayWorkspaces = NiriService.allWorkspaces.filter(ws => ws.output === root.screenName).map(ws => ws.idx + 1);
|
||||
return displayWorkspaces.length > 0 ? displayWorkspaces : [1, 2];
|
||||
if (!SettingsData.showOccupiedWorkspacesOnly) {
|
||||
return workspaces;
|
||||
}
|
||||
|
||||
return workspaces.filter(wsNum => {
|
||||
const workspace = NiriService.allWorkspaces.find(w => w.idx + 1 === wsNum && w.output === root.screenName);
|
||||
if (!workspace)
|
||||
return false;
|
||||
if (workspace.is_active)
|
||||
return true;
|
||||
return NiriService.windows?.some(win => win.workspace_id === workspace.id) ?? false;
|
||||
});
|
||||
}
|
||||
|
||||
function getNiriActiveWorkspace() {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
property bool active: false
|
||||
|
||||
signal fadeCompleted
|
||||
signal fadeCancelled
|
||||
|
||||
visible: active
|
||||
color: "transparent"
|
||||
|
||||
WlrLayershell.namespace: "dms:fade-to-lock"
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: active ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
left: true
|
||||
right: true
|
||||
top: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: fadeOverlay
|
||||
anchors.fill: parent
|
||||
color: "black"
|
||||
opacity: 0
|
||||
|
||||
onOpacityChanged: {
|
||||
if (opacity >= 0.99 && root.active) {
|
||||
root.fadeCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: fadeSeq
|
||||
running: false
|
||||
|
||||
NumberAnimation {
|
||||
target: fadeOverlay
|
||||
property: "opacity"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: SettingsData.fadeToLockGracePeriod * 1000
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
function startFade() {
|
||||
if (!SettingsData.fadeToLockEnabled)
|
||||
return;
|
||||
active = true;
|
||||
fadeOverlay.opacity = 0.0;
|
||||
fadeSeq.stop();
|
||||
fadeSeq.start();
|
||||
}
|
||||
|
||||
function cancelFade() {
|
||||
fadeSeq.stop();
|
||||
fadeOverlay.opacity = 0.0;
|
||||
active = false;
|
||||
fadeCancelled();
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: root.active
|
||||
onClicked: root.cancelFade()
|
||||
onPressed: root.cancelFade()
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
anchors.fill: parent
|
||||
focus: root.active
|
||||
|
||||
Keys.onPressed: event => {
|
||||
root.cancelFade();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (active) {
|
||||
forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
if (active) {
|
||||
forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,23 +15,23 @@ Scope {
|
||||
property bool processingExternalEvent: false
|
||||
|
||||
Component.onCompleted: {
|
||||
IdleService.lockComponent = this
|
||||
IdleService.lockComponent = this;
|
||||
}
|
||||
|
||||
function lock() {
|
||||
if (SettingsData.customPowerActionLock && SettingsData.customPowerActionLock.length > 0) {
|
||||
Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock])
|
||||
return
|
||||
Quickshell.execDetached(["sh", "-c", SettingsData.customPowerActionLock]);
|
||||
return;
|
||||
}
|
||||
if (!processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
|
||||
DMSService.lockSession(response => {
|
||||
if (response.error) {
|
||||
console.warn("Lock: Failed to call loginctl.lock:", response.error)
|
||||
shouldLock = true
|
||||
console.warn("Lock: Failed to call loginctl.lock:", response.error);
|
||||
shouldLock = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
shouldLock = true
|
||||
shouldLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,32 +39,32 @@ Scope {
|
||||
if (!processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
|
||||
DMSService.unlockSession(response => {
|
||||
if (response.error) {
|
||||
console.warn("Lock: Failed to call loginctl.unlock:", response.error)
|
||||
shouldLock = false
|
||||
console.warn("Lock: Failed to call loginctl.unlock:", response.error);
|
||||
shouldLock = false;
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
shouldLock = false
|
||||
shouldLock = false;
|
||||
}
|
||||
}
|
||||
|
||||
function activate() {
|
||||
lock()
|
||||
lock();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionService
|
||||
|
||||
function onSessionLocked() {
|
||||
processingExternalEvent = true
|
||||
shouldLock = true
|
||||
processingExternalEvent = false
|
||||
processingExternalEvent = true;
|
||||
shouldLock = true;
|
||||
processingExternalEvent = false;
|
||||
}
|
||||
|
||||
function onSessionUnlocked() {
|
||||
processingExternalEvent = true
|
||||
shouldLock = false
|
||||
processingExternalEvent = false
|
||||
processingExternalEvent = true;
|
||||
shouldLock = false;
|
||||
processingExternalEvent = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ Scope {
|
||||
target: IdleService
|
||||
|
||||
function onLockRequested() {
|
||||
lock()
|
||||
lock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,11 +93,11 @@ Scope {
|
||||
screenName: lockSurface.screen?.name ?? ""
|
||||
isLocked: shouldLock
|
||||
onUnlockRequested: {
|
||||
root.unlock()
|
||||
root.unlock();
|
||||
}
|
||||
onPasswordChanged: newPassword => {
|
||||
root.sharedPasswordBuffer = newPassword
|
||||
}
|
||||
root.sharedPasswordBuffer = newPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,21 +113,21 @@ Scope {
|
||||
if (!root.processingExternalEvent && SettingsData.loginctlLockIntegration && DMSService.isConnected) {
|
||||
DMSService.lockSession(response => {
|
||||
if (response.error) {
|
||||
console.warn("Lock: Failed to call loginctl.lock:", response.error)
|
||||
root.shouldLock = true
|
||||
console.warn("Lock: Failed to call loginctl.lock:", response.error);
|
||||
root.shouldLock = true;
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
root.shouldLock = true
|
||||
root.shouldLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
function demo() {
|
||||
demoWindow.showDemo()
|
||||
demoWindow.showDemo();
|
||||
}
|
||||
|
||||
function isLocked(): bool {
|
||||
return sessionLock.locked
|
||||
return sessionLock.locked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
@@ -30,52 +29,60 @@ Item {
|
||||
signal unlockRequested
|
||||
|
||||
function pickRandomFact() {
|
||||
randomFact = Facts.getRandomFact()
|
||||
randomFact = Facts.getRandomFact();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (demoMode) {
|
||||
pickRandomFact()
|
||||
pickRandomFact();
|
||||
}
|
||||
|
||||
WeatherService.addRef()
|
||||
UserInfoService.refreshUserInfo()
|
||||
WeatherService.addRef();
|
||||
UserInfoService.refreshUserInfo();
|
||||
|
||||
if (CompositorService.isHyprland) {
|
||||
updateHyprlandLayout()
|
||||
hyprlandLayoutUpdateTimer.start()
|
||||
updateHyprlandLayout();
|
||||
hyprlandLayoutUpdateTimer.start();
|
||||
}
|
||||
|
||||
lockerReadyArmed = true
|
||||
lockerReadyArmed = true;
|
||||
}
|
||||
|
||||
onDemoModeChanged: {
|
||||
if (demoMode) {
|
||||
pickRandomFact()
|
||||
pickRandomFact();
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
WeatherService.removeRef()
|
||||
WeatherService.removeRef();
|
||||
if (CompositorService.isHyprland) {
|
||||
hyprlandLayoutUpdateTimer.stop()
|
||||
hyprlandLayoutUpdateTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
function sendLockerReadyOnce() {
|
||||
if (lockerReadySent) return;
|
||||
if (root.unlocking) return;
|
||||
if (lockerReadySent)
|
||||
return;
|
||||
if (root.unlocking)
|
||||
return;
|
||||
lockerReadySent = true;
|
||||
if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) {
|
||||
DMSService.sendRequest("loginctl.lockerReady", null, resp => {
|
||||
if (resp?.error) console.warn("lockerReady failed:", resp.error)
|
||||
else console.log("lockerReady sent (afterAnimating/afterRendering)");
|
||||
if (resp?.error)
|
||||
console.warn("lockerReady failed:", resp.error);
|
||||
else
|
||||
console.log("lockerReady sent (afterAnimating/afterRendering)");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function maybeSend() {
|
||||
if (!lockerReadyArmed) return;
|
||||
if (root.unlocking) return;
|
||||
if (!root.visible || root.opacity <= 0) return;
|
||||
if (!lockerReadyArmed)
|
||||
return;
|
||||
if (root.unlocking)
|
||||
return;
|
||||
if (!root.visible || root.opacity <= 0)
|
||||
return;
|
||||
Qt.callLater(() => {
|
||||
if (root.visible && root.opacity > 0 && !root.unlocking)
|
||||
sendLockerReadyOnce();
|
||||
@@ -86,8 +93,12 @@ Item {
|
||||
target: root.Window.window
|
||||
enabled: target !== null
|
||||
|
||||
function onAfterAnimating() { maybeSend(); }
|
||||
function onAfterRendering() { maybeSend(); }
|
||||
function onAfterAnimating() {
|
||||
maybeSend();
|
||||
}
|
||||
function onAfterRendering() {
|
||||
maybeSend();
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: maybeSend()
|
||||
@@ -95,7 +106,7 @@ Item {
|
||||
|
||||
function updateHyprlandLayout() {
|
||||
if (CompositorService.isHyprland) {
|
||||
hyprlandLayoutProcess.running = true
|
||||
hyprlandLayoutProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,27 +117,27 @@ Item {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
const data = JSON.parse(text)
|
||||
const mainKeyboard = data.keyboards.find(kb => kb.main === true)
|
||||
hyprlandKeyboard = mainKeyboard.name
|
||||
const data = JSON.parse(text);
|
||||
const mainKeyboard = data.keyboards.find(kb => kb.main === true);
|
||||
hyprlandKeyboard = mainKeyboard.name;
|
||||
if (mainKeyboard && mainKeyboard.active_keymap) {
|
||||
const parts = mainKeyboard.active_keymap.split(" ")
|
||||
const parts = mainKeyboard.active_keymap.split(" ");
|
||||
if (parts.length > 0) {
|
||||
hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase()
|
||||
hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase();
|
||||
} else {
|
||||
hyprlandCurrentLayout = mainKeyboard.active_keymap.substring(0, 2).toUpperCase()
|
||||
hyprlandCurrentLayout = mainKeyboard.active_keymap.substring(0, 2).toUpperCase();
|
||||
}
|
||||
} else {
|
||||
hyprlandCurrentLayout = ""
|
||||
hyprlandCurrentLayout = "";
|
||||
}
|
||||
if (mainKeyboard && mainKeyboard.layout_names) {
|
||||
hyprlandLayoutCount = mainKeyboard.layout_names.length
|
||||
hyprlandLayoutCount = mainKeyboard.layout_names.length;
|
||||
} else {
|
||||
hyprlandLayoutCount = 0
|
||||
hyprlandLayoutCount = 0;
|
||||
}
|
||||
} catch (e) {
|
||||
hyprlandCurrentLayout = ""
|
||||
hyprlandLayoutCount = 0
|
||||
hyprlandCurrentLayout = "";
|
||||
hyprlandLayoutCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,8 +154,8 @@ Item {
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
active: {
|
||||
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
|
||||
return !currentWallpaper || (currentWallpaper && currentWallpaper.startsWith("#"))
|
||||
var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
|
||||
return !currentWallpaper || (currentWallpaper && currentWallpaper.startsWith("#"));
|
||||
}
|
||||
asynchronous: true
|
||||
|
||||
@@ -158,8 +169,8 @@ Item {
|
||||
|
||||
anchors.fill: parent
|
||||
source: {
|
||||
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
|
||||
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? currentWallpaper : ""
|
||||
var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
|
||||
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? currentWallpaper : "";
|
||||
}
|
||||
fillMode: Theme.getFillMode(SettingsData.wallpaperFillMode)
|
||||
smooth: true
|
||||
@@ -213,8 +224,8 @@ Item {
|
||||
spacing: 0
|
||||
|
||||
property string fullTimeStr: {
|
||||
const format = SettingsData.getEffectiveTimeFormat()
|
||||
return systemClock.date.toLocaleTimeString(Qt.locale(), format)
|
||||
const format = SettingsData.getEffectiveTimeFormat();
|
||||
return systemClock.date.toLocaleTimeString(Qt.locale(), format);
|
||||
}
|
||||
property var timeParts: fullTimeStr.split(':')
|
||||
property string hours: timeParts[0] || ""
|
||||
@@ -222,8 +233,8 @@ Item {
|
||||
property string secondsWithAmPm: timeParts.length > 2 ? timeParts[2] : ""
|
||||
property string seconds: secondsWithAmPm.replace(/\s*(AM|PM|am|pm)$/i, '')
|
||||
property string ampm: {
|
||||
const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i)
|
||||
return match ? match[0].trim() : ""
|
||||
const match = fullTimeStr.match(/\s*(AM|PM|am|pm)$/i);
|
||||
return match ? match[0].trim() : "";
|
||||
}
|
||||
property bool hasSeconds: timeParts.length > 2
|
||||
|
||||
@@ -322,9 +333,9 @@ Item {
|
||||
anchors.verticalCenterOffset: -25
|
||||
text: {
|
||||
if (SettingsData.lockDateFormat && SettingsData.lockDateFormat.length > 0) {
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat)
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat);
|
||||
}
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), Locale.LongFormat)
|
||||
return systemClock.date.toLocaleDateString(Qt.locale(), Locale.LongFormat);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeXLarge
|
||||
color: "white"
|
||||
@@ -347,14 +358,14 @@ Item {
|
||||
Layout.preferredHeight: 60
|
||||
imageSource: {
|
||||
if (PortalService.profileImage === "") {
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
|
||||
if (PortalService.profileImage.startsWith("/")) {
|
||||
return "file://" + PortalService.profileImage
|
||||
return "file://" + PortalService.profileImage;
|
||||
}
|
||||
|
||||
return PortalService.profileImage
|
||||
return PortalService.profileImage;
|
||||
}
|
||||
fallbackIcon: "person"
|
||||
}
|
||||
@@ -414,20 +425,20 @@ Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: lockIconContainer.width + Theme.spacingM * 2
|
||||
anchors.rightMargin: {
|
||||
let margin = Theme.spacingM
|
||||
let margin = Theme.spacingM;
|
||||
if (loadingSpinner.visible) {
|
||||
margin += loadingSpinner.width
|
||||
margin += loadingSpinner.width;
|
||||
}
|
||||
if (enterButton.visible) {
|
||||
margin += enterButton.width + 2
|
||||
margin += enterButton.width + 2;
|
||||
}
|
||||
if (virtualKeyboardButton.visible) {
|
||||
margin += virtualKeyboardButton.width
|
||||
margin += virtualKeyboardButton.width;
|
||||
}
|
||||
if (revealButton.visible) {
|
||||
margin += revealButton.width
|
||||
margin += revealButton.width;
|
||||
}
|
||||
return margin
|
||||
return margin;
|
||||
}
|
||||
opacity: 0
|
||||
focus: true
|
||||
@@ -436,36 +447,36 @@ Item {
|
||||
echoMode: parent.showPassword ? TextInput.Normal : TextInput.Password
|
||||
onTextChanged: {
|
||||
if (!demoMode) {
|
||||
root.passwordBuffer = text
|
||||
root.passwordBuffer = text;
|
||||
}
|
||||
}
|
||||
onAccepted: {
|
||||
if (!demoMode && !pam.passwd.active) {
|
||||
console.log("Enter pressed, starting PAM authentication")
|
||||
pam.passwd.start()
|
||||
console.log("Enter pressed, starting PAM authentication");
|
||||
pam.passwd.start();
|
||||
}
|
||||
}
|
||||
Keys.onPressed: event => {
|
||||
if (demoMode) {
|
||||
return
|
||||
}
|
||||
if (demoMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pam.passwd.active) {
|
||||
console.log("PAM is active, ignoring input")
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
}
|
||||
if (pam.passwd.active) {
|
||||
console.log("PAM is active, ignoring input");
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!demoMode) {
|
||||
forceActiveFocus()
|
||||
forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && !demoMode) {
|
||||
forceActiveFocus()
|
||||
forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,9 +484,9 @@ Item {
|
||||
if (!activeFocus && !demoMode && visible && passwordField && !powerMenu.isVisible) {
|
||||
Qt.callLater(() => {
|
||||
if (passwordField && passwordField.forceActiveFocus) {
|
||||
passwordField.forceActiveFocus()
|
||||
passwordField.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,9 +494,9 @@ Item {
|
||||
if (enabled && !demoMode && visible && passwordField && !powerMenu.isVisible) {
|
||||
Qt.callLater(() => {
|
||||
if (passwordField && passwordField.forceActiveFocus) {
|
||||
passwordField.forceActiveFocus()
|
||||
passwordField.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -506,15 +517,15 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: {
|
||||
if (demoMode) {
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
if (root.unlocking) {
|
||||
return "Unlocking..."
|
||||
return "Unlocking...";
|
||||
}
|
||||
if (pam.passwd.active) {
|
||||
return "Authenticating..."
|
||||
return "Authenticating...";
|
||||
}
|
||||
return "Password..."
|
||||
return "Password...";
|
||||
}
|
||||
color: root.unlocking ? Theme.primary : (pam.passwd.active ? Theme.primary : Theme.outline)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
@@ -543,12 +554,12 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: {
|
||||
if (demoMode) {
|
||||
return "••••••••"
|
||||
return "••••••••";
|
||||
}
|
||||
if (parent.showPassword) {
|
||||
return root.passwordBuffer
|
||||
return root.passwordBuffer;
|
||||
}
|
||||
return "•".repeat(root.passwordBuffer.length)
|
||||
return "•".repeat(root.passwordBuffer.length);
|
||||
}
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: parent.showPassword ? Theme.fontSizeMedium : Theme.fontSizeLarge
|
||||
@@ -589,9 +600,9 @@ Item {
|
||||
enabled: visible
|
||||
onClicked: {
|
||||
if (keyboardController.isKeyboardActive) {
|
||||
keyboardController.hide()
|
||||
keyboardController.hide();
|
||||
} else {
|
||||
keyboardController.show()
|
||||
keyboardController.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -690,8 +701,8 @@ Item {
|
||||
enabled: !demoMode
|
||||
onClicked: {
|
||||
if (!demoMode) {
|
||||
console.log("Enter button clicked, starting PAM authentication")
|
||||
pam.passwd.start()
|
||||
console.log("Enter button clicked, starting PAM authentication");
|
||||
pam.passwd.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,15 +728,15 @@ Item {
|
||||
Layout.preferredHeight: 20
|
||||
text: {
|
||||
if (root.pamState === "error") {
|
||||
return "Authentication error - try again"
|
||||
return "Authentication error - try again";
|
||||
}
|
||||
if (root.pamState === "max") {
|
||||
return "Too many attempts - locked out"
|
||||
return "Too many attempts - locked out";
|
||||
}
|
||||
if (root.pamState === "fail") {
|
||||
return "Incorrect password - try again"
|
||||
return "Incorrect password - try again";
|
||||
}
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
color: Theme.error
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
@@ -793,11 +804,11 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: {
|
||||
if (CompositorService.isNiri) {
|
||||
return NiriService.keyboardLayoutNames.length > 1
|
||||
return NiriService.keyboardLayoutNames.length > 1;
|
||||
} else if (CompositorService.isHyprland) {
|
||||
return hyprlandLayoutCount > 1
|
||||
return hyprlandLayoutCount > 1;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -823,17 +834,18 @@ Item {
|
||||
StyledText {
|
||||
text: {
|
||||
if (CompositorService.isNiri) {
|
||||
const layout = NiriService.getCurrentKeyboardLayoutName()
|
||||
if (!layout) return ""
|
||||
const parts = layout.split(" ")
|
||||
const layout = NiriService.getCurrentKeyboardLayoutName();
|
||||
if (!layout)
|
||||
return "";
|
||||
const parts = layout.split(" ");
|
||||
if (parts.length > 0) {
|
||||
return parts[0].substring(0, 2).toUpperCase()
|
||||
return parts[0].substring(0, 2).toUpperCase();
|
||||
}
|
||||
return layout.substring(0, 2).toUpperCase()
|
||||
return layout.substring(0, 2).toUpperCase();
|
||||
} else if (CompositorService.isHyprland) {
|
||||
return hyprlandCurrentLayout
|
||||
return hyprlandCurrentLayout;
|
||||
}
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Light
|
||||
@@ -851,15 +863,10 @@ Item {
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onClicked: {
|
||||
if (CompositorService.isNiri) {
|
||||
NiriService.cycleKeyboardLayout()
|
||||
NiriService.cycleKeyboardLayout();
|
||||
} else if (CompositorService.isHyprland) {
|
||||
Quickshell.execDetached([
|
||||
"hyprctl",
|
||||
"switchxkblayout",
|
||||
hyprlandKeyboard,
|
||||
"next"
|
||||
])
|
||||
updateHyprlandLayout()
|
||||
Quickshell.execDetached(["hyprctl", "switchxkblayout", hyprlandKeyboard, "next"]);
|
||||
updateHyprlandLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -898,7 +905,7 @@ Item {
|
||||
interval: 256
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25]
|
||||
CavaService.values = [Math.random() * 40 + 10, Math.random() * 60 + 20, Math.random() * 50 + 15, Math.random() * 35 + 20, Math.random() * 45 + 15, Math.random() * 55 + 25];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -914,13 +921,13 @@ Item {
|
||||
width: 2
|
||||
height: {
|
||||
if (MprisController.activePlayer?.playbackState === MprisPlaybackState.Playing && CavaService.values.length > index) {
|
||||
const rawLevel = CavaService.values[index] || 0
|
||||
const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100
|
||||
const maxHeight = Theme.iconSize - 2
|
||||
const minHeight = 3
|
||||
return minHeight + (scaledLevel / 100) * (maxHeight - minHeight)
|
||||
const rawLevel = CavaService.values[index] || 0;
|
||||
const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100;
|
||||
const maxHeight = Theme.iconSize - 2;
|
||||
const minHeight = 3;
|
||||
return minHeight + (scaledLevel / 100) * (maxHeight - minHeight);
|
||||
}
|
||||
return 3
|
||||
return 3;
|
||||
}
|
||||
radius: 1.5
|
||||
color: "white"
|
||||
@@ -940,11 +947,12 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const player = MprisController.activePlayer
|
||||
if (!player?.trackTitle) return ""
|
||||
const title = player.trackTitle
|
||||
const artist = player.trackArtist || ""
|
||||
return artist ? title + " • " + artist : title
|
||||
const player = MprisController.activePlayer;
|
||||
if (!player?.trackTitle)
|
||||
return "";
|
||||
const title = player.trackTitle;
|
||||
const artist = player.trackArtist || "";
|
||||
return artist ? title + " • " + artist : title;
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: "white"
|
||||
@@ -1099,15 +1107,15 @@ Item {
|
||||
DankIcon {
|
||||
name: {
|
||||
if (!AudioService.sink?.audio) {
|
||||
return "volume_up"
|
||||
return "volume_up";
|
||||
}
|
||||
if (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0) {
|
||||
return "volume_off"
|
||||
return "volume_off";
|
||||
}
|
||||
if (AudioService.sink.audio.volume * 100 < 33) {
|
||||
return "volume_down"
|
||||
return "volume_down";
|
||||
}
|
||||
return "volume_up"
|
||||
return "volume_up";
|
||||
}
|
||||
size: Theme.iconSize - 2
|
||||
color: (AudioService.sink && AudioService.sink.audio && (AudioService.sink.audio.muted || AudioService.sink.audio.volume === 0)) ? Qt.rgba(255, 255, 255, 0.5) : "white"
|
||||
@@ -1133,95 +1141,95 @@ Item {
|
||||
name: {
|
||||
if (BatteryService.isCharging) {
|
||||
if (BatteryService.batteryLevel >= 90) {
|
||||
return "battery_charging_full"
|
||||
return "battery_charging_full";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 80) {
|
||||
return "battery_charging_90"
|
||||
return "battery_charging_90";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 60) {
|
||||
return "battery_charging_80"
|
||||
return "battery_charging_80";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 50) {
|
||||
return "battery_charging_60"
|
||||
return "battery_charging_60";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 30) {
|
||||
return "battery_charging_50"
|
||||
return "battery_charging_50";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 20) {
|
||||
return "battery_charging_30"
|
||||
return "battery_charging_30";
|
||||
}
|
||||
|
||||
return "battery_charging_20"
|
||||
return "battery_charging_20";
|
||||
}
|
||||
if (BatteryService.isPluggedIn) {
|
||||
if (BatteryService.batteryLevel >= 90) {
|
||||
return "battery_charging_full"
|
||||
return "battery_charging_full";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 80) {
|
||||
return "battery_charging_90"
|
||||
return "battery_charging_90";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 60) {
|
||||
return "battery_charging_80"
|
||||
return "battery_charging_80";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 50) {
|
||||
return "battery_charging_60"
|
||||
return "battery_charging_60";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 30) {
|
||||
return "battery_charging_50"
|
||||
return "battery_charging_50";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 20) {
|
||||
return "battery_charging_30"
|
||||
return "battery_charging_30";
|
||||
}
|
||||
|
||||
return "battery_charging_20"
|
||||
return "battery_charging_20";
|
||||
}
|
||||
if (BatteryService.batteryLevel >= 95) {
|
||||
return "battery_full"
|
||||
return "battery_full";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 85) {
|
||||
return "battery_6_bar"
|
||||
return "battery_6_bar";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 70) {
|
||||
return "battery_5_bar"
|
||||
return "battery_5_bar";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 55) {
|
||||
return "battery_4_bar"
|
||||
return "battery_4_bar";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 40) {
|
||||
return "battery_3_bar"
|
||||
return "battery_3_bar";
|
||||
}
|
||||
|
||||
if (BatteryService.batteryLevel >= 25) {
|
||||
return "battery_2_bar"
|
||||
return "battery_2_bar";
|
||||
}
|
||||
|
||||
return "battery_1_bar"
|
||||
return "battery_1_bar";
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: {
|
||||
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
|
||||
return Theme.error
|
||||
return Theme.error;
|
||||
}
|
||||
|
||||
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
|
||||
return Theme.primary
|
||||
return Theme.primary;
|
||||
}
|
||||
|
||||
return "white"
|
||||
return "white";
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
@@ -1246,9 +1254,9 @@ Item {
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
if (demoMode) {
|
||||
console.log("Demo: Power Menu")
|
||||
console.log("Demo: Power Menu");
|
||||
} else {
|
||||
powerMenu.show()
|
||||
powerMenu.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1272,18 +1280,18 @@ Item {
|
||||
id: pam
|
||||
lockSecured: !demoMode
|
||||
onUnlockRequested: {
|
||||
root.unlocking = true
|
||||
lockerReadyArmed = false
|
||||
passwordField.text = ""
|
||||
root.passwordBuffer = ""
|
||||
root.unlockRequested()
|
||||
root.unlocking = true;
|
||||
lockerReadyArmed = false;
|
||||
passwordField.text = "";
|
||||
root.passwordBuffer = "";
|
||||
root.unlockRequested();
|
||||
}
|
||||
onStateChanged: {
|
||||
root.pamState = state
|
||||
root.pamState = state;
|
||||
if (state !== "") {
|
||||
placeholderDelay.restart()
|
||||
passwordField.text = ""
|
||||
root.passwordBuffer = ""
|
||||
placeholderDelay.restart();
|
||||
passwordField.text = "";
|
||||
root.passwordBuffer = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1312,7 +1320,7 @@ Item {
|
||||
showLogout: true
|
||||
onClosed: {
|
||||
if (!demoMode && passwordField && passwordField.forceActiveFocus) {
|
||||
Qt.callLater(() => passwordField.forceActiveFocus())
|
||||
Qt.callLater(() => passwordField.forceActiveFocus());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
@@ -14,7 +12,7 @@ Rectangle {
|
||||
required property bool isLocked
|
||||
|
||||
signal passwordChanged(string newPassword)
|
||||
signal unlockRequested()
|
||||
signal unlockRequested
|
||||
|
||||
color: "transparent"
|
||||
|
||||
@@ -28,14 +26,14 @@ Rectangle {
|
||||
onUnlockRequested: root.unlockRequested()
|
||||
onPasswordBufferChanged: {
|
||||
if (root.sharedPasswordBuffer !== passwordBuffer) {
|
||||
root.passwordChanged(passwordBuffer)
|
||||
root.passwordChanged(passwordBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onIsLockedChanged: {
|
||||
if (!isLocked) {
|
||||
lockContent.unlocking = false
|
||||
lockContent.unlocking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -16,50 +14,70 @@ Item {
|
||||
property bool isLabwc: CompositorService.isLabwc
|
||||
|
||||
property string compositorName: {
|
||||
if (isHyprland) return "hyprland"
|
||||
if (isSway) return "sway"
|
||||
if (isDwl) return "mangowc"
|
||||
if (isLabwc) return "labwc"
|
||||
return "niri"
|
||||
if (isHyprland)
|
||||
return "hyprland";
|
||||
if (isSway)
|
||||
return "sway";
|
||||
if (isDwl)
|
||||
return "mangowc";
|
||||
if (isLabwc)
|
||||
return "labwc";
|
||||
return "niri";
|
||||
}
|
||||
|
||||
property string compositorLogo: {
|
||||
if (isHyprland) return "/assets/hyprland.svg"
|
||||
if (isSway) return "/assets/sway.svg"
|
||||
if (isDwl) return "/assets/mango.png"
|
||||
if (isLabwc) return "/assets/labwc.png"
|
||||
return "/assets/niri.svg"
|
||||
if (isHyprland)
|
||||
return "/assets/hyprland.svg";
|
||||
if (isSway)
|
||||
return "/assets/sway.svg";
|
||||
if (isDwl)
|
||||
return "/assets/mango.png";
|
||||
if (isLabwc)
|
||||
return "/assets/labwc.png";
|
||||
return "/assets/niri.svg";
|
||||
}
|
||||
|
||||
property string compositorUrl: {
|
||||
if (isHyprland) return "https://hypr.land"
|
||||
if (isSway) return "https://swaywm.org"
|
||||
if (isDwl) return "https://github.com/DreamMaoMao/mangowc"
|
||||
if (isLabwc) return "https://labwc.github.io/"
|
||||
return "https://github.com/YaLTeR/niri"
|
||||
if (isHyprland)
|
||||
return "https://hypr.land";
|
||||
if (isSway)
|
||||
return "https://swaywm.org";
|
||||
if (isDwl)
|
||||
return "https://github.com/DreamMaoMao/mangowc";
|
||||
if (isLabwc)
|
||||
return "https://labwc.github.io/";
|
||||
return "https://github.com/YaLTeR/niri";
|
||||
}
|
||||
|
||||
property string compositorTooltip: {
|
||||
if (isHyprland) return "Hyprland Website"
|
||||
if (isSway) return "Sway Website"
|
||||
if (isDwl) return "mangowc GitHub"
|
||||
if (isLabwc) return "LabWC Website"
|
||||
return "niri GitHub"
|
||||
if (isHyprland)
|
||||
return "Hyprland Website";
|
||||
if (isSway)
|
||||
return "Sway Website";
|
||||
if (isDwl)
|
||||
return "mangowc GitHub";
|
||||
if (isLabwc)
|
||||
return "LabWC Website";
|
||||
return "niri GitHub";
|
||||
}
|
||||
|
||||
property string dmsDiscordUrl: "https://discord.gg/ppWTpKmPgT"
|
||||
property string dmsDiscordTooltip: "niri/dms Discord"
|
||||
|
||||
property string compositorDiscordUrl: {
|
||||
if (isHyprland) return "https://discord.com/invite/hQ9XvMUjjr"
|
||||
if (isDwl) return "https://discord.gg/CPjbDxesh5"
|
||||
return ""
|
||||
if (isHyprland)
|
||||
return "https://discord.com/invite/hQ9XvMUjjr";
|
||||
if (isDwl)
|
||||
return "https://discord.gg/CPjbDxesh5";
|
||||
return "";
|
||||
}
|
||||
|
||||
property string compositorDiscordTooltip: {
|
||||
if (isHyprland) return "Hyprland Discord Server"
|
||||
if (isDwl) return "mangowc Discord Server"
|
||||
return ""
|
||||
if (isHyprland)
|
||||
return "Hyprland Discord Server";
|
||||
if (isDwl)
|
||||
return "mangowc Discord Server";
|
||||
return "";
|
||||
}
|
||||
|
||||
property string redditUrl: "https://reddit.com/r/niri"
|
||||
@@ -76,13 +94,14 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
// ASCII Art Header
|
||||
@@ -91,8 +110,7 @@ Item {
|
||||
height: asciiSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -157,20 +175,20 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: 24
|
||||
width: {
|
||||
let baseWidth = compositorButton.width + dmsDiscordButton.width + Theme.spacingM
|
||||
let baseWidth = compositorButton.width + dmsDiscordButton.width + Theme.spacingM;
|
||||
if (showMatrix) {
|
||||
baseWidth += matrixButton.width + 4
|
||||
baseWidth += matrixButton.width + 4;
|
||||
}
|
||||
if (showIrc) {
|
||||
baseWidth += ircButton.width + Theme.spacingM
|
||||
baseWidth += ircButton.width + Theme.spacingM;
|
||||
}
|
||||
if (showCompositorDiscord) {
|
||||
baseWidth += compositorDiscordButton.width + Theme.spacingM
|
||||
baseWidth += compositorDiscordButton.width + Theme.spacingM;
|
||||
}
|
||||
if (showReddit) {
|
||||
baseWidth += redditButton.width + Theme.spacingM
|
||||
baseWidth += redditButton.width + Theme.spacingM;
|
||||
}
|
||||
return baseWidth
|
||||
return baseWidth;
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -186,10 +204,7 @@ Item {
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + compositorLogo
|
||||
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + compositorLogo
|
||||
sourceSize: Qt.size(24, 24)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
@@ -217,10 +232,7 @@ Item {
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + "/assets/matrix-logo-white.svg"
|
||||
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/matrix-logo-white.svg"
|
||||
sourceSize: Qt.size(28, 18)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
@@ -238,8 +250,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
onEntered: parent.hovered = true
|
||||
onExited: parent.hovered = false
|
||||
onClicked: Qt.openUrlExternally(
|
||||
"https://matrix.to/#/#niri:matrix.org")
|
||||
onClicked: Qt.openUrlExternally("https://matrix.to/#/#niri:matrix.org")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,9 +287,11 @@ Item {
|
||||
width: 20
|
||||
height: 20
|
||||
x: {
|
||||
if (showMatrix) return matrixButton.x + matrixButton.width + Theme.spacingM
|
||||
if (showIrc) return ircButton.x + ircButton.width + Theme.spacingM
|
||||
return compositorButton.x + compositorButton.width + Theme.spacingM
|
||||
if (showMatrix)
|
||||
return matrixButton.x + matrixButton.width + Theme.spacingM;
|
||||
if (showIrc)
|
||||
return ircButton.x + ircButton.width + Theme.spacingM;
|
||||
return compositorButton.x + compositorButton.width + Theme.spacingM;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -287,10 +300,7 @@ Item {
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + "/assets/discord.svg"
|
||||
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/discord.svg"
|
||||
sourceSize: Qt.size(20, 20)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
@@ -319,10 +329,7 @@ Item {
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + "/assets/discord.svg"
|
||||
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/discord.svg"
|
||||
sourceSize: Qt.size(20, 20)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
@@ -351,10 +358,7 @@ Item {
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: Qt.resolvedUrl(".").toString().replace(
|
||||
"file://", "").replace(
|
||||
"/Modules/Settings/",
|
||||
"") + "/assets/reddit.svg"
|
||||
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modules/Settings/", "") + "/assets/reddit.svg"
|
||||
sourceSize: Qt.size(20, 20)
|
||||
smooth: true
|
||||
fillMode: Image.PreserveAspectFit
|
||||
@@ -373,15 +377,13 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Project Information
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: projectSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -438,8 +440,7 @@ Item {
|
||||
height: techSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -600,8 +601,7 @@ Item {
|
||||
height: supportSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
@@ -648,7 +648,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,13 +658,19 @@ Item {
|
||||
z: 1000
|
||||
|
||||
property var hoveredButton: {
|
||||
if (compositorButton.hovered) return compositorButton
|
||||
if (matrixButton.visible && matrixButton.hovered) return matrixButton
|
||||
if (ircButton.visible && ircButton.hovered) return ircButton
|
||||
if (dmsDiscordButton.hovered) return dmsDiscordButton
|
||||
if (compositorDiscordButton.visible && compositorDiscordButton.hovered) return compositorDiscordButton
|
||||
if (redditButton.visible && redditButton.hovered) return redditButton
|
||||
return null
|
||||
if (compositorButton.hovered)
|
||||
return compositorButton;
|
||||
if (matrixButton.visible && matrixButton.hovered)
|
||||
return matrixButton;
|
||||
if (ircButton.visible && ircButton.hovered)
|
||||
return ircButton;
|
||||
if (dmsDiscordButton.hovered)
|
||||
return dmsDiscordButton;
|
||||
if (compositorDiscordButton.visible && compositorDiscordButton.hovered)
|
||||
return compositorDiscordButton;
|
||||
if (redditButton.visible && redditButton.hovered)
|
||||
return redditButton;
|
||||
return null;
|
||||
}
|
||||
|
||||
property string tooltipText: hoveredButton ? hoveredButton.tooltipText : ""
|
||||
|
||||
@@ -1075,12 +1075,13 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
@@ -10,81 +9,88 @@ Item {
|
||||
id: displaysTab
|
||||
|
||||
function getBarComponentsFromSettings() {
|
||||
const bars = SettingsData.barConfigs || []
|
||||
const bars = SettingsData.barConfigs || [];
|
||||
return bars.map(bar => ({
|
||||
"id": "bar:" + bar.id,
|
||||
"name": bar.name || "Bar",
|
||||
"description": I18n.tr("Individual bar configuration"),
|
||||
"icon": "toolbar",
|
||||
"barId": bar.id
|
||||
}))
|
||||
"id": "bar:" + bar.id,
|
||||
"name": bar.name || "Bar",
|
||||
"description": I18n.tr("Individual bar configuration"),
|
||||
"icon": "toolbar",
|
||||
"barId": bar.id
|
||||
}));
|
||||
}
|
||||
|
||||
property var variantComponents: getVariantComponentsList()
|
||||
|
||||
function getVariantComponentsList() {
|
||||
return [
|
||||
...getBarComponentsFromSettings(),
|
||||
return [...getBarComponentsFromSettings(),
|
||||
{
|
||||
"id": "dock",
|
||||
"name": I18n.tr("Application Dock"),
|
||||
"description": I18n.tr("Bottom dock for pinned and running applications"),
|
||||
"icon": "dock"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"id": "notifications",
|
||||
"name": I18n.tr("Notification Popups"),
|
||||
"description": I18n.tr("Notification toast popups"),
|
||||
"icon": "notifications"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"id": "wallpaper",
|
||||
"name": I18n.tr("Wallpaper"),
|
||||
"description": I18n.tr("Desktop background images"),
|
||||
"icon": "wallpaper"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"id": "osd",
|
||||
"name": I18n.tr("On-Screen Displays"),
|
||||
"description": I18n.tr("Volume, brightness, and other system OSDs"),
|
||||
"icon": "picture_in_picture"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"id": "toast",
|
||||
"name": I18n.tr("Toast Messages"),
|
||||
"description": I18n.tr("System toast notifications"),
|
||||
"icon": "campaign"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"id": "notepad",
|
||||
"name": I18n.tr("Notepad Slideout"),
|
||||
"description": I18n.tr("Quick note-taking slideout panel"),
|
||||
"icon": "sticky_note_2"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"id": "systemTray",
|
||||
"name": I18n.tr("System Tray"),
|
||||
"description": I18n.tr("System tray icons"),
|
||||
"icon": "notifications"
|
||||
}
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onBarConfigsChanged() {
|
||||
variantComponents = getVariantComponentsList()
|
||||
variantComponents = getVariantComponentsList();
|
||||
}
|
||||
}
|
||||
|
||||
function getScreenPreferences(componentId) {
|
||||
if (componentId.startsWith("bar:")) {
|
||||
const barId = componentId.substring(4)
|
||||
const barConfig = SettingsData.getBarConfig(barId)
|
||||
return barConfig?.screenPreferences || ["all"]
|
||||
const barId = componentId.substring(4);
|
||||
const barConfig = SettingsData.getBarConfig(barId);
|
||||
return barConfig?.screenPreferences || ["all"];
|
||||
}
|
||||
return SettingsData.screenPreferences && SettingsData.screenPreferences[componentId] || ["all"];
|
||||
}
|
||||
|
||||
function setScreenPreferences(componentId, screenNames) {
|
||||
if (componentId.startsWith("bar:")) {
|
||||
const barId = componentId.substring(4)
|
||||
SettingsData.updateBarConfig(barId, { screenPreferences: screenNames })
|
||||
return
|
||||
const barId = componentId.substring(4);
|
||||
SettingsData.updateBarConfig(barId, {
|
||||
screenPreferences: screenNames
|
||||
});
|
||||
return;
|
||||
}
|
||||
var prefs = SettingsData.screenPreferences || {};
|
||||
var newPrefs = Object.assign({}, prefs);
|
||||
@@ -94,18 +100,20 @@ Item {
|
||||
|
||||
function getShowOnLastDisplay(componentId) {
|
||||
if (componentId.startsWith("bar:")) {
|
||||
const barId = componentId.substring(4)
|
||||
const barConfig = SettingsData.getBarConfig(barId)
|
||||
return barConfig?.showOnLastDisplay ?? true
|
||||
const barId = componentId.substring(4);
|
||||
const barConfig = SettingsData.getBarConfig(barId);
|
||||
return barConfig?.showOnLastDisplay ?? true;
|
||||
}
|
||||
return SettingsData.showOnLastDisplay && SettingsData.showOnLastDisplay[componentId] || false;
|
||||
}
|
||||
|
||||
function setShowOnLastDisplay(componentId, enabled) {
|
||||
if (componentId.startsWith("bar:")) {
|
||||
const barId = componentId.substring(4)
|
||||
SettingsData.updateBarConfig(barId, { showOnLastDisplay: enabled })
|
||||
return
|
||||
const barId = componentId.substring(4);
|
||||
SettingsData.updateBarConfig(barId, {
|
||||
showOnLastDisplay: enabled
|
||||
});
|
||||
return;
|
||||
}
|
||||
var prefs = SettingsData.showOnLastDisplay || {};
|
||||
var newPrefs = Object.assign({}, prefs);
|
||||
@@ -116,13 +124,14 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
@@ -169,12 +178,12 @@ Item {
|
||||
checked: DisplayService.nightModeEnabled
|
||||
enabled: DisplayService.gammaControlAvailable
|
||||
onToggled: checked => {
|
||||
DisplayService.toggleNightMode()
|
||||
}
|
||||
DisplayService.toggleNightMode();
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onNightModeEnabledChanged() {
|
||||
nightModeToggle.checked = DisplayService.nightModeEnabled
|
||||
nightModeToggle.checked = DisplayService.nightModeEnabled;
|
||||
}
|
||||
|
||||
target: DisplayService
|
||||
@@ -194,19 +203,19 @@ Item {
|
||||
description: I18n.tr("Color temperature for night mode")
|
||||
currentValue: SessionData.nightModeTemperature + "K"
|
||||
options: {
|
||||
var temps = []
|
||||
var temps = [];
|
||||
for (var i = 2500; i <= 6000; i += 500) {
|
||||
temps.push(i + "K")
|
||||
temps.push(i + "K");
|
||||
}
|
||||
return temps
|
||||
return temps;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var temp = parseInt(value.replace("K", ""))
|
||||
SessionData.setNightModeTemperature(temp)
|
||||
if (SessionData.nightModeHighTemperature < temp) {
|
||||
SessionData.setNightModeHighTemperature(temp)
|
||||
}
|
||||
}
|
||||
var temp = parseInt(value.replace("K", ""));
|
||||
SessionData.setNightModeTemperature(temp);
|
||||
if (SessionData.nightModeHighTemperature < temp) {
|
||||
SessionData.setNightModeHighTemperature(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
@@ -215,19 +224,19 @@ Item {
|
||||
description: I18n.tr("Color temperature for day time")
|
||||
currentValue: SessionData.nightModeHighTemperature + "K"
|
||||
options: {
|
||||
var temps = []
|
||||
var minTemp = SessionData.nightModeTemperature
|
||||
var temps = [];
|
||||
var minTemp = SessionData.nightModeTemperature;
|
||||
for (var i = Math.max(2500, minTemp); i <= 10000; i += 500) {
|
||||
temps.push(i + "K")
|
||||
temps.push(i + "K");
|
||||
}
|
||||
return temps
|
||||
return temps;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var temp = parseInt(value.replace("K", ""))
|
||||
if (temp >= SessionData.nightModeTemperature) {
|
||||
SessionData.setNightModeHighTemperature(temp)
|
||||
}
|
||||
}
|
||||
var temp = parseInt(value.replace("K", ""));
|
||||
if (temp >= SessionData.nightModeTemperature) {
|
||||
SessionData.setNightModeHighTemperature(temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,18 +248,18 @@ Item {
|
||||
checked: SessionData.nightModeAutoEnabled
|
||||
visible: DisplayService.gammaControlAvailable
|
||||
onToggled: checked => {
|
||||
if (checked && !DisplayService.nightModeEnabled) {
|
||||
DisplayService.toggleNightMode()
|
||||
} else if (!checked && DisplayService.nightModeEnabled) {
|
||||
DisplayService.toggleNightMode()
|
||||
}
|
||||
SessionData.setNightModeAutoEnabled(checked)
|
||||
}
|
||||
if (checked && !DisplayService.nightModeEnabled) {
|
||||
DisplayService.toggleNightMode();
|
||||
} else if (!checked && DisplayService.nightModeEnabled) {
|
||||
DisplayService.toggleNightMode();
|
||||
}
|
||||
SessionData.setNightModeAutoEnabled(checked);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoEnabledChanged() {
|
||||
automaticToggle.checked = SessionData.nightModeAutoEnabled
|
||||
automaticToggle.checked = SessionData.nightModeAutoEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,7 +273,7 @@ Item {
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoEnabledChanged() {
|
||||
automaticSettings.visible = SessionData.nightModeAutoEnabled
|
||||
automaticSettings.visible = SessionData.nightModeAutoEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,29 +286,32 @@ Item {
|
||||
width: 200
|
||||
height: 45
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
model: [{
|
||||
model: [
|
||||
{
|
||||
"text": "Time",
|
||||
"icon": "access_time"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"text": "Location",
|
||||
"icon": "place"
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
Component.onCompleted: {
|
||||
currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0
|
||||
Qt.callLater(updateIndicator)
|
||||
currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0;
|
||||
Qt.callLater(updateIndicator);
|
||||
}
|
||||
|
||||
onTabClicked: index => {
|
||||
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time")
|
||||
currentIndex = index
|
||||
}
|
||||
DisplayService.setNightModeAutomationMode(index === 1 ? "location" : "time");
|
||||
currentIndex = index;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeAutoModeChanged() {
|
||||
modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0
|
||||
Qt.callLater(modeTabBarNight.updateIndicator)
|
||||
modeTabBarNight.currentIndex = SessionData.nightModeAutoMode === "location" ? 1 : 0;
|
||||
Qt.callLater(modeTabBarNight.updateIndicator);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,30 +368,30 @@ Item {
|
||||
dropdownWidth: 70
|
||||
currentValue: SessionData.nightModeStartHour.toString()
|
||||
options: {
|
||||
var hours = []
|
||||
var hours = [];
|
||||
for (var i = 0; i < 24; i++) {
|
||||
hours.push(i.toString())
|
||||
hours.push(i.toString());
|
||||
}
|
||||
return hours
|
||||
return hours;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeStartHour(parseInt(value))
|
||||
}
|
||||
SessionData.setNightModeStartHour(parseInt(value));
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
dropdownWidth: 70
|
||||
currentValue: SessionData.nightModeStartMinute.toString().padStart(2, '0')
|
||||
options: {
|
||||
var minutes = []
|
||||
var minutes = [];
|
||||
for (var i = 0; i < 60; i += 5) {
|
||||
minutes.push(i.toString().padStart(2, '0'))
|
||||
minutes.push(i.toString().padStart(2, '0'));
|
||||
}
|
||||
return minutes
|
||||
return minutes;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeStartMinute(parseInt(value))
|
||||
}
|
||||
SessionData.setNightModeStartMinute(parseInt(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,30 +411,30 @@ Item {
|
||||
dropdownWidth: 70
|
||||
currentValue: SessionData.nightModeEndHour.toString()
|
||||
options: {
|
||||
var hours = []
|
||||
var hours = [];
|
||||
for (var i = 0; i < 24; i++) {
|
||||
hours.push(i.toString())
|
||||
hours.push(i.toString());
|
||||
}
|
||||
return hours
|
||||
return hours;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeEndHour(parseInt(value))
|
||||
}
|
||||
SessionData.setNightModeEndHour(parseInt(value));
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
dropdownWidth: 70
|
||||
currentValue: SessionData.nightModeEndMinute.toString().padStart(2, '0')
|
||||
options: {
|
||||
var minutes = []
|
||||
var minutes = [];
|
||||
for (var i = 0; i < 60; i += 5) {
|
||||
minutes.push(i.toString().padStart(2, '0'))
|
||||
minutes.push(i.toString().padStart(2, '0'));
|
||||
}
|
||||
return minutes
|
||||
return minutes;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
SessionData.setNightModeEndMinute(parseInt(value))
|
||||
}
|
||||
SessionData.setNightModeEndMinute(parseInt(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,13 +453,13 @@ Item {
|
||||
description: I18n.tr("Automatically detect location based on IP address")
|
||||
checked: SessionData.nightModeUseIPLocation || false
|
||||
onToggled: checked => {
|
||||
SessionData.setNightModeUseIPLocation(checked)
|
||||
SessionData.setNightModeUseIPLocation(checked);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onNightModeUseIPLocationChanged() {
|
||||
ipLocationToggle.checked = SessionData.nightModeUseIPLocation
|
||||
ipLocationToggle.checked = SessionData.nightModeUseIPLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,9 +494,9 @@ Item {
|
||||
text: SessionData.latitude.toString()
|
||||
placeholderText: "0.0"
|
||||
onEditingFinished: {
|
||||
const lat = parseFloat(text)
|
||||
const lat = parseFloat(text);
|
||||
if (!isNaN(lat) && lat >= -90 && lat <= 90 && lat !== SessionData.latitude) {
|
||||
SessionData.setLatitude(lat)
|
||||
SessionData.setLatitude(lat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -505,9 +517,9 @@ Item {
|
||||
text: SessionData.longitude.toString()
|
||||
placeholderText: "0.0"
|
||||
onEditingFinished: {
|
||||
const lon = parseFloat(text)
|
||||
const lon = parseFloat(text);
|
||||
if (!isNaN(lon) && lon >= -180 && lon <= 180 && lon !== SessionData.longitude) {
|
||||
SessionData.setLongitude(lon)
|
||||
SessionData.setLongitude(lon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,9 +584,7 @@ Item {
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -618,15 +628,16 @@ Item {
|
||||
model: [I18n.tr("Name"), I18n.tr("Model")]
|
||||
currentIndex: SettingsData.displayNameMode === "model" ? 1 : 0
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected) return
|
||||
SettingsData.displayNameMode = index === 1 ? "model" : "system"
|
||||
SettingsData.saveSettings()
|
||||
if (!selected)
|
||||
return;
|
||||
SettingsData.displayNameMode = index === 1 ? "model" : "system";
|
||||
SettingsData.saveSettings();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onDisplayNameModeChanged() {
|
||||
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0
|
||||
displayModeGroup.currentIndex = SettingsData.displayNameMode === "model" ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -691,21 +702,13 @@ Item {
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -760,9 +763,7 @@ Item {
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -787,17 +788,17 @@ Item {
|
||||
text: I18n.tr("All displays")
|
||||
description: I18n.tr("Show on all connected displays")
|
||||
checked: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId);
|
||||
return prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
||||
}
|
||||
onToggled: (checked) => {
|
||||
onToggled: checked => {
|
||||
if (checked) {
|
||||
displaysTab.setScreenPreferences(parent.componentId, ["all"])
|
||||
displaysTab.setScreenPreferences(parent.componentId, ["all"]);
|
||||
} else {
|
||||
displaysTab.setScreenPreferences(parent.componentId, [])
|
||||
const cid = parent.componentId
|
||||
displaysTab.setScreenPreferences(parent.componentId, []);
|
||||
const cid = parent.componentId;
|
||||
if (["dankBar", "dock", "notifications", "osd", "toast"].includes(cid) || cid.startsWith("bar:")) {
|
||||
displaysTab.setShowOnLastDisplay(cid, true)
|
||||
displaysTab.setShowOnLastDisplay(cid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -809,14 +810,14 @@ Item {
|
||||
description: I18n.tr("Always show when there's only one connected display")
|
||||
checked: displaysTab.getShowOnLastDisplay(parent.componentId)
|
||||
visible: {
|
||||
const prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
const cid = parent.componentId
|
||||
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(cid) || cid.startsWith("bar:")
|
||||
return !isAll && isRelevantComponent
|
||||
const prefs = displaysTab.getScreenPreferences(parent.componentId);
|
||||
const isAll = prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all");
|
||||
const cid = parent.componentId;
|
||||
const isRelevantComponent = ["dankBar", "dock", "notifications", "osd", "toast", "notepad", "systemTray"].includes(cid) || cid.startsWith("bar:");
|
||||
return !isAll && isRelevantComponent;
|
||||
}
|
||||
onToggled: (checked) => {
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, checked)
|
||||
onToggled: checked => {
|
||||
displaysTab.setShowOnLastDisplay(parent.componentId, checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -826,8 +827,8 @@ Item {
|
||||
color: Theme.outline
|
||||
opacity: 0.2
|
||||
visible: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId);
|
||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -835,8 +836,8 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
visible: {
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId)
|
||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
var prefs = displaysTab.getScreenPreferences(parent.componentId);
|
||||
return !prefs.includes("all") && !(typeof prefs[0] === "string" && prefs[0] === "all");
|
||||
}
|
||||
|
||||
Repeater {
|
||||
@@ -850,50 +851,41 @@ Item {
|
||||
text: SettingsData.getScreenDisplayName(screenData)
|
||||
description: screenData.width + "×" + screenData.height + " • " + (SettingsData.displayNameMode === "system" ? (screenData.model || "Unknown Model") : screenData.name)
|
||||
checked: {
|
||||
var prefs = displaysTab.getScreenPreferences(componentId)
|
||||
if (typeof prefs[0] === "string" && prefs[0] === "all") return false
|
||||
return SettingsData.isScreenInPreferences(screenData, prefs)
|
||||
var prefs = displaysTab.getScreenPreferences(componentId);
|
||||
if (typeof prefs[0] === "string" && prefs[0] === "all")
|
||||
return false;
|
||||
return SettingsData.isScreenInPreferences(screenData, prefs);
|
||||
}
|
||||
onToggled: (checked) => {
|
||||
var currentPrefs = displaysTab.getScreenPreferences(componentId)
|
||||
onToggled: checked => {
|
||||
var currentPrefs = displaysTab.getScreenPreferences(componentId);
|
||||
if (typeof currentPrefs[0] === "string" && currentPrefs[0] === "all") {
|
||||
currentPrefs = []
|
||||
currentPrefs = [];
|
||||
}
|
||||
|
||||
var newPrefs = currentPrefs.filter(pref => {
|
||||
if (typeof pref === "string") return false
|
||||
return pref.name !== screenData.name || pref.model !== screenData.model
|
||||
})
|
||||
if (typeof pref === "string")
|
||||
return false;
|
||||
return pref.name !== screenData.name || pref.model !== screenData.model;
|
||||
});
|
||||
|
||||
if (checked) {
|
||||
newPrefs.push({
|
||||
name: screenData.name,
|
||||
model: screenData.model || ""
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
displaysTab.setScreenPreferences(componentId, newPrefs)
|
||||
displaysTab.setScreenPreferences(componentId, newPrefs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -11,12 +9,13 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
// Dock Position
|
||||
@@ -25,8 +24,7 @@ Item {
|
||||
height: dockPositionSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -67,20 +65,33 @@ Item {
|
||||
model: ["Top", "Bottom", "Left", "Right"]
|
||||
currentIndex: {
|
||||
switch (SettingsData.dockPosition) {
|
||||
case SettingsData.Position.Top: return 0
|
||||
case SettingsData.Position.Bottom: return 1
|
||||
case SettingsData.Position.Left: return 2
|
||||
case SettingsData.Position.Right: return 3
|
||||
default: return 1
|
||||
case SettingsData.Position.Top:
|
||||
return 0;
|
||||
case SettingsData.Position.Bottom:
|
||||
return 1;
|
||||
case SettingsData.Position.Left:
|
||||
return 2;
|
||||
case SettingsData.Position.Right:
|
||||
return 3;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (selected) {
|
||||
switch (index) {
|
||||
case 0: SettingsData.setDockPosition(SettingsData.Position.Top); break
|
||||
case 1: SettingsData.setDockPosition(SettingsData.Position.Bottom); break
|
||||
case 2: SettingsData.setDockPosition(SettingsData.Position.Left); break
|
||||
case 3: SettingsData.setDockPosition(SettingsData.Position.Right); break
|
||||
case 0:
|
||||
SettingsData.setDockPosition(SettingsData.Position.Top);
|
||||
break;
|
||||
case 1:
|
||||
SettingsData.setDockPosition(SettingsData.Position.Bottom);
|
||||
break;
|
||||
case 2:
|
||||
SettingsData.setDockPosition(SettingsData.Position.Left);
|
||||
break;
|
||||
case 3:
|
||||
SettingsData.setDockPosition(SettingsData.Position.Right);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,8 +106,7 @@ Item {
|
||||
height: dockVisibilitySection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -118,8 +128,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- enableToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - enableToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -145,8 +154,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.showDock
|
||||
onToggled: checked => {
|
||||
SettingsData.setShowDock(checked)
|
||||
}
|
||||
SettingsData.setShowDock(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +181,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- autoHideToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - autoHideToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -199,8 +207,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.dockAutoHide
|
||||
onToggled: checked => {
|
||||
SettingsData.set("dockAutoHide", checked)
|
||||
}
|
||||
SettingsData.set("dockAutoHide", checked);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -232,8 +240,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- overviewToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - overviewToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -259,8 +266,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.dockOpenOnOverview
|
||||
onToggled: checked => {
|
||||
SettingsData.set("dockOpenOnOverview", checked)
|
||||
}
|
||||
SettingsData.set("dockOpenOnOverview", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -272,8 +279,7 @@ Item {
|
||||
height: groupByAppSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -295,8 +301,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- groupByAppToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - groupByAppToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -322,8 +327,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.dockGroupByApp
|
||||
onToggled: checked => {
|
||||
SettingsData.set("dockGroupByApp", checked)
|
||||
}
|
||||
SettingsData.set("dockGroupByApp", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,8 +340,7 @@ Item {
|
||||
height: indicatorStyleSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -378,7 +382,7 @@ Item {
|
||||
currentIndex: SettingsData.dockIndicatorStyle === "circle" ? 0 : 1
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (selected) {
|
||||
SettingsData.set("dockIndicatorStyle", index === 0 ? "circle" : "line")
|
||||
SettingsData.set("dockIndicatorStyle", index === 0 ? "circle" : "line");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -392,8 +396,7 @@ Item {
|
||||
height: iconSizeSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -437,7 +440,7 @@ Item {
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.set("dockIconSize", 48)
|
||||
SettingsData.set("dockIconSize", 48);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -453,8 +456,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("dockIconSize", newValue)
|
||||
}
|
||||
SettingsData.set("dockIconSize", newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,8 +468,7 @@ Item {
|
||||
height: dockSpacingSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -533,7 +535,7 @@ Item {
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.set("dockSpacing", 8)
|
||||
SettingsData.set("dockSpacing", 8);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -554,9 +556,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("dockSpacing",
|
||||
newValue)
|
||||
}
|
||||
SettingsData.set("dockSpacing", newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -597,7 +598,7 @@ Item {
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.set("dockBottomGap", 0)
|
||||
SettingsData.set("dockBottomGap", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,9 +619,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("dockBottomGap",
|
||||
newValue)
|
||||
}
|
||||
SettingsData.set("dockBottomGap", newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,7 +661,7 @@ Item {
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.set("dockMargin", 0)
|
||||
SettingsData.set("dockMargin", 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -682,8 +682,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("dockMargin", newValue)
|
||||
}
|
||||
SettingsData.set("dockMargin", newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -695,8 +695,7 @@ Item {
|
||||
height: transparencySection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -740,7 +739,7 @@ Item {
|
||||
iconColor: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
SettingsData.set("dockTransparency", 0.85)
|
||||
SettingsData.set("dockTransparency", 0.85);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -756,9 +755,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("dockTransparency",
|
||||
newValue / 100)
|
||||
}
|
||||
SettingsData.set("dockTransparency", newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modals
|
||||
import qs.Modals.FileBrowser
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -18,19 +14,20 @@ Item {
|
||||
browserType: "generic"
|
||||
filterExtensions: ["*.svg", "*.png", "*.jpg", "*.jpeg", "*.webp"]
|
||||
onFileSelected: path => {
|
||||
SettingsData.set("launcherLogoCustomPath", path.replace("file://", ""))
|
||||
SettingsData.set("launcherLogoCustomPath", path.replace("file://", ""));
|
||||
}
|
||||
}
|
||||
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
@@ -38,8 +35,7 @@ Item {
|
||||
height: launcherLogoSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -85,41 +81,47 @@ Item {
|
||||
id: logoModeGroup
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
model: {
|
||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")]
|
||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")];
|
||||
if (CompositorService.isNiri) {
|
||||
modes.push("niri")
|
||||
modes.push("niri");
|
||||
} else if (CompositorService.isHyprland) {
|
||||
modes.push("Hyprland")
|
||||
modes.push("Hyprland");
|
||||
} else if (CompositorService.isDwl) {
|
||||
modes.push("mango")
|
||||
modes.push("mango");
|
||||
} else if (CompositorService.isSway) {
|
||||
modes.push("Sway")
|
||||
modes.push("Sway");
|
||||
} else {
|
||||
modes.push(I18n.tr("Compositor"))
|
||||
modes.push(I18n.tr("Compositor"));
|
||||
}
|
||||
modes.push(I18n.tr("Custom"))
|
||||
return modes
|
||||
modes.push(I18n.tr("Custom"));
|
||||
return modes;
|
||||
}
|
||||
currentIndex: {
|
||||
if (SettingsData.launcherLogoMode === "apps") return 0
|
||||
if (SettingsData.launcherLogoMode === "os") return 1
|
||||
if (SettingsData.launcherLogoMode === "dank") return 2
|
||||
if (SettingsData.launcherLogoMode === "compositor") return 3
|
||||
if (SettingsData.launcherLogoMode === "custom") return 4
|
||||
return 0
|
||||
if (SettingsData.launcherLogoMode === "apps")
|
||||
return 0;
|
||||
if (SettingsData.launcherLogoMode === "os")
|
||||
return 1;
|
||||
if (SettingsData.launcherLogoMode === "dank")
|
||||
return 2;
|
||||
if (SettingsData.launcherLogoMode === "compositor")
|
||||
return 3;
|
||||
if (SettingsData.launcherLogoMode === "custom")
|
||||
return 4;
|
||||
return 0;
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected) return
|
||||
if (!selected)
|
||||
return;
|
||||
if (index === 0) {
|
||||
SettingsData.set("launcherLogoMode", "apps")
|
||||
SettingsData.set("launcherLogoMode", "apps");
|
||||
} else if (index === 1) {
|
||||
SettingsData.set("launcherLogoMode", "os")
|
||||
SettingsData.set("launcherLogoMode", "os");
|
||||
} else if (index === 2) {
|
||||
SettingsData.set("launcherLogoMode", "dank")
|
||||
SettingsData.set("launcherLogoMode", "dank");
|
||||
} else if (index === 3) {
|
||||
SettingsData.set("launcherLogoMode", "compositor")
|
||||
SettingsData.set("launcherLogoMode", "compositor");
|
||||
} else if (index === 4) {
|
||||
SettingsData.set("launcherLogoMode", "custom")
|
||||
SettingsData.set("launcherLogoMode", "custom");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,25 +202,29 @@ Item {
|
||||
id: colorModeGroup
|
||||
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
||||
currentIndex: {
|
||||
const override = SettingsData.launcherLogoColorOverride
|
||||
if (override === "") return 0
|
||||
if (override === "primary") return 1
|
||||
if (override === "surface") return 2
|
||||
return 3
|
||||
const override = SettingsData.launcherLogoColorOverride;
|
||||
if (override === "")
|
||||
return 0;
|
||||
if (override === "primary")
|
||||
return 1;
|
||||
if (override === "surface")
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected) return
|
||||
if (!selected)
|
||||
return;
|
||||
if (index === 0) {
|
||||
SettingsData.set("launcherLogoColorOverride", "")
|
||||
SettingsData.set("launcherLogoColorOverride", "");
|
||||
} else if (index === 1) {
|
||||
SettingsData.set("launcherLogoColorOverride", "primary")
|
||||
SettingsData.set("launcherLogoColorOverride", "primary");
|
||||
} else if (index === 2) {
|
||||
SettingsData.set("launcherLogoColorOverride", "surface")
|
||||
SettingsData.set("launcherLogoColorOverride", "surface");
|
||||
} else if (index === 3) {
|
||||
const currentOverride = SettingsData.launcherLogoColorOverride
|
||||
const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface"
|
||||
const currentOverride = SettingsData.launcherLogoColorOverride;
|
||||
const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface";
|
||||
if (isPreset) {
|
||||
SettingsData.set("launcherLogoColorOverride", "#ffffff")
|
||||
SettingsData.set("launcherLogoColorOverride", "#ffffff");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,18 +232,18 @@ Item {
|
||||
|
||||
Rectangle {
|
||||
visible: {
|
||||
const override = SettingsData.launcherLogoColorOverride
|
||||
return override !== "" && override !== "primary" && override !== "surface"
|
||||
const override = SettingsData.launcherLogoColorOverride;
|
||||
return override !== "" && override !== "primary" && override !== "surface";
|
||||
}
|
||||
width: 36
|
||||
height: 36
|
||||
radius: 18
|
||||
color: {
|
||||
const override = SettingsData.launcherLogoColorOverride
|
||||
const override = SettingsData.launcherLogoColorOverride;
|
||||
if (override !== "" && override !== "primary" && override !== "surface") {
|
||||
return override
|
||||
return override;
|
||||
}
|
||||
return "#ffffff"
|
||||
return "#ffffff";
|
||||
}
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
@@ -248,12 +254,12 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (PopoutService.colorPickerModal) {
|
||||
PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride
|
||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color")
|
||||
PopoutService.colorPickerModal.onColorSelectedCallback = function(selectedColor) {
|
||||
SettingsData.set("launcherLogoColorOverride", selectedColor)
|
||||
}
|
||||
PopoutService.colorPickerModal.show()
|
||||
PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride;
|
||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color");
|
||||
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
||||
SettingsData.set("launcherLogoColorOverride", selectedColor);
|
||||
};
|
||||
PopoutService.colorPickerModal.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,7 +296,7 @@ Item {
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("launcherLogoSizeOffset", newValue)
|
||||
SettingsData.set("launcherLogoSizeOffset", newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -300,8 +306,8 @@ Item {
|
||||
width: parent.width
|
||||
height: customControlsFlow.height
|
||||
visible: {
|
||||
const override = SettingsData.launcherLogoColorOverride
|
||||
return override !== "" && override !== "primary" && override !== "surface"
|
||||
const override = SettingsData.launcherLogoColorOverride;
|
||||
return override !== "" && override !== "primary" && override !== "surface";
|
||||
}
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
@@ -341,7 +347,7 @@ Item {
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("launcherLogoBrightness", newValue / 100)
|
||||
SettingsData.set("launcherLogoBrightness", newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -370,7 +376,7 @@ Item {
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("launcherLogoContrast", newValue / 100)
|
||||
SettingsData.set("launcherLogoContrast", newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -393,7 +399,7 @@ Item {
|
||||
checked: SettingsData.launcherLogoColorInvertOnMode
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onToggled: checked => {
|
||||
SettingsData.set("launcherLogoColorInvertOnMode", checked)
|
||||
SettingsData.set("launcherLogoColorInvertOnMode", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,8 +414,7 @@ Item {
|
||||
height: launchPrefixSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -452,7 +457,7 @@ Item {
|
||||
text: SettingsData.launchPrefix
|
||||
placeholderText: I18n.tr("Enter launch prefix (e.g., 'uwsm-app')")
|
||||
onTextEdited: {
|
||||
SettingsData.set("launchPrefix", text)
|
||||
SettingsData.set("launchPrefix", text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,8 +468,7 @@ Item {
|
||||
height: sortingSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -494,9 +498,7 @@ Item {
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.children[0].width
|
||||
- parent.children[1].width
|
||||
- sortToggle.width - Theme.spacingM * 3
|
||||
width: parent.width - parent.children[0].width - parent.children[1].width - sortToggle.width - Theme.spacingM * 3
|
||||
height: 1
|
||||
}
|
||||
|
||||
@@ -508,7 +510,7 @@ Item {
|
||||
checked: SettingsData.sortAppsAlphabetically
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onToggled: checked => {
|
||||
SettingsData.set("sortAppsAlphabetically", checked)
|
||||
SettingsData.set("sortAppsAlphabetically", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -528,8 +530,7 @@ Item {
|
||||
height: gridColumnsSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -584,7 +585,7 @@ Item {
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.set("appLauncherGridColumns", newValue)
|
||||
SettingsData.set("appLauncherGridColumns", newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,8 +597,7 @@ Item {
|
||||
height: niriOverviewSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: CompositorService.isNiri
|
||||
|
||||
@@ -628,9 +628,7 @@ Item {
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.children[0].width
|
||||
- parent.children[1].width
|
||||
- niriOverviewToggle.width - Theme.spacingM * 3
|
||||
width: parent.width - parent.children[0].width - parent.children[1].width - niriOverviewToggle.width - Theme.spacingM * 3
|
||||
height: 1
|
||||
}
|
||||
|
||||
@@ -642,7 +640,7 @@ Item {
|
||||
checked: SettingsData.spotlightCloseNiriOverview
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onToggled: checked => {
|
||||
SettingsData.set("spotlightCloseNiriOverview", checked)
|
||||
SettingsData.set("spotlightCloseNiriOverview", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -662,36 +660,33 @@ Item {
|
||||
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
id: recentlyUsedSection
|
||||
|
||||
property var rankedAppsModel: {
|
||||
var apps = []
|
||||
for (var appId in (AppUsageHistoryData.appUsageRanking
|
||||
|| {})) {
|
||||
var appData = (AppUsageHistoryData.appUsageRanking
|
||||
|| {})[appId]
|
||||
var apps = [];
|
||||
for (var appId in (AppUsageHistoryData.appUsageRanking || {})) {
|
||||
var appData = (AppUsageHistoryData.appUsageRanking || {})[appId];
|
||||
apps.push({
|
||||
"id": appId,
|
||||
"name": appData.name,
|
||||
"exec": appData.exec,
|
||||
"icon": appData.icon,
|
||||
"comment": appData.comment,
|
||||
"usageCount": appData.usageCount,
|
||||
"lastUsed": appData.lastUsed
|
||||
})
|
||||
"id": appId,
|
||||
"name": appData.name,
|
||||
"exec": appData.exec,
|
||||
"icon": appData.icon,
|
||||
"comment": appData.comment,
|
||||
"usageCount": appData.usageCount,
|
||||
"lastUsed": appData.lastUsed
|
||||
});
|
||||
}
|
||||
apps.sort(function (a, b) {
|
||||
if (a.usageCount !== b.usageCount)
|
||||
return b.usageCount - a.usageCount
|
||||
return b.usageCount - a.usageCount;
|
||||
|
||||
return a.name.localeCompare(b.name)
|
||||
})
|
||||
return apps.slice(0, 20)
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
return apps.slice(0, 20);
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
@@ -718,9 +713,7 @@ Item {
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.children[0].width
|
||||
- parent.children[1].width
|
||||
- clearAllButton.width - Theme.spacingM * 3
|
||||
width: parent.width - parent.children[0].width - parent.children[1].width - clearAllButton.width - Theme.spacingM * 3
|
||||
height: 1
|
||||
}
|
||||
|
||||
@@ -732,8 +725,8 @@ Item {
|
||||
iconColor: Theme.error
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
AppUsageHistoryData.appUsageRanking = {}
|
||||
AppUsageHistoryData.saveSettings()
|
||||
AppUsageHistoryData.appUsageRanking = {};
|
||||
AppUsageHistoryData.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,12 +752,8 @@ Item {
|
||||
width: rankedAppsList.width
|
||||
height: 48
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r,
|
||||
Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b, 0.1)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
@@ -792,7 +781,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onStatusChanged: {
|
||||
if (status === Image.Error)
|
||||
source = "image://icon/application-x-executable"
|
||||
source = "image://icon/application-x-executable";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,8 +790,7 @@ Item {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: modelData.name
|
||||
|| "Unknown App"
|
||||
text: modelData.name || "Unknown App"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
@@ -811,37 +799,27 @@ Item {
|
||||
StyledText {
|
||||
text: {
|
||||
if (!modelData.lastUsed)
|
||||
return "Never used"
|
||||
return "Never used";
|
||||
|
||||
var date = new Date(modelData.lastUsed)
|
||||
var now = new Date()
|
||||
var diffMs = now - date
|
||||
var diffMins = Math.floor(
|
||||
diffMs / (1000 * 60))
|
||||
var diffHours = Math.floor(
|
||||
diffMs / (1000 * 60 * 60))
|
||||
var diffDays = Math.floor(
|
||||
diffMs / (1000 * 60 * 60 * 24))
|
||||
var date = new Date(modelData.lastUsed);
|
||||
var now = new Date();
|
||||
var diffMs = now - date;
|
||||
var diffMins = Math.floor(diffMs / (1000 * 60));
|
||||
var diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
||||
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
if (diffMins < 1)
|
||||
return I18n.tr("Last launched just now")
|
||||
return I18n.tr("Last launched just now");
|
||||
|
||||
if (diffMins < 60)
|
||||
return I18n.tr("Last launched %1 minute%2 ago")
|
||||
.arg(diffMins)
|
||||
.arg(diffMins === 1 ? "" : "s")
|
||||
return I18n.tr("Last launched %1 minute%2 ago").arg(diffMins).arg(diffMins === 1 ? "" : "s");
|
||||
|
||||
if (diffHours < 24)
|
||||
return I18n.tr("Last launched %1 hour%2 ago")
|
||||
.arg(diffHours)
|
||||
.arg(diffHours === 1 ? "" : "s")
|
||||
return I18n.tr("Last launched %1 hour%2 ago").arg(diffHours).arg(diffHours === 1 ? "" : "s");
|
||||
|
||||
if (diffDays < 7)
|
||||
return I18n.tr("Last launched %1 day%2 ago")
|
||||
.arg(diffDays)
|
||||
.arg(diffDays === 1 ? "" : "s")
|
||||
return I18n.tr("Last launched %1 day%2 ago").arg(diffDays).arg(diffDays === 1 ? "" : "s");
|
||||
|
||||
return I18n.tr("Last launched %1")
|
||||
.arg(date.toLocaleDateString())
|
||||
return I18n.tr("Last launched %1").arg(date.toLocaleDateString());
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
@@ -858,13 +836,10 @@ Item {
|
||||
iconSize: 16
|
||||
iconColor: Theme.error
|
||||
onClicked: {
|
||||
var currentRanking = Object.assign(
|
||||
{},
|
||||
AppUsageHistoryData.appUsageRanking
|
||||
|| {})
|
||||
delete currentRanking[modelData.id]
|
||||
AppUsageHistoryData.appUsageRanking = currentRanking
|
||||
AppUsageHistoryData.saveSettings()
|
||||
var currentRanking = Object.assign({}, AppUsageHistoryData.appUsageRanking || {});
|
||||
delete currentRanking[modelData.id];
|
||||
AppUsageHistoryData.appUsageRanking = currentRanking;
|
||||
AppUsageHistoryData.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -872,8 +847,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: recentlyUsedSection.rankedAppsModel.length
|
||||
=== 0 ? "No apps have been launched yet." : ""
|
||||
text: recentlyUsedSection.rankedAppsModel.length === 0 ? "No apps have been launched yet." : ""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
@@ -66,13 +66,14 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
// Wallpaper Section
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -15,10 +14,10 @@ StyledRect {
|
||||
property string pluginId: pluginData ? pluginData.id : ""
|
||||
property string pluginDirectoryName: {
|
||||
if (pluginData && pluginData.pluginDirectory) {
|
||||
var path = pluginData.pluginDirectory
|
||||
return path.substring(path.lastIndexOf('/') + 1)
|
||||
var path = pluginData.pluginDirectory;
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
}
|
||||
return pluginId
|
||||
return pluginId;
|
||||
}
|
||||
property string pluginName: pluginData ? (pluginData.name || pluginData.id) : ""
|
||||
property string pluginVersion: pluginData ? (pluginData.version || "1.0.0") : ""
|
||||
@@ -44,7 +43,7 @@ StyledRect {
|
||||
cursorShape: root.hasSettings ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
enabled: root.hasSettings
|
||||
onClicked: {
|
||||
root.expandedPluginId = root.expandedPluginId === root.pluginId ? "" : root.pluginId
|
||||
root.expandedPluginId = root.expandedPluginId === root.pluginId ? "" : root.pluginId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,32 +126,32 @@ StyledRect {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const currentPluginName = root.pluginName
|
||||
const currentPluginId = root.pluginId
|
||||
const currentPluginName = root.pluginName;
|
||||
const currentPluginId = root.pluginId;
|
||||
DMSService.update(currentPluginName, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError("Update failed: " + response.error)
|
||||
ToastService.showError("Update failed: " + response.error);
|
||||
} else {
|
||||
ToastService.showInfo("Plugin updated: " + currentPluginName)
|
||||
PluginService.forceRescanPlugin(currentPluginId)
|
||||
ToastService.showInfo("Plugin updated: " + currentPluginName);
|
||||
PluginService.forceRescanPlugin(currentPluginId);
|
||||
if (DMSService.apiVersion >= 8) {
|
||||
DMSService.listInstalled()
|
||||
DMSService.listInstalled();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
onEntered: {
|
||||
tooltipLoader.active = true
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
const p = mapToItem(null, width / 2, 0)
|
||||
tooltipLoader.item.show(I18n.tr("Update Plugin"), p.x, p.y - 40, null)
|
||||
const p = mapToItem(null, width / 2, 0);
|
||||
tooltipLoader.item.show(I18n.tr("Update Plugin"), p.x, p.y - 40, null);
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
tooltipLoader.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,31 +176,31 @@ StyledRect {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const currentPluginName = root.pluginName
|
||||
const currentPluginName = root.pluginName;
|
||||
DMSService.uninstall(currentPluginName, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError("Uninstall failed: " + response.error)
|
||||
ToastService.showError("Uninstall failed: " + response.error);
|
||||
} else {
|
||||
ToastService.showInfo("Plugin uninstalled: " + currentPluginName)
|
||||
PluginService.scanPlugins()
|
||||
ToastService.showInfo("Plugin uninstalled: " + currentPluginName);
|
||||
PluginService.scanPlugins();
|
||||
if (root.isExpanded) {
|
||||
root.expandedPluginId = ""
|
||||
root.expandedPluginId = "";
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
onEntered: {
|
||||
tooltipLoader.active = true
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
const p = mapToItem(null, width / 2, 0)
|
||||
tooltipLoader.item.show(I18n.tr("Uninstall Plugin"), p.x, p.y - 40, null)
|
||||
const p = mapToItem(null, width / 2, 0);
|
||||
tooltipLoader.item.show(I18n.tr("Uninstall Plugin"), p.x, p.y - 40, null);
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
tooltipLoader.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,28 +225,28 @@ StyledRect {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const currentPluginId = root.pluginId
|
||||
const currentPluginName = root.pluginName
|
||||
root.isReloading = true
|
||||
const currentPluginId = root.pluginId;
|
||||
const currentPluginName = root.pluginName;
|
||||
root.isReloading = true;
|
||||
if (PluginService.reloadPlugin(currentPluginId)) {
|
||||
ToastService.showInfo("Plugin reloaded: " + currentPluginName)
|
||||
ToastService.showInfo("Plugin reloaded: " + currentPluginName);
|
||||
} else {
|
||||
ToastService.showError("Failed to reload plugin: " + currentPluginName)
|
||||
root.isReloading = false
|
||||
ToastService.showError("Failed to reload plugin: " + currentPluginName);
|
||||
root.isReloading = false;
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
tooltipLoader.active = true
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
const p = mapToItem(null, width / 2, 0)
|
||||
tooltipLoader.item.show(I18n.tr("Reload Plugin"), p.x, p.y - 40, null)
|
||||
const p = mapToItem(null, width / 2, 0);
|
||||
tooltipLoader.item.show(I18n.tr("Reload Plugin"), p.x, p.y - 40, null);
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
tooltipLoader.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,25 +256,25 @@ StyledRect {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: PluginService.isPluginLoaded(root.pluginId)
|
||||
onToggled: isChecked => {
|
||||
const currentPluginId = root.pluginId
|
||||
const currentPluginName = root.pluginName
|
||||
const currentPluginId = root.pluginId;
|
||||
const currentPluginName = root.pluginName;
|
||||
|
||||
if (isChecked) {
|
||||
if (PluginService.enablePlugin(currentPluginId)) {
|
||||
ToastService.showInfo("Plugin enabled: " + currentPluginName)
|
||||
ToastService.showInfo("Plugin enabled: " + currentPluginName);
|
||||
} else {
|
||||
ToastService.showError("Failed to enable plugin: " + currentPluginName)
|
||||
checked = false
|
||||
ToastService.showError("Failed to enable plugin: " + currentPluginName);
|
||||
checked = false;
|
||||
}
|
||||
} else {
|
||||
if (PluginService.disablePlugin(currentPluginId)) {
|
||||
ToastService.showInfo("Plugin disabled: " + currentPluginName)
|
||||
ToastService.showInfo("Plugin disabled: " + currentPluginName);
|
||||
if (root.isExpanded) {
|
||||
root.expandedPluginId = ""
|
||||
root.expandedPluginId = "";
|
||||
}
|
||||
} else {
|
||||
ToastService.showError("Failed to disable plugin: " + currentPluginName)
|
||||
checked = true
|
||||
ToastService.showError("Failed to disable plugin: " + currentPluginName);
|
||||
checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -330,7 +329,7 @@ StyledRect {
|
||||
focus: root.isExpanded && root.hasSettings
|
||||
|
||||
Keys.onPressed: event => {
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -350,38 +349,34 @@ StyledRect {
|
||||
|
||||
source: {
|
||||
if (active && root.pluginSettingsPath) {
|
||||
var path = root.pluginSettingsPath
|
||||
var path = root.pluginSettingsPath;
|
||||
if (!path.startsWith("file://")) {
|
||||
path = "file://" + path
|
||||
path = "file://" + path;
|
||||
}
|
||||
return path
|
||||
return path;
|
||||
}
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (item && typeof PluginService !== "undefined") {
|
||||
item.pluginService = PluginService
|
||||
item.pluginService = PluginService;
|
||||
}
|
||||
if (item && typeof PopoutService !== "undefined" && "popoutService" in item) {
|
||||
item.popoutService = PopoutService
|
||||
item.popoutService = PopoutService;
|
||||
}
|
||||
if (item) {
|
||||
Qt.callLater(() => {
|
||||
settingsContainer.focus = true
|
||||
item.forceActiveFocus()
|
||||
})
|
||||
settingsContainer.focus = true;
|
||||
item.forceActiveFocus();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: !PluginService.isPluginLoaded(root.pluginId) ?
|
||||
"Enable plugin to access settings" :
|
||||
(settingsLoader.status === Loader.Error ?
|
||||
"Failed to load settings" :
|
||||
"No configurable settings")
|
||||
text: !PluginService.isPluginLoaded(root.pluginId) ? "Enable plugin to access settings" : (settingsLoader.status === Loader.Error ? "Failed to load settings" : "No configurable settings")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
visible: root.isExpanded && (!settingsLoader.active || settingsLoader.status === Loader.Error)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Common
|
||||
import qs.Modals.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
@@ -20,13 +17,14 @@ FocusScope {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
@@ -126,7 +124,7 @@ FocusScope {
|
||||
iconName: "store"
|
||||
enabled: DMSService.dmsAvailable
|
||||
onClicked: {
|
||||
pluginBrowserModal.show()
|
||||
pluginBrowserModal.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,12 +132,12 @@ FocusScope {
|
||||
text: I18n.tr("Scan")
|
||||
iconName: "refresh"
|
||||
onClicked: {
|
||||
pluginsTab.isRefreshingPlugins = true
|
||||
PluginService.scanPlugins()
|
||||
pluginsTab.isRefreshingPlugins = true;
|
||||
PluginService.scanPlugins();
|
||||
if (DMSService.dmsAvailable) {
|
||||
DMSService.listInstalled()
|
||||
DMSService.listInstalled();
|
||||
}
|
||||
pluginsTab.refreshPluginList()
|
||||
pluginsTab.refreshPluginList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +145,8 @@ FocusScope {
|
||||
text: I18n.tr("Create Dir")
|
||||
iconName: "create_new_folder"
|
||||
onClicked: {
|
||||
PluginService.createPluginDirectory()
|
||||
ToastService.showInfo("Created plugin directory: " + PluginService.pluginDirectory)
|
||||
PluginService.createPluginDirectory();
|
||||
ToastService.showInfo("Created plugin directory: " + PluginService.pluginDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,15 +224,16 @@ FocusScope {
|
||||
pluginData: modelData
|
||||
expandedPluginId: pluginsTab.expandedPluginId
|
||||
hasUpdate: {
|
||||
if (DMSService.apiVersion < 8) return false
|
||||
return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false
|
||||
if (DMSService.apiVersion < 8)
|
||||
return false;
|
||||
return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false;
|
||||
}
|
||||
isReloading: pluginsTab.isReloading
|
||||
onExpandedPluginIdChanged: {
|
||||
pluginsTab.expandedPluginId = expandedPluginId
|
||||
pluginsTab.expandedPluginId = expandedPluginId;
|
||||
}
|
||||
onIsReloadingChanged: {
|
||||
pluginsTab.isReloading = isReloading
|
||||
pluginsTab.isReloading = isReloading;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,69 +254,69 @@ FocusScope {
|
||||
|
||||
function refreshPluginList() {
|
||||
Qt.callLater(() => {
|
||||
var plugins = PluginService.getAvailablePlugins()
|
||||
pluginRepeater.model = null
|
||||
pluginRepeater.model = plugins
|
||||
pluginsTab.isRefreshingPlugins = false
|
||||
})
|
||||
var plugins = PluginService.getAvailablePlugins();
|
||||
pluginRepeater.model = null;
|
||||
pluginRepeater.model = plugins;
|
||||
pluginsTab.isRefreshingPlugins = false;
|
||||
});
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PluginService
|
||||
function onPluginLoaded() {
|
||||
refreshPluginList()
|
||||
refreshPluginList();
|
||||
if (isReloading) {
|
||||
isReloading = false
|
||||
isReloading = false;
|
||||
}
|
||||
}
|
||||
function onPluginUnloaded() {
|
||||
refreshPluginList()
|
||||
refreshPluginList();
|
||||
if (!isReloading && pluginsTab.expandedPluginId !== "" && !PluginService.isPluginLoaded(pluginsTab.expandedPluginId)) {
|
||||
pluginsTab.expandedPluginId = ""
|
||||
pluginsTab.expandedPluginId = "";
|
||||
}
|
||||
}
|
||||
function onPluginListUpdated() {
|
||||
if (DMSService.apiVersion >= 8) {
|
||||
DMSService.listInstalled()
|
||||
DMSService.listInstalled();
|
||||
}
|
||||
refreshPluginList()
|
||||
refreshPluginList();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DMSService
|
||||
function onPluginsListReceived(plugins) {
|
||||
pluginBrowserModal.isLoading = false
|
||||
pluginBrowserModal.allPlugins = plugins
|
||||
pluginBrowserModal.updateFilteredPlugins()
|
||||
pluginBrowserModal.isLoading = false;
|
||||
pluginBrowserModal.allPlugins = plugins;
|
||||
pluginBrowserModal.updateFilteredPlugins();
|
||||
}
|
||||
function onInstalledPluginsReceived(plugins) {
|
||||
var pluginMap = {}
|
||||
var pluginMap = {};
|
||||
for (var i = 0; i < plugins.length; i++) {
|
||||
var plugin = plugins[i]
|
||||
var hasUpdate = plugin.hasUpdate || false
|
||||
var plugin = plugins[i];
|
||||
var hasUpdate = plugin.hasUpdate || false;
|
||||
if (plugin.id) {
|
||||
pluginMap[plugin.id] = hasUpdate
|
||||
pluginMap[plugin.id] = hasUpdate;
|
||||
}
|
||||
if (plugin.name) {
|
||||
pluginMap[plugin.name] = hasUpdate
|
||||
pluginMap[plugin.name] = hasUpdate;
|
||||
}
|
||||
}
|
||||
installedPluginsData = pluginMap
|
||||
Qt.callLater(refreshPluginList)
|
||||
installedPluginsData = pluginMap;
|
||||
Qt.callLater(refreshPluginList);
|
||||
}
|
||||
function onOperationSuccess(message) {
|
||||
ToastService.showInfo(message)
|
||||
ToastService.showInfo(message);
|
||||
}
|
||||
function onOperationError(error) {
|
||||
ToastService.showError(error)
|
||||
ToastService.showError(error);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
pluginBrowserModal.parentModal = pluginsTab.parentModal
|
||||
pluginBrowserModal.parentModal = pluginsTab.parentModal;
|
||||
if (DMSService.dmsAvailable && DMSService.apiVersion >= 8) {
|
||||
DMSService.listInstalled()
|
||||
DMSService.listInstalled();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Column {
|
||||
spacing: expanded ? Theme.spacingM : 0
|
||||
Component.onCompleted: {
|
||||
if (!collapsible)
|
||||
expanded = true
|
||||
expanded = true;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -26,15 +26,12 @@ Column {
|
||||
hoverEnabled: collapsible
|
||||
onClicked: {
|
||||
if (collapsible)
|
||||
expanded = !expanded
|
||||
expanded = !expanded;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: parent.containsMouse ? Qt.rgba(Theme.primary.r,
|
||||
Theme.primary.g,
|
||||
Theme.primary.b,
|
||||
0.08) : "transparent"
|
||||
color: parent.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
radius: Theme.radiusS
|
||||
}
|
||||
|
||||
|
||||
@@ -59,13 +59,14 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
// Theme Color
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import qs.Common
|
||||
@@ -12,13 +11,14 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
@@ -26,8 +26,7 @@ Item {
|
||||
height: timeSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -49,8 +48,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- toggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -76,9 +74,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.use24HourClock
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("use24HourClock",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("use24HourClock", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,8 +86,7 @@ Item {
|
||||
height: timeSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -112,8 +108,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- toggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -139,9 +134,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.showSeconds
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showSeconds",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("showSeconds", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,8 +146,7 @@ Item {
|
||||
height: dateSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -189,60 +182,67 @@ Item {
|
||||
description: "Preview: " + (SettingsData.clockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat) : new Date().toLocaleDateString(Qt.locale(), "ddd d"))
|
||||
currentValue: {
|
||||
if (!SettingsData.clockDateFormat || SettingsData.clockDateFormat.length === 0) {
|
||||
return "System Default"
|
||||
return "System Default";
|
||||
}
|
||||
const presets = [{
|
||||
"format": "ddd d",
|
||||
"label": "Day Date"
|
||||
}, {
|
||||
"format": "ddd MMM d",
|
||||
"label": "Day Month Date"
|
||||
}, {
|
||||
"format": "MMM d",
|
||||
"label": "Month Date"
|
||||
}, {
|
||||
"format": "M/d",
|
||||
"label": "Numeric (M/D)"
|
||||
}, {
|
||||
"format": "d/M",
|
||||
"label": "Numeric (D/M)"
|
||||
}, {
|
||||
"format": "ddd d MMM yyyy",
|
||||
"label": "Full with Year"
|
||||
}, {
|
||||
"format": "yyyy-MM-dd",
|
||||
"label": "ISO Date"
|
||||
}, {
|
||||
"format": "dddd, MMMM d",
|
||||
"label": "Full Day & Month"
|
||||
}]
|
||||
const presets = [
|
||||
{
|
||||
"format": "ddd d",
|
||||
"label": "Day Date"
|
||||
},
|
||||
{
|
||||
"format": "ddd MMM d",
|
||||
"label": "Day Month Date"
|
||||
},
|
||||
{
|
||||
"format": "MMM d",
|
||||
"label": "Month Date"
|
||||
},
|
||||
{
|
||||
"format": "M/d",
|
||||
"label": "Numeric (M/D)"
|
||||
},
|
||||
{
|
||||
"format": "d/M",
|
||||
"label": "Numeric (D/M)"
|
||||
},
|
||||
{
|
||||
"format": "ddd d MMM yyyy",
|
||||
"label": "Full with Year"
|
||||
},
|
||||
{
|
||||
"format": "yyyy-MM-dd",
|
||||
"label": "ISO Date"
|
||||
},
|
||||
{
|
||||
"format": "dddd, MMMM d",
|
||||
"label": "Full Day & Month"
|
||||
}
|
||||
];
|
||||
const match = presets.find(p => {
|
||||
return p.format
|
||||
=== SettingsData.clockDateFormat
|
||||
})
|
||||
return match ? match.label: I18n.tr("Custom: ") + SettingsData.clockDateFormat
|
||||
return p.format === SettingsData.clockDateFormat;
|
||||
});
|
||||
return match ? match.label : I18n.tr("Custom: ") + SettingsData.clockDateFormat;
|
||||
}
|
||||
options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
|
||||
onValueChanged: value => {
|
||||
const formatMap = {
|
||||
"System Default": "",
|
||||
"Day Date": "ddd d",
|
||||
"Day Month Date": "ddd MMM d",
|
||||
"Month Date": "MMM d",
|
||||
"Numeric (M/D)": "M/d",
|
||||
"Numeric (D/M)": "d/M",
|
||||
"Full with Year": "ddd d MMM yyyy",
|
||||
"ISO Date": "yyyy-MM-dd",
|
||||
"Full Day & Month": "dddd, MMMM d"
|
||||
}
|
||||
if (value === "Custom...") {
|
||||
customFormatInput.visible = true
|
||||
} else {
|
||||
customFormatInput.visible = false
|
||||
SettingsData.set("clockDateFormat",
|
||||
formatMap[value])
|
||||
}
|
||||
}
|
||||
const formatMap = {
|
||||
"System Default": "",
|
||||
"Day Date": "ddd d",
|
||||
"Day Month Date": "ddd MMM d",
|
||||
"Month Date": "MMM d",
|
||||
"Numeric (M/D)": "M/d",
|
||||
"Numeric (D/M)": "d/M",
|
||||
"Full with Year": "ddd d MMM yyyy",
|
||||
"ISO Date": "yyyy-MM-dd",
|
||||
"Full Day & Month": "dddd, MMMM d"
|
||||
};
|
||||
if (value === "Custom...") {
|
||||
customFormatInput.visible = true;
|
||||
} else {
|
||||
customFormatInput.visible = false;
|
||||
SettingsData.set("clockDateFormat", formatMap[value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
@@ -251,60 +251,67 @@ Item {
|
||||
description: "Preview: " + (SettingsData.lockDateFormat ? new Date().toLocaleDateString(Qt.locale(), SettingsData.lockDateFormat) : new Date().toLocaleDateString(Qt.locale(), Locale.LongFormat))
|
||||
currentValue: {
|
||||
if (!SettingsData.lockDateFormat || SettingsData.lockDateFormat.length === 0) {
|
||||
return "System Default"
|
||||
return "System Default";
|
||||
}
|
||||
const presets = [{
|
||||
"format": "ddd d",
|
||||
"label": "Day Date"
|
||||
}, {
|
||||
"format": "ddd MMM d",
|
||||
"label": "Day Month Date"
|
||||
}, {
|
||||
"format": "MMM d",
|
||||
"label": "Month Date"
|
||||
}, {
|
||||
"format": "M/d",
|
||||
"label": "Numeric (M/D)"
|
||||
}, {
|
||||
"format": "d/M",
|
||||
"label": "Numeric (D/M)"
|
||||
}, {
|
||||
"format": "ddd d MMM yyyy",
|
||||
"label": "Full with Year"
|
||||
}, {
|
||||
"format": "yyyy-MM-dd",
|
||||
"label": "ISO Date"
|
||||
}, {
|
||||
"format": "dddd, MMMM d",
|
||||
"label": "Full Day & Month"
|
||||
}]
|
||||
const presets = [
|
||||
{
|
||||
"format": "ddd d",
|
||||
"label": "Day Date"
|
||||
},
|
||||
{
|
||||
"format": "ddd MMM d",
|
||||
"label": "Day Month Date"
|
||||
},
|
||||
{
|
||||
"format": "MMM d",
|
||||
"label": "Month Date"
|
||||
},
|
||||
{
|
||||
"format": "M/d",
|
||||
"label": "Numeric (M/D)"
|
||||
},
|
||||
{
|
||||
"format": "d/M",
|
||||
"label": "Numeric (D/M)"
|
||||
},
|
||||
{
|
||||
"format": "ddd d MMM yyyy",
|
||||
"label": "Full with Year"
|
||||
},
|
||||
{
|
||||
"format": "yyyy-MM-dd",
|
||||
"label": "ISO Date"
|
||||
},
|
||||
{
|
||||
"format": "dddd, MMMM d",
|
||||
"label": "Full Day & Month"
|
||||
}
|
||||
];
|
||||
const match = presets.find(p => {
|
||||
return p.format
|
||||
=== SettingsData.lockDateFormat
|
||||
})
|
||||
return match ? match.label: I18n.tr("Custom: ") + SettingsData.lockDateFormat
|
||||
return p.format === SettingsData.lockDateFormat;
|
||||
});
|
||||
return match ? match.label : I18n.tr("Custom: ") + SettingsData.lockDateFormat;
|
||||
}
|
||||
options: ["System Default", "Day Date", "Day Month Date", "Month Date", "Numeric (M/D)", "Numeric (D/M)", "Full with Year", "ISO Date", "Full Day & Month", "Custom..."]
|
||||
onValueChanged: value => {
|
||||
const formatMap = {
|
||||
"System Default": "",
|
||||
"Day Date": "ddd d",
|
||||
"Day Month Date": "ddd MMM d",
|
||||
"Month Date": "MMM d",
|
||||
"Numeric (M/D)": "M/d",
|
||||
"Numeric (D/M)": "d/M",
|
||||
"Full with Year": "ddd d MMM yyyy",
|
||||
"ISO Date": "yyyy-MM-dd",
|
||||
"Full Day & Month": "dddd, MMMM d"
|
||||
}
|
||||
if (value === "Custom...") {
|
||||
customLockFormatInput.visible = true
|
||||
} else {
|
||||
customLockFormatInput.visible = false
|
||||
SettingsData.set("lockDateFormat",
|
||||
formatMap[value])
|
||||
}
|
||||
}
|
||||
const formatMap = {
|
||||
"System Default": "",
|
||||
"Day Date": "ddd d",
|
||||
"Day Month Date": "ddd MMM d",
|
||||
"Month Date": "MMM d",
|
||||
"Numeric (M/D)": "M/d",
|
||||
"Numeric (D/M)": "d/M",
|
||||
"Full with Year": "ddd d MMM yyyy",
|
||||
"ISO Date": "yyyy-MM-dd",
|
||||
"Full Day & Month": "dddd, MMMM d"
|
||||
};
|
||||
if (value === "Custom...") {
|
||||
customLockFormatInput.visible = true;
|
||||
} else {
|
||||
customLockFormatInput.visible = false;
|
||||
SettingsData.set("lockDateFormat", formatMap[value]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -316,7 +323,7 @@ Item {
|
||||
text: SettingsData.clockDateFormat
|
||||
onTextChanged: {
|
||||
if (visible && text)
|
||||
SettingsData.set("clockDateFormat", text)
|
||||
SettingsData.set("clockDateFormat", text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +336,7 @@ Item {
|
||||
text: SettingsData.lockDateFormat
|
||||
onTextChanged: {
|
||||
if (visible && text)
|
||||
SettingsData.set("lockDateFormat", text)
|
||||
SettingsData.set("lockDateFormat", text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,8 +345,7 @@ Item {
|
||||
height: formatHelp.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.1)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -440,8 +446,7 @@ Item {
|
||||
height: enableWeatherSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -463,8 +468,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- enableToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - enableToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -490,9 +494,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.weatherEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("weatherEnabled",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("weatherEnabled", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,8 +506,7 @@ Item {
|
||||
height: temperatureSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: SettingsData.weatherEnabled
|
||||
opacity: visible ? 1 : 0
|
||||
@@ -528,8 +530,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- temperatureToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - temperatureToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -555,9 +556,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.useFahrenheit
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("useFahrenheit",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("useFahrenheit", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,8 +575,7 @@ Item {
|
||||
height: locationSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: SettingsData.weatherEnabled
|
||||
opacity: visible ? 1 : 0
|
||||
@@ -600,8 +599,7 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM
|
||||
- autoLocationToggle.width - Theme.spacingM
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM - autoLocationToggle.width - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
@@ -627,9 +625,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.useAutoLocation
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("useAutoLocation",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("useAutoLocation", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,113 +650,113 @@ Item {
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
spacing: Theme.spacingXS
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Latitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: latitudeInput
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "40.7128"
|
||||
backgroundColor: Theme.surfaceVariant
|
||||
normalBorderColor: Theme.primarySelected
|
||||
focusedBorderColor: Theme.primary
|
||||
keyNavigationTab: longitudeInput
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',')
|
||||
if (coords.length > 0) {
|
||||
text = coords[0].trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWeatherCoordinatesChanged() {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',')
|
||||
if (coords.length > 0) {
|
||||
latitudeInput.text = coords[0].trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
if (text && longitudeInput.text) {
|
||||
const coords = text + "," + longitudeInput.text
|
||||
SettingsData.weatherCoordinates = coords
|
||||
SettingsData.saveSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
StyledText {
|
||||
text: I18n.tr("Latitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
spacing: Theme.spacingXS
|
||||
DankTextField {
|
||||
id: latitudeInput
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "40.7128"
|
||||
backgroundColor: Theme.surfaceVariant
|
||||
normalBorderColor: Theme.primarySelected
|
||||
focusedBorderColor: Theme.primary
|
||||
keyNavigationTab: longitudeInput
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Longitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',');
|
||||
if (coords.length > 0) {
|
||||
text = coords[0].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: longitudeInput
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "-74.0060"
|
||||
backgroundColor: Theme.surfaceVariant
|
||||
normalBorderColor: Theme.primarySelected
|
||||
focusedBorderColor: Theme.primary
|
||||
keyNavigationTab: locationSearchInput
|
||||
keyNavigationBacktab: latitudeInput
|
||||
|
||||
Component.onCompleted: {
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWeatherCoordinatesChanged() {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',')
|
||||
if (coords.length > 1) {
|
||||
text = coords[1].trim()
|
||||
const coords = SettingsData.weatherCoordinates.split(',');
|
||||
if (coords.length > 0) {
|
||||
latitudeInput.text = coords[0].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWeatherCoordinatesChanged() {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',')
|
||||
if (coords.length > 1) {
|
||||
longitudeInput.text = coords[1].trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
if (text && latitudeInput.text) {
|
||||
const coords = latitudeInput.text + "," + text
|
||||
SettingsData.weatherCoordinates = coords
|
||||
SettingsData.saveSettings()
|
||||
}
|
||||
onTextEdited: {
|
||||
if (text && longitudeInput.text) {
|
||||
const coords = text + "," + longitudeInput.text;
|
||||
SettingsData.weatherCoordinates = coords;
|
||||
SettingsData.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Longitude")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: longitudeInput
|
||||
width: parent.width
|
||||
height: 48
|
||||
placeholderText: "-74.0060"
|
||||
backgroundColor: Theme.surfaceVariant
|
||||
normalBorderColor: Theme.primarySelected
|
||||
focusedBorderColor: Theme.primary
|
||||
keyNavigationTab: locationSearchInput
|
||||
keyNavigationBacktab: latitudeInput
|
||||
|
||||
Component.onCompleted: {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',');
|
||||
if (coords.length > 1) {
|
||||
text = coords[1].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWeatherCoordinatesChanged() {
|
||||
if (SettingsData.weatherCoordinates) {
|
||||
const coords = SettingsData.weatherCoordinates.split(',');
|
||||
if (coords.length > 1) {
|
||||
longitudeInput.text = coords[1].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTextEdited: {
|
||||
if (text && latitudeInput.text) {
|
||||
const coords = latitudeInput.text + "," + text;
|
||||
SettingsData.weatherCoordinates = coords;
|
||||
SettingsData.saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXS
|
||||
@@ -778,14 +775,14 @@ Item {
|
||||
placeholderText: I18n.tr("New York, NY")
|
||||
keyNavigationBacktab: longitudeInput
|
||||
onLocationSelected: (displayName, coordinates) => {
|
||||
SettingsData.setWeatherLocation(displayName, coordinates)
|
||||
SettingsData.setWeatherLocation(displayName, coordinates);
|
||||
|
||||
const coords = coordinates.split(',')
|
||||
if (coords.length >= 2) {
|
||||
latitudeInput.text = coords[0].trim()
|
||||
longitudeInput.text = coords[1].trim()
|
||||
}
|
||||
}
|
||||
const coords = coordinates.split(',');
|
||||
if (coords.length >= 2) {
|
||||
latitudeInput.text = coords[0].trim();
|
||||
longitudeInput.text = coords[1].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -804,8 +801,7 @@ Item {
|
||||
height: weatherDisplaySection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: SettingsData.weatherEnabled
|
||||
opacity: visible ? 1 : 0
|
||||
@@ -882,9 +878,9 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: parent.enabled ? Qt.PointingHandCursor : Qt.ForbiddenCursor
|
||||
onClicked: {
|
||||
refreshButton.isRefreshing = true
|
||||
WeatherService.forceRefresh()
|
||||
refreshTimer.restart()
|
||||
refreshButton.isRefreshing = true;
|
||||
WeatherService.forceRefresh();
|
||||
refreshTimer.restart();
|
||||
}
|
||||
enabled: parent.enabled
|
||||
}
|
||||
@@ -965,7 +961,7 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (WeatherService.weather.available) {
|
||||
SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit)
|
||||
SettingsData.set("useFahrenheit", !SettingsData.useFahrenheit);
|
||||
}
|
||||
}
|
||||
enabled: WeatherService.weather.available
|
||||
@@ -1185,14 +1181,16 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!WeatherService.weather.wind) return "--"
|
||||
const windKmh = parseFloat(WeatherService.weather.wind)
|
||||
if (isNaN(windKmh)) return WeatherService.weather.wind
|
||||
if (!WeatherService.weather.wind)
|
||||
return "--";
|
||||
const windKmh = parseFloat(WeatherService.weather.wind);
|
||||
if (isNaN(windKmh))
|
||||
return WeatherService.weather.wind;
|
||||
if (SettingsData.useFahrenheit) {
|
||||
const windMph = Math.round(windKmh * 0.621371)
|
||||
return windMph + " mph"
|
||||
const windMph = Math.round(windKmh * 0.621371);
|
||||
return windMph + " mph";
|
||||
}
|
||||
return WeatherService.weather.wind
|
||||
return WeatherService.weather.wind;
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall + 1
|
||||
color: Theme.surfaceText
|
||||
@@ -1241,13 +1239,14 @@ Item {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!WeatherService.weather.pressure) return "--"
|
||||
const pressureHpa = WeatherService.weather.pressure
|
||||
if (!WeatherService.weather.pressure)
|
||||
return "--";
|
||||
const pressureHpa = WeatherService.weather.pressure;
|
||||
if (SettingsData.useFahrenheit) {
|
||||
const pressureInHg = (pressureHpa * 0.02953).toFixed(2)
|
||||
return pressureInHg + " inHg"
|
||||
const pressureInHg = (pressureHpa * 0.02953).toFixed(2);
|
||||
return pressureInHg + " inHg";
|
||||
}
|
||||
return pressureHpa + " hPa"
|
||||
return pressureHpa + " hPa";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall + 1
|
||||
color: Theme.surfaceText
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Modals.Common
|
||||
import qs.Widgets
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -10,12 +9,13 @@ Item {
|
||||
DankFlickable {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentHeight: mainColumn.height
|
||||
contentHeight: mainColumn.height + Theme.spacingXL
|
||||
contentWidth: width
|
||||
|
||||
Column {
|
||||
id: mainColumn
|
||||
width: parent.width
|
||||
width: Math.min(550, parent.width - Theme.spacingL * 2)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
@@ -23,8 +23,7 @@ Item {
|
||||
height: workspaceSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -60,9 +59,8 @@ Item {
|
||||
description: I18n.tr("Show workspace index numbers in the top bar workspace switcher")
|
||||
checked: SettingsData.showWorkspaceIndex
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showWorkspaceIndex",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("showWorkspaceIndex", checked);
|
||||
}
|
||||
}
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
@@ -70,9 +68,8 @@ Item {
|
||||
description: I18n.tr("Always show a minimum of 3 workspaces, even if fewer are available")
|
||||
checked: SettingsData.showWorkspacePadding
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showWorkspacePadding",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("showWorkspacePadding", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -82,12 +79,11 @@ Item {
|
||||
checked: SettingsData.showWorkspaceApps
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showWorkspaceApps",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("showWorkspaceApps", checked);
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
Row {
|
||||
width: parent.width - Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
visible: SettingsData.showWorkspaceApps
|
||||
@@ -116,7 +112,7 @@ Item {
|
||||
topPadding: Theme.spacingXS
|
||||
bottomPadding: Theme.spacingXS
|
||||
onEditingFinished: {
|
||||
SettingsData.set("maxWorkspaceIcons", parseInt(text, 10))
|
||||
SettingsData.set("maxWorkspaceIcons", parseInt(text, 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,6 +135,17 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show Occupied Workspaces Only")
|
||||
description: I18n.tr("Display only workspaces that contain windows")
|
||||
checked: SettingsData.showOccupiedWorkspacesOnly
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("showOccupiedWorkspacesOnly", checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Show All Tags")
|
||||
@@ -157,8 +164,7 @@ Item {
|
||||
height: mediaSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -290,8 +296,8 @@ Item {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => {
|
||||
updaterCustomCommand.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
updaterCustomCommand.forceActiveFocus();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,8 +343,8 @@ Item {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => {
|
||||
updaterTerminalCustomClass.forceActiveFocus()
|
||||
mouse.accepted = false
|
||||
updaterTerminalCustomClass.forceActiveFocus();
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,8 +358,7 @@ Item {
|
||||
height: runningAppsSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: CompositorService.isNiri || CompositorService.isHyprland
|
||||
|
||||
@@ -390,9 +395,8 @@ Item {
|
||||
description: I18n.tr("Show only apps running in current workspace")
|
||||
checked: SettingsData.runningAppsCurrentWorkspace
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("runningAppsCurrentWorkspace",
|
||||
checked)
|
||||
}
|
||||
return SettingsData.set("runningAppsCurrentWorkspace", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,8 +406,7 @@ Item {
|
||||
height: workspaceIconsSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
visible: SettingsData.hasNamedWorkspaces()
|
||||
|
||||
@@ -449,12 +452,8 @@ Item {
|
||||
width: parent.width
|
||||
height: workspaceIconRow.implicitHeight + Theme.spacingM
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r,
|
||||
Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.5)
|
||||
border.color: Qt.rgba(Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b, 0.3)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.5)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
@@ -482,35 +481,28 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Component.onCompleted: {
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(
|
||||
modelData)
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(modelData);
|
||||
if (iconData) {
|
||||
setIcon(iconData.value,
|
||||
iconData.type)
|
||||
setIcon(iconData.value, iconData.type);
|
||||
}
|
||||
}
|
||||
|
||||
onIconSelected: (iconName, iconType) => {
|
||||
SettingsData.setWorkspaceNameIcon(
|
||||
modelData, {
|
||||
"type": iconType,
|
||||
"value": iconName
|
||||
})
|
||||
setIcon(iconName,
|
||||
iconType)
|
||||
}
|
||||
SettingsData.setWorkspaceNameIcon(modelData, {
|
||||
"type": iconType,
|
||||
"value": iconName
|
||||
});
|
||||
setIcon(iconName, iconType);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onWorkspaceIconsUpdated() {
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(
|
||||
modelData)
|
||||
var iconData = SettingsData.getWorkspaceNameIcon(modelData);
|
||||
if (iconData) {
|
||||
iconPicker.setIcon(
|
||||
iconData.value,
|
||||
iconData.type)
|
||||
iconPicker.setIcon(iconData.value, iconData.type);
|
||||
} else {
|
||||
iconPicker.setIcon("", "icon")
|
||||
iconPicker.setIcon("", "icon");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,8 +531,7 @@ Item {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
SettingsData.removeWorkspaceNameIcon(
|
||||
modelData)
|
||||
SettingsData.removeWorkspaceNameIcon(modelData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -560,8 +551,7 @@ Item {
|
||||
height: notificationSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -603,41 +593,41 @@ Item {
|
||||
description: I18n.tr("Choose where notification popups appear on screen")
|
||||
currentValue: {
|
||||
if (SettingsData.notificationPopupPosition === -1) {
|
||||
return "Top Center"
|
||||
return "Top Center";
|
||||
}
|
||||
switch (SettingsData.notificationPopupPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right"
|
||||
return "Top Right";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left"
|
||||
return "Bottom Left";
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left"
|
||||
return "Top Left";
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right"
|
||||
return "Bottom Right";
|
||||
default:
|
||||
return "Top Right"
|
||||
return "Top Right";
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Top)
|
||||
break
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Top);
|
||||
break;
|
||||
case "Top Left":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Left)
|
||||
break
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Left);
|
||||
break;
|
||||
case "Top Center":
|
||||
SettingsData.set("notificationPopupPosition", -1)
|
||||
break
|
||||
SettingsData.set("notificationPopupPosition", -1);
|
||||
break;
|
||||
case "Bottom Right":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Right)
|
||||
break
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Right);
|
||||
break;
|
||||
case "Bottom Left":
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom)
|
||||
break
|
||||
SettingsData.set("notificationPopupPosition", SettingsData.Position.Bottom);
|
||||
break;
|
||||
}
|
||||
SettingsData.sendTestNotifications()
|
||||
SettingsData.sendTestNotifications();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -649,8 +639,7 @@ Item {
|
||||
height: osdRow.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
@@ -694,8 +683,8 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.osdAlwaysShowValue
|
||||
onToggleCompleted: checked => {
|
||||
SettingsData.set("osdAlwaysShowValue", checked)
|
||||
}
|
||||
SettingsData.set("osdAlwaysShowValue", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,8 +694,7 @@ Item {
|
||||
height: osdSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
Column {
|
||||
@@ -749,52 +737,52 @@ Item {
|
||||
currentValue: {
|
||||
switch (SettingsData.osdPosition) {
|
||||
case SettingsData.Position.Top:
|
||||
return "Top Right"
|
||||
return "Top Right";
|
||||
case SettingsData.Position.Left:
|
||||
return "Top Left"
|
||||
return "Top Left";
|
||||
case SettingsData.Position.TopCenter:
|
||||
return "Top Center"
|
||||
return "Top Center";
|
||||
case SettingsData.Position.Right:
|
||||
return "Bottom Right"
|
||||
return "Bottom Right";
|
||||
case SettingsData.Position.Bottom:
|
||||
return "Bottom Left"
|
||||
return "Bottom Left";
|
||||
case SettingsData.Position.BottomCenter:
|
||||
return "Bottom Center"
|
||||
return "Bottom Center";
|
||||
case SettingsData.Position.LeftCenter:
|
||||
return "Left Center"
|
||||
return "Left Center";
|
||||
case SettingsData.Position.RightCenter:
|
||||
return "Right Center"
|
||||
return "Right Center";
|
||||
default:
|
||||
return "Bottom Center"
|
||||
return "Bottom Center";
|
||||
}
|
||||
}
|
||||
options: ["Top Right", "Top Left", "Top Center", "Bottom Right", "Bottom Left", "Bottom Center", "Left Center", "Right Center"]
|
||||
onValueChanged: value => {
|
||||
switch (value) {
|
||||
case "Top Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Top)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Top);
|
||||
break;
|
||||
case "Top Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Left)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Left);
|
||||
break;
|
||||
case "Top Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.TopCenter)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.TopCenter);
|
||||
break;
|
||||
case "Bottom Right":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Right)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Right);
|
||||
break;
|
||||
case "Bottom Left":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Bottom)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.Bottom);
|
||||
break;
|
||||
case "Bottom Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.BottomCenter)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.BottomCenter);
|
||||
break;
|
||||
case "Left Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.LeftCenter)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.LeftCenter);
|
||||
break;
|
||||
case "Right Center":
|
||||
SettingsData.set("osdPosition", SettingsData.Position.RightCenter)
|
||||
break
|
||||
SettingsData.set("osdPosition", SettingsData.Position.RightCenter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,18 +794,17 @@ Item {
|
||||
description: I18n.tr("Show on-screen display when volume changes")
|
||||
checked: SettingsData.osdVolumeEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdVolumeEnabled", checked)
|
||||
return SettingsData.set("osdVolumeEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: I18n.tr("Media Volume OSD")
|
||||
description: I18n.tr("Show on-screen display when media player volume changes")
|
||||
checked: SettingsData.osdMediaVolumeEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdMediaVolumeEnabled", checked)
|
||||
return SettingsData.set("osdMediaVolumeEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,7 +814,7 @@ Item {
|
||||
description: I18n.tr("Show on-screen display when brightness changes")
|
||||
checked: SettingsData.osdBrightnessEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdBrightnessEnabled", checked)
|
||||
return SettingsData.set("osdBrightnessEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -837,7 +824,7 @@ Item {
|
||||
description: I18n.tr("Show on-screen display when idle inhibitor state changes")
|
||||
checked: SettingsData.osdIdleInhibitorEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdIdleInhibitorEnabled", checked)
|
||||
return SettingsData.set("osdIdleInhibitorEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -847,7 +834,7 @@ Item {
|
||||
description: I18n.tr("Show on-screen display when microphone is muted/unmuted")
|
||||
checked: SettingsData.osdMicMuteEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdMicMuteEnabled", checked)
|
||||
return SettingsData.set("osdMicMuteEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -857,7 +844,7 @@ Item {
|
||||
description: I18n.tr("Show on-screen display when caps lock state changes")
|
||||
checked: SettingsData.osdCapsLockEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdCapsLockEnabled", checked)
|
||||
return SettingsData.set("osdCapsLockEnabled", checked);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,7 +854,7 @@ Item {
|
||||
description: I18n.tr("Show on-screen display when power profile changes")
|
||||
checked: SettingsData.osdPowerProfileEnabled
|
||||
onToggled: checked => {
|
||||
return SettingsData.set("osdPowerProfileEnabled", checked)
|
||||
return SettingsData.set("osdPowerProfileEnabled", checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
@@ -19,12 +18,12 @@ Singleton {
|
||||
command: ["which", "cava"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
root.cavaAvailable = exitCode === 0
|
||||
root.cavaAvailable = exitCode === 0;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
cavaCheck.running = true
|
||||
cavaCheck.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
@@ -35,21 +34,18 @@ Singleton {
|
||||
|
||||
onRunningChanged: {
|
||||
if (!running) {
|
||||
root.values = Array(6).fill(0)
|
||||
root.values = Array(6).fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: data => {
|
||||
if (root.refCount > 0 && data.trim()) {
|
||||
let points = data.split(";").map(p => {
|
||||
return parseInt(p.trim(), 10)
|
||||
}).filter(p => {
|
||||
return !isNaN(p)
|
||||
})
|
||||
if (points.length >= 6) {
|
||||
root.values = points.slice(0, 6)
|
||||
if (root.refCount > 0 && data.length > 0) {
|
||||
const parts = data.split(";");
|
||||
if (parts.length >= 6) {
|
||||
const points = [parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10), parseInt(parts[3], 10), parseInt(parts[4], 10), parseInt(parts[5], 10)];
|
||||
root.values = points;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,24 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Mpris
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property bool idleMonitorAvailable: {
|
||||
try {
|
||||
return typeof IdleMonitor !== "undefined"
|
||||
return typeof IdleMonitor !== "undefined";
|
||||
} catch (e) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
readonly property bool idleInhibitorAvailable: {
|
||||
try {
|
||||
return typeof IdleInhibitor !== "undefined"
|
||||
return typeof IdleInhibitor !== "undefined";
|
||||
} catch (e) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,32 +42,37 @@ Singleton {
|
||||
onSuspendTimeoutChanged: _rearmIdleMonitors()
|
||||
|
||||
function _rearmIdleMonitors() {
|
||||
_enableGate = false
|
||||
Qt.callLater(() => { _enableGate = true })
|
||||
_enableGate = false;
|
||||
Qt.callLater(() => {
|
||||
_enableGate = true;
|
||||
});
|
||||
}
|
||||
|
||||
signal lockRequested()
|
||||
signal requestMonitorOff()
|
||||
signal requestMonitorOn()
|
||||
signal requestSuspend()
|
||||
signal lockRequested
|
||||
signal fadeToLockRequested
|
||||
signal cancelFadeToLock
|
||||
signal requestMonitorOff
|
||||
signal requestMonitorOn
|
||||
signal requestSuspend
|
||||
|
||||
property var monitorOffMonitor: null
|
||||
property var lockMonitor: null
|
||||
property var suspendMonitor: null
|
||||
property var mediaInhibitor: null
|
||||
property var lockComponent: null
|
||||
|
||||
function wake() {
|
||||
requestMonitorOn()
|
||||
requestMonitorOn();
|
||||
}
|
||||
|
||||
function createMediaInhibitor() {
|
||||
if (!idleInhibitorAvailable) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if (mediaInhibitor) {
|
||||
mediaInhibitor.destroy()
|
||||
mediaInhibitor = null
|
||||
mediaInhibitor.destroy();
|
||||
mediaInhibitor = null;
|
||||
}
|
||||
|
||||
const inhibitorString = `
|
||||
@@ -79,23 +82,23 @@ Singleton {
|
||||
IdleInhibitor {
|
||||
active: false
|
||||
}
|
||||
`
|
||||
`;
|
||||
|
||||
mediaInhibitor = Qt.createQmlObject(inhibitorString, root, "IdleService.MediaInhibitor")
|
||||
mediaInhibitor.active = Qt.binding(() => root.mediaPlaying)
|
||||
mediaInhibitor = Qt.createQmlObject(inhibitorString, root, "IdleService.MediaInhibitor");
|
||||
mediaInhibitor.active = Qt.binding(() => root.mediaPlaying);
|
||||
}
|
||||
|
||||
function destroyMediaInhibitor() {
|
||||
if (mediaInhibitor) {
|
||||
mediaInhibitor.destroy()
|
||||
mediaInhibitor = null
|
||||
mediaInhibitor.destroy();
|
||||
mediaInhibitor = null;
|
||||
}
|
||||
}
|
||||
|
||||
function createIdleMonitors() {
|
||||
if (!idleMonitorAvailable) {
|
||||
console.info("IdleService: IdleMonitor not available, skipping creation")
|
||||
return
|
||||
console.info("IdleService: IdleMonitor not available, skipping creation");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -108,60 +111,68 @@ Singleton {
|
||||
respectInhibitors: true
|
||||
timeout: 0
|
||||
}
|
||||
`
|
||||
`;
|
||||
|
||||
monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor")
|
||||
monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0)
|
||||
monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors)
|
||||
monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout)
|
||||
monitorOffMonitor.isIdleChanged.connect(function() {
|
||||
monitorOffMonitor = Qt.createQmlObject(qmlString, root, "IdleService.MonitorOffMonitor");
|
||||
monitorOffMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.monitorTimeout > 0);
|
||||
monitorOffMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
||||
monitorOffMonitor.timeout = Qt.binding(() => root.monitorTimeout);
|
||||
monitorOffMonitor.isIdleChanged.connect(function () {
|
||||
if (monitorOffMonitor.isIdle) {
|
||||
root.requestMonitorOff()
|
||||
root.requestMonitorOff();
|
||||
} else {
|
||||
root.requestMonitorOn()
|
||||
root.requestMonitorOn();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor")
|
||||
lockMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.lockTimeout > 0)
|
||||
lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors)
|
||||
lockMonitor.timeout = Qt.binding(() => root.lockTimeout)
|
||||
lockMonitor.isIdleChanged.connect(function() {
|
||||
lockMonitor = Qt.createQmlObject(qmlString, root, "IdleService.LockMonitor");
|
||||
lockMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.lockTimeout > 0);
|
||||
lockMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
||||
lockMonitor.timeout = Qt.binding(() => root.lockTimeout);
|
||||
lockMonitor.isIdleChanged.connect(function () {
|
||||
if (lockMonitor.isIdle) {
|
||||
root.lockRequested()
|
||||
if (SettingsData.fadeToLockEnabled) {
|
||||
root.fadeToLockRequested();
|
||||
} else {
|
||||
root.lockRequested();
|
||||
}
|
||||
} else {
|
||||
if (SettingsData.fadeToLockEnabled) {
|
||||
root.cancelFadeToLock();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
suspendMonitor = Qt.createQmlObject(qmlString, root, "IdleService.SuspendMonitor")
|
||||
suspendMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.suspendTimeout > 0)
|
||||
suspendMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors)
|
||||
suspendMonitor.timeout = Qt.binding(() => root.suspendTimeout)
|
||||
suspendMonitor.isIdleChanged.connect(function() {
|
||||
suspendMonitor = Qt.createQmlObject(qmlString, root, "IdleService.SuspendMonitor");
|
||||
suspendMonitor.enabled = Qt.binding(() => root._enableGate && root.enabled && root.idleMonitorAvailable && root.suspendTimeout > 0);
|
||||
suspendMonitor.respectInhibitors = Qt.binding(() => root.respectInhibitors);
|
||||
suspendMonitor.timeout = Qt.binding(() => root.suspendTimeout);
|
||||
suspendMonitor.isIdleChanged.connect(function () {
|
||||
if (suspendMonitor.isIdle) {
|
||||
root.requestSuspend()
|
||||
root.requestSuspend();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (SettingsData.preventIdleForMedia) {
|
||||
createMediaInhibitor()
|
||||
createMediaInhibitor();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("IdleService: Error creating IdleMonitors:", e)
|
||||
console.warn("IdleService: Error creating IdleMonitors:", e);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onRequestMonitorOff() {
|
||||
CompositorService.powerOffMonitors()
|
||||
CompositorService.powerOffMonitors();
|
||||
}
|
||||
|
||||
function onRequestMonitorOn() {
|
||||
CompositorService.powerOnMonitors()
|
||||
CompositorService.powerOnMonitors();
|
||||
}
|
||||
|
||||
function onRequestSuspend() {
|
||||
SessionService.suspendWithBehavior(root.suspendBehavior)
|
||||
SessionService.suspendWithBehavior(root.suspendBehavior);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +180,7 @@ Singleton {
|
||||
target: SessionService
|
||||
function onPrepareForSleep() {
|
||||
if (SettingsData.lockBeforeSuspend) {
|
||||
root.lockRequested()
|
||||
root.lockRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,19 +189,19 @@ Singleton {
|
||||
target: SettingsData
|
||||
function onPreventIdleForMediaChanged() {
|
||||
if (SettingsData.preventIdleForMedia) {
|
||||
createMediaInhibitor()
|
||||
createMediaInhibitor();
|
||||
} else {
|
||||
destroyMediaInhibitor()
|
||||
destroyMediaInhibitor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!idleMonitorAvailable) {
|
||||
console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell.")
|
||||
console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell.");
|
||||
} else {
|
||||
console.info("IdleService: Initialized with idle monitoring support")
|
||||
createIdleMonitors()
|
||||
console.info("IdleService: Initialized with idle monitoring support");
|
||||
createIdleMonitors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Shapes
|
||||
import Quickshell.Services.Mpris
|
||||
import qs.Common
|
||||
@@ -18,7 +17,7 @@ Item {
|
||||
|
||||
onArtUrlChanged: {
|
||||
if (artUrl && albumArt.status !== Image.Error) {
|
||||
lastValidArtUrl = artUrl
|
||||
lastValidArtUrl = artUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +35,7 @@ Item {
|
||||
width: parent.width * 1.1
|
||||
height: parent.height * 1.1
|
||||
anchors.centerIn: parent
|
||||
visible: activePlayer?.playbackState === MprisPlaybackState.Playing && showAnimation
|
||||
visible: CavaService.cavaAvailable && activePlayer?.playbackState === MprisPlaybackState.Playing && showAnimation
|
||||
asynchronous: false
|
||||
antialiasing: true
|
||||
preferredRendererType: Shape.CurveRenderer
|
||||
@@ -50,19 +49,21 @@ Item {
|
||||
|
||||
property var audioLevels: {
|
||||
if (!CavaService.cavaAvailable || CavaService.values.length === 0) {
|
||||
return [0.5, 0.3, 0.7, 0.4, 0.6, 0.5, 0.8, 0.2, 0.9, 0.6]
|
||||
return [0.5, 0.3, 0.7, 0.4, 0.6, 0.5, 0.8, 0.2, 0.9, 0.6];
|
||||
}
|
||||
return CavaService.values
|
||||
return CavaService.values;
|
||||
}
|
||||
|
||||
property var smoothedLevels: [0.5, 0.3, 0.7, 0.4, 0.6, 0.5, 0.8, 0.2, 0.9, 0.6]
|
||||
property var cubics: []
|
||||
|
||||
onAudioLevelsChanged: updatePath()
|
||||
|
||||
FrameAnimation {
|
||||
running: morphingBlob.visible
|
||||
onTriggered: morphingBlob.updatePath()
|
||||
Connections {
|
||||
target: CavaService
|
||||
function onValuesChanged() {
|
||||
if (morphingBlob.visible) {
|
||||
morphingBlob.updatePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
@@ -71,69 +72,61 @@ Item {
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
shapePath.pathElements.push(Qt.createQmlObject(
|
||||
'import QtQuick; import QtQuick.Shapes; PathMove {}', shapePath
|
||||
))
|
||||
shapePath.pathElements.push(Qt.createQmlObject('import QtQuick; import QtQuick.Shapes; PathMove {}', shapePath));
|
||||
|
||||
for (let i = 0; i < segments; i++) {
|
||||
const seg = cubicSegment.createObject(shapePath)
|
||||
shapePath.pathElements.push(seg)
|
||||
cubics.push(seg)
|
||||
const seg = cubicSegment.createObject(shapePath);
|
||||
shapePath.pathElements.push(seg);
|
||||
cubics.push(seg);
|
||||
}
|
||||
|
||||
updatePath()
|
||||
}
|
||||
|
||||
function expSmooth(prev, next, alpha) {
|
||||
return prev + alpha * (next - prev)
|
||||
updatePath();
|
||||
}
|
||||
|
||||
function updatePath() {
|
||||
if (cubics.length === 0) return
|
||||
if (cubics.length === 0)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < Math.min(smoothedLevels.length, audioLevels.length); i++) {
|
||||
smoothedLevels[i] = expSmooth(smoothedLevels[i], audioLevels[i], 0.35)
|
||||
const alpha = 0.35;
|
||||
const minLen = Math.min(smoothedLevels.length, audioLevels.length);
|
||||
for (let i = 0; i < minLen; i++) {
|
||||
smoothedLevels[i] += alpha * (audioLevels[i] - smoothedLevels[i]);
|
||||
}
|
||||
|
||||
const points = []
|
||||
const angleStep = 2 * Math.PI / segments;
|
||||
const tension3 = 0.16666667;
|
||||
const startMove = shapePath.pathElements[0];
|
||||
|
||||
const points = new Array(segments);
|
||||
for (let i = 0; i < segments; i++) {
|
||||
const angle = (i / segments) * 2 * Math.PI
|
||||
const audioIndex = i % Math.min(smoothedLevels.length, 10)
|
||||
|
||||
const rawLevel = smoothedLevels[audioIndex] || 0
|
||||
const scaledLevel = Math.sqrt(Math.min(Math.max(rawLevel, 0), 100) / 100) * 100
|
||||
const normalizedLevel = scaledLevel / 100
|
||||
const audioLevel = Math.max(0.15, normalizedLevel) * 0.5
|
||||
|
||||
const radius = baseRadius * (1.0 + audioLevel)
|
||||
const x = centerX + Math.cos(angle) * radius
|
||||
const y = centerY + Math.sin(angle) * radius
|
||||
points.push({x: x, y: y})
|
||||
const angle = i * angleStep;
|
||||
const audioIndex = i % 10;
|
||||
const rawLevel = smoothedLevels[audioIndex] || 0;
|
||||
const clampedLevel = rawLevel < 0 ? 0 : (rawLevel > 100 ? 100 : rawLevel);
|
||||
const audioLevel = Math.max(0.15, Math.sqrt(clampedLevel * 0.01)) * 0.5;
|
||||
const radius = baseRadius * (1.0 + audioLevel);
|
||||
points[i] = {
|
||||
x: centerX + Math.cos(angle) * radius,
|
||||
y: centerY + Math.sin(angle) * radius
|
||||
};
|
||||
}
|
||||
|
||||
const startMove = shapePath.pathElements[0]
|
||||
startMove.x = points[0].x
|
||||
startMove.y = points[0].y
|
||||
startMove.x = points[0].x;
|
||||
startMove.y = points[0].y;
|
||||
|
||||
const tension = 0.5
|
||||
for (let i = 0; i < segments; i++) {
|
||||
const p0 = points[(i - 1 + segments) % segments]
|
||||
const p1 = points[i]
|
||||
const p2 = points[(i + 1) % segments]
|
||||
const p3 = points[(i + 2) % segments]
|
||||
const p0 = points[(i + segments - 1) % segments];
|
||||
const p1 = points[i];
|
||||
const p2 = points[(i + 1) % segments];
|
||||
const p3 = points[(i + 2) % segments];
|
||||
|
||||
const c1x = p1.x + (p2.x - p0.x) * tension / 3
|
||||
const c1y = p1.y + (p2.y - p0.y) * tension / 3
|
||||
const c2x = p2.x - (p3.x - p1.x) * tension / 3
|
||||
const c2y = p2.y - (p3.y - p1.y) * tension / 3
|
||||
|
||||
const seg = cubics[i]
|
||||
seg.control1X = c1x
|
||||
seg.control1Y = c1y
|
||||
seg.control2X = c2x
|
||||
seg.control2Y = c2y
|
||||
seg.x = p2.x
|
||||
seg.y = p2.y
|
||||
const seg = cubics[i];
|
||||
seg.control1X = p1.x + (p2.x - p0.x) * tension3;
|
||||
seg.control1Y = p1.y + (p2.y - p0.y) * tension3;
|
||||
seg.control2X = p2.x - (p3.x - p1.x) * tension3;
|
||||
seg.control2Y = p2.y - (p3.y - p1.y) * tension3;
|
||||
seg.x = p2.x;
|
||||
seg.y = p2.y;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +154,8 @@ Item {
|
||||
|
||||
onImageSourceChanged: {
|
||||
if (imageSource && imageStatus !== Image.Error) {
|
||||
lastValidArtUrl = imageSource
|
||||
lastValidArtUrl = imageSource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,10 +91,7 @@ Item {
|
||||
setBarContext(pos, bottomGap);
|
||||
}
|
||||
|
||||
readonly property bool useBackgroundWindow: {
|
||||
const layerOverride = Quickshell.env("DMS_POPOUT_LAYER");
|
||||
return !layerOverride || layerOverride === "overlay";
|
||||
}
|
||||
readonly property bool useBackgroundWindow: true
|
||||
|
||||
function open() {
|
||||
if (!screen)
|
||||
@@ -258,13 +255,15 @@ Item {
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_POPOUT_LAYER")) {
|
||||
case "bottom":
|
||||
return WlrLayershell.Bottom;
|
||||
case "top":
|
||||
console.warn("DankPopout: 'bottom' layer is not valid for popouts. Defaulting to 'top' layer.");
|
||||
return WlrLayershell.Top;
|
||||
case "background":
|
||||
return WlrLayershell.Background;
|
||||
default:
|
||||
console.warn("DankPopout: 'background' layer is not valid for popouts. Defaulting to 'top' layer.");
|
||||
return WlrLayershell.Top;
|
||||
case "overlay":
|
||||
return WlrLayershell.Overlay;
|
||||
default:
|
||||
return WlrLayershell.Top;
|
||||
}
|
||||
}
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
|
||||
Reference in New Issue
Block a user