mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-30 00:12:50 -05:00
Compare commits
10 Commits
769f58caa9
...
2947ff4131
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2947ff4131 | ||
|
|
b8fca10896 | ||
|
|
33e45794d2 | ||
|
|
42cc88ca65 | ||
|
|
0b7f2416ca | ||
|
|
5d5c745ee5 | ||
|
|
e0429e4c60 | ||
|
|
0bece5287e | ||
|
|
60b5e47836 | ||
|
|
aa75b44790 |
71
.github/workflows/run-obs.yml
vendored
71
.github/workflows/run-obs.yml
vendored
@@ -7,13 +7,14 @@ on:
|
||||
description: "Package to update (dms, dms-git, or all)"
|
||||
required: false
|
||||
default: "all"
|
||||
tag_version:
|
||||
description: "Specific tag version for dms stable (e.g., v1.0.2). Leave empty to auto-detect latest release."
|
||||
required: false
|
||||
default: ""
|
||||
rebuild_release:
|
||||
description: "Release number for rebuilds (e.g., 2, 3, 4 to increment spec Release)"
|
||||
required: false
|
||||
default: ""
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
schedule:
|
||||
- cron: "0 */3 * * *" # Every 3 hours for dms-git builds
|
||||
|
||||
@@ -97,7 +98,7 @@ jobs:
|
||||
# Rebuild requested - always proceed
|
||||
echo "packages=$PKG" >> $GITHUB_OUTPUT
|
||||
echo "has_updates=true" >> $GITHUB_OUTPUT
|
||||
echo "🔄 Manual rebuild requested: $PKG (ppa$REBUILD)"
|
||||
echo "🔄 Manual rebuild requested: $PKG (db$REBUILD)"
|
||||
|
||||
elif [[ "$PKG" == "all" ]]; then
|
||||
# Check each package and build list of those needing updates
|
||||
@@ -161,16 +162,51 @@ jobs:
|
||||
id: packages
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "push" && "${{ github.ref }}" =~ ^refs/tags/ ]]; then
|
||||
# Tag push event - use the pushed tag
|
||||
echo "packages=dms" >> $GITHUB_OUTPUT
|
||||
VERSION="${GITHUB_REF#refs/tags/}"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Triggered by tag: $VERSION"
|
||||
elif [[ "${{ github.event_name }}" == "schedule" ]]; then
|
||||
# Scheduled run - dms-git only
|
||||
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
|
||||
echo "Triggered by schedule: updating git package"
|
||||
elif [[ -n "${{ github.event.inputs.package }}" ]]; then
|
||||
# Use filtered packages from check-updates when package="all" and no rebuild requested
|
||||
if [[ "${{ github.event.inputs.package }}" == "all" ]] && [[ -z "${{ github.event.inputs.rebuild_release }}" ]]; then
|
||||
# Manual workflow dispatch
|
||||
|
||||
# Determine version for dms stable
|
||||
if [[ "${{ github.event.inputs.package }}" == "dms" ]]; then
|
||||
# For explicit dms selection, require tag_version
|
||||
if [[ -n "${{ github.event.inputs.tag_version }}" ]]; then
|
||||
VERSION="${{ github.event.inputs.tag_version }}"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Using specified tag: $VERSION"
|
||||
else
|
||||
echo "ERROR: tag_version is required when package=dms"
|
||||
echo "Please specify a tag version (e.g., v1.0.2) or use package=all for auto-detection"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "${{ github.event.inputs.package }}" == "all" ]]; then
|
||||
# For "all", auto-detect if tag_version not specified
|
||||
if [[ -n "${{ github.event.inputs.tag_version }}" ]]; then
|
||||
VERSION="${{ github.event.inputs.tag_version }}"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Using specified tag: $VERSION"
|
||||
else
|
||||
# Auto-detect latest release for "all"
|
||||
LATEST_TAG=$(curl -s https://api.github.com/repos/AvengeMedia/DankMaterialShell/releases/latest | grep '"tag_name"' | sed 's/.*"tag_name": "\([^"]*\)".*/\1/' || echo "")
|
||||
if [[ -n "$LATEST_TAG" ]]; then
|
||||
echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT
|
||||
echo "Auto-detected latest release: $LATEST_TAG"
|
||||
else
|
||||
echo "ERROR: Could not auto-detect latest release"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use filtered packages from check-updates when package="all" and no rebuild/tag specified
|
||||
if [[ "${{ github.event.inputs.package }}" == "all" ]] && [[ -z "${{ github.event.inputs.rebuild_release }}" ]] && [[ -z "${{ github.event.inputs.tag_version }}" ]]; then
|
||||
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
|
||||
echo "Manual trigger: all (filtered to: ${{ needs.check-updates.outputs.packages }})"
|
||||
else
|
||||
@@ -186,7 +222,7 @@ jobs:
|
||||
run: |
|
||||
COMMIT_HASH=$(git rev-parse --short=8 HEAD)
|
||||
COMMIT_COUNT=$(git rev-list --count HEAD)
|
||||
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "0.6.2")
|
||||
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "1.0.2")
|
||||
NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}"
|
||||
echo "📦 Updating dms-git.spec to version: $NEW_VERSION"
|
||||
|
||||
@@ -207,14 +243,14 @@ jobs:
|
||||
run: |
|
||||
COMMIT_HASH=$(git rev-parse --short=8 HEAD)
|
||||
COMMIT_COUNT=$(git rev-list --count HEAD)
|
||||
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "0.6.2")
|
||||
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "1.0.2")
|
||||
NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}"
|
||||
echo "📦 Updating Debian dms-git changelog to version: $NEW_VERSION"
|
||||
|
||||
# Single changelog entry (git snapshots don't need history)
|
||||
CHANGELOG_DATE=$(date -R)
|
||||
{
|
||||
echo "dms-git ($NEW_VERSION) nightly; urgency=medium"
|
||||
echo "dms-git (${NEW_VERSION}db1) nightly; urgency=medium"
|
||||
echo ""
|
||||
echo " * Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)"
|
||||
echo ""
|
||||
@@ -226,10 +262,15 @@ jobs:
|
||||
run: |
|
||||
VERSION="${{ steps.packages.outputs.version }}"
|
||||
VERSION_NO_V="${VERSION#v}"
|
||||
echo "Updating packaging to version $VERSION_NO_V"
|
||||
echo "==> Updating packaging files to version: $VERSION_NO_V"
|
||||
|
||||
# Update spec file
|
||||
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec
|
||||
|
||||
# Verify the update
|
||||
UPDATED_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1)
|
||||
echo "✓ Spec file now shows Version: $UPDATED_VERSION"
|
||||
|
||||
# Single changelog entry (full history on OBS website)
|
||||
DATE_STR=$(date "+%a %b %d %Y")
|
||||
LOCAL_SPEC_HEAD=$(sed -n '1,/%changelog/{ /%changelog/d; p }' distro/opensuse/dms.spec)
|
||||
@@ -256,13 +297,13 @@ jobs:
|
||||
if [[ -f "distro/debian/dms/debian/changelog" ]]; then
|
||||
CHANGELOG_DATE=$(date -R)
|
||||
{
|
||||
echo "dms ($VERSION_NO_V) stable; urgency=medium"
|
||||
echo "dms (${VERSION_NO_V}db1) stable; urgency=medium"
|
||||
echo ""
|
||||
echo " * Update to $VERSION stable release"
|
||||
echo ""
|
||||
echo " -- Avenge Media <AvengeMedia.US@gmail.com> $CHANGELOG_DATE"
|
||||
} > "distro/debian/dms/debian/changelog"
|
||||
echo "✓ Updated Debian changelog to $VERSION_NO_V"
|
||||
echo "✓ Updated Debian changelog to ${VERSION_NO_V}db1"
|
||||
fi
|
||||
|
||||
- name: Install Go
|
||||
@@ -289,6 +330,7 @@ jobs:
|
||||
- name: Upload to OBS
|
||||
env:
|
||||
REBUILD_RELEASE: ${{ github.event.inputs.rebuild_release }}
|
||||
TAG_VERSION: ${{ steps.packages.outputs.version }}
|
||||
run: |
|
||||
PACKAGES="${{ steps.packages.outputs.packages }}"
|
||||
|
||||
@@ -300,6 +342,7 @@ jobs:
|
||||
MESSAGE="Automated update from GitHub Actions"
|
||||
if [[ -n "${{ steps.packages.outputs.version }}" ]]; then
|
||||
MESSAGE="Update to ${{ steps.packages.outputs.version }}"
|
||||
echo "==> Version being uploaded: ${{ steps.packages.outputs.version }}"
|
||||
fi
|
||||
|
||||
# PACKAGES can be space-separated list (e.g., "dms-git dms" from "all" check)
|
||||
@@ -309,7 +352,7 @@ jobs:
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "Uploading $PKG to OBS..."
|
||||
if [[ -n "$REBUILD_RELEASE" ]]; then
|
||||
echo "🔄 Using rebuild release number: ppa$REBUILD_RELEASE"
|
||||
echo "🔄 Using rebuild release number: db$REBUILD_RELEASE"
|
||||
fi
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
@@ -350,7 +393,7 @@ jobs:
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
if [[ -n "${{ github.event.inputs.rebuild_release }}" ]]; then
|
||||
echo "**Rebuild Number:** ppa${{ github.event.inputs.rebuild_release }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Rebuild Number:** db${{ github.event.inputs.rebuild_release }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -96,7 +96,7 @@ go.work
|
||||
go.work.sum
|
||||
|
||||
# env file
|
||||
.env
|
||||
.env*
|
||||
|
||||
# Editor/IDE
|
||||
# .idea/
|
||||
|
||||
@@ -220,7 +220,7 @@ func getBaseVersion() string {
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return "0.6.2"
|
||||
return "1.0.2"
|
||||
}
|
||||
|
||||
func startDebugServer() error {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
dms-git (1.0.2+git2528.d336866f) nightly; urgency=medium
|
||||
dms-git (1.0.2+git2528.d336866fdb1) nightly; urgency=medium
|
||||
|
||||
* Git snapshot (commit 2528: d336866f)
|
||||
|
||||
@@ -16,23 +16,6 @@ dms-git (1.0.2+git2518.a783d650) nightly; urgency=medium
|
||||
|
||||
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 15:11:40 +0000
|
||||
|
||||
dms-git (1.0.2+git2510.0f89886c) nightly; urgency=medium
|
||||
|
||||
* Git snapshot (commit 2510: 0f89886c)
|
||||
|
||||
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:46:43 +0000
|
||||
|
||||
dms-git (1.0.2+git2507.b2ac9c6c) nightly; urgency=medium
|
||||
|
||||
* Git snapshot (commit 2507: b2ac9c6c)
|
||||
|
||||
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:18:05 +0000
|
||||
|
||||
dms-git (1.0.2+git2505.82f881af) nightly; urgency=medium
|
||||
|
||||
* Git snapshot (commit 2505: 82f881af)
|
||||
|
||||
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 05:55:03 +0000
|
||||
|
||||
dms-git (1.0.0+git2419.993f14a3) nightly; urgency=medium
|
||||
|
||||
|
||||
@@ -3,19 +3,19 @@
|
||||
<service name="download_url">
|
||||
<param name="protocol">https</param>
|
||||
<param name="host">github.com</param>
|
||||
<param name="path">/AvengeMedia/DankMaterialShell/archive/refs/tags/v1.0.2.tar.gz</param>
|
||||
<param name="path">/AvengeMedia/DankMaterialShell/archive/refs/tags/v1.0.3.tar.gz</param>
|
||||
<param name="filename">dms-source.tar.gz</param>
|
||||
</service>
|
||||
<!-- Download amd64 binary -->
|
||||
<service name="download_url">
|
||||
<param name="protocol">https</param>
|
||||
<param name="host">github.com</param>
|
||||
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.2/dms-distropkg-amd64.gz</param>
|
||||
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.3/dms-distropkg-amd64.gz</param>
|
||||
</service>
|
||||
<!-- Download arm64 binary -->
|
||||
<service name="download_url">
|
||||
<param name="protocol">https</param>
|
||||
<param name="host">github.com</param>
|
||||
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.2/dms-distropkg-arm64.gz</param>
|
||||
<param name="path">/AvengeMedia/DankMaterialShell/releases/download/v1.0.3/dms-distropkg-arm64.gz</param>
|
||||
</service>
|
||||
</services>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
dms (1.0.2ppa6) unstable; urgency=medium
|
||||
dms (1.0.3db1) unstable; urgency=medium
|
||||
|
||||
* Rebuild to fix repository metadata issues
|
||||
* Update to v1.0.3 stable release
|
||||
|
||||
-- Avenge Media <AvengeMedia.US@gmail.com> Mon, 16 Dec 2025 10:00:00 +0000
|
||||
|
||||
dms (1.0.2db1) unstable; urgency=medium
|
||||
|
||||
* Update to v1.0.2 stable release
|
||||
|
||||
-- Avenge Media <AvengeMedia.US@gmail.com> Sat, 13 Dec 2025 06:47:39 +0000
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
%global debug_package %{nil}
|
||||
|
||||
Name: dms
|
||||
Version: 1.0.2
|
||||
Release: 7%{?dist}
|
||||
Version: 1.0.3
|
||||
Release: 1%{?dist}
|
||||
Summary: DankMaterialShell - Material 3 inspired shell for Wayland compositors
|
||||
|
||||
License: MIT
|
||||
@@ -105,6 +105,9 @@ pkill -USR1 -x dms >/dev/null 2>&1 || :
|
||||
%{_datadir}/icons/hicolor/scalable/apps/danklogo.svg
|
||||
|
||||
%changelog
|
||||
* Mon Dec 16 2025 AvengeMedia <maintainer@avengemedia.com> - 1.0.3-1
|
||||
- Update to stable v1.0.3 release
|
||||
|
||||
* Fri Dec 12 2025 AvengeMedia <maintainer@avengemedia.com> - 1.0.2-1
|
||||
- Update to stable v1.0.2 release
|
||||
- Bug fixes and improvements
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
# ./distro/scripts/obs-upload.sh dms "Update to v1.0.2"
|
||||
# ./distro/scripts/obs-upload.sh debian dms
|
||||
# ./distro/scripts/obs-upload.sh opensuse dms-git
|
||||
# ./distro/scripts/obs-upload.sh debian dms-git 2 # Rebuild with ppa2 suffix
|
||||
# ./distro/scripts/obs-upload.sh dms-git --rebuild=2 # Rebuild with ppa2 suffix (flag syntax)
|
||||
# ./distro/scripts/obs-upload.sh debian dms-git 2 # Rebuild with db2 suffix
|
||||
# ./distro/scripts/obs-upload.sh dms-git --rebuild=2 # Rebuild with db2 suffix (flag syntax)
|
||||
|
||||
set -e
|
||||
|
||||
@@ -126,8 +126,8 @@ check_obs_version_exists() {
|
||||
OBS_VERSION=$(echo "$OBS_SPEC" | grep "^Version:" | awk '{print $2}' | xargs)
|
||||
# Commit hash check for -git packages
|
||||
if [[ "$CHECK_MODE" == "commit" ]] && [[ "$PACKAGE" == *"-git" ]]; then
|
||||
OBS_COMMIT=$(echo "$OBS_VERSION" | grep -oP '\.([a-f0-9]{8})(ppa[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "")
|
||||
NEW_COMMIT=$(echo "$VERSION" | grep -oP '\.([a-f0-9]{8})(ppa[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "")
|
||||
OBS_COMMIT=$(echo "$OBS_VERSION" | grep -oP '\.([a-f0-9]{8})(db[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "")
|
||||
NEW_COMMIT=$(echo "$VERSION" | grep -oP '\.([a-f0-9]{8})(db[0-9]+)?$' | grep -oP '[a-f0-9]{8}' || echo "")
|
||||
|
||||
if [[ -n "$OBS_COMMIT" && -n "$NEW_COMMIT" && "$OBS_COMMIT" == "$NEW_COMMIT" ]]; then
|
||||
echo "⚠️ Commit $NEW_COMMIT already exists in OBS (current version: $OBS_VERSION)"
|
||||
@@ -279,7 +279,8 @@ if [[ -d "distro/debian/$PACKAGE/debian" ]]; then
|
||||
|
||||
# Apply rebuild suffix if specified (must happen before API check)
|
||||
if [[ -n "$REBUILD_RELEASE" ]] && [[ -n "$CHANGELOG_VERSION" ]]; then
|
||||
CHANGELOG_VERSION="${CHANGELOG_VERSION}ppa${REBUILD_RELEASE}"
|
||||
BASE_VERSION=$(echo "$CHANGELOG_VERSION" | sed 's/db[0-9]*$//')
|
||||
CHANGELOG_VERSION="${BASE_VERSION}db${REBUILD_RELEASE}"
|
||||
echo " - Applied rebuild suffix: $CHANGELOG_VERSION"
|
||||
fi
|
||||
|
||||
@@ -307,12 +308,16 @@ if [[ -d "distro/debian/$PACKAGE/debian" ]]; then
|
||||
else
|
||||
# Rebuild number specified - check if this exact version already exists (exact mode)
|
||||
if check_obs_version_exists "$OBS_PROJECT" "$PACKAGE" "$CHANGELOG_VERSION" "exact"; then
|
||||
echo "==> Error: Version $CHANGELOG_VERSION already exists in OBS"
|
||||
echo " This exact version (including ppa${REBUILD_RELEASE}) is already uploaded."
|
||||
echo " To rebuild with a different release number, try incrementing:"
|
||||
echo "==> Version $CHANGELOG_VERSION already exists in OBS"
|
||||
echo " This exact version (including db${REBUILD_RELEASE}) is already uploaded."
|
||||
echo " Skipping upload - nothing to do."
|
||||
echo ""
|
||||
echo " 💡 To rebuild with a different release number, try incrementing:"
|
||||
NEXT_NUM=$((REBUILD_RELEASE + 1))
|
||||
echo " ./distro/scripts/obs-upload.sh $PACKAGE $NEXT_NUM"
|
||||
exit 1
|
||||
echo " REBUILD_RELEASE=$NEXT_NUM"
|
||||
echo ""
|
||||
echo "✓ Exiting gracefully (no changes needed)"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -511,7 +516,7 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
|
||||
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"
|
||||
echo "==> Downloading source from: $SOURCE_URL"
|
||||
|
||||
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
|
||||
@@ -534,9 +539,17 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
fi
|
||||
SOURCE_DIR=$(cd "$SOURCE_DIR" && pwd)
|
||||
cd "$REPO_ROOT"
|
||||
if [[ "$(pwd)" != "$REPO_ROOT" ]]; then
|
||||
echo "ERROR: Failed to return to REPO_ROOT. Expected: $REPO_ROOT, Got: $(pwd)"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Error: Failed to download source from $SOURCE_URL"
|
||||
echo "Tried both wget and curl. Please check the URL and network connectivity."
|
||||
echo "ERROR: Failed to download source from $SOURCE_URL"
|
||||
echo "Attempted both wget and curl"
|
||||
echo "Please check:"
|
||||
echo " 1. URL is accessible: $SOURCE_URL"
|
||||
echo " 2. _service file has correct version"
|
||||
echo " 3. GitHub releases are available"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
@@ -553,7 +566,7 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " Found source directory: $SOURCE_DIR"
|
||||
echo "==> Found source directory: $SOURCE_DIR"
|
||||
|
||||
# Vendor Go dependencies for dms-git
|
||||
if [[ "$PACKAGE" == "dms-git" ]] && [[ -d "$SOURCE_DIR/core" ]]; then
|
||||
@@ -712,6 +725,10 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
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 "$REPO_ROOT"
|
||||
if [[ "$(pwd)" != "$REPO_ROOT" ]]; then
|
||||
echo "ERROR: Failed to return to REPO_ROOT after tarball creation"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$PACKAGE" == "dms" ]]; then
|
||||
TARBALL_DIR=$(tar -tzf "$WORK_DIR/$COMBINED_TARBALL" 2>/dev/null | head -1 | cut -d'/' -f1)
|
||||
@@ -723,6 +740,10 @@ if [[ "$UPLOAD_DEBIAN" == true ]] && [[ -d "distro/debian/$PACKAGE/debian" ]]; t
|
||||
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"
|
||||
if [[ "$(pwd)" != "$REPO_ROOT" ]]; then
|
||||
echo "ERROR: Failed to return to REPO_ROOT after tarball recreation"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -796,23 +817,29 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "$WORK_DIR"
|
||||
echo "==> Ensuring we're in the OSC working directory"
|
||||
cd "$WORK_DIR" || {
|
||||
echo "ERROR: Cannot cd to WORK_DIR: $WORK_DIR"
|
||||
echo "DEBUG: Current directory: $(pwd)"
|
||||
echo "DEBUG: WORK_DIR exists: $(test -d "$WORK_DIR" && echo "yes" || echo "no")"
|
||||
exit 1
|
||||
}
|
||||
echo "DEBUG: Successfully entered WORK_DIR: $(pwd)"
|
||||
|
||||
# Server-side cleanup via API
|
||||
echo "==> Cleaning old tarballs from OBS server (prevents downloading 100+ old versions)"
|
||||
OBS_FILES=$(osc api "/source/$OBS_PROJECT/$PACKAGE" 2>/dev/null || echo "")
|
||||
if [[ -n "$OBS_FILES" ]]; then
|
||||
DELETED_COUNT=0
|
||||
KEEP_PATTERN=""
|
||||
KEEP_CURRENT=""
|
||||
if [[ -n "$CHANGELOG_VERSION" ]]; then
|
||||
BASE_KEEP_VERSION=$(echo "$CHANGELOG_VERSION" | sed 's/ppa[0-9]*$//')
|
||||
KEEP_PATTERN="${PACKAGE}_${BASE_KEEP_VERSION}"
|
||||
echo " Keeping tarballs matching: ${KEEP_PATTERN}*"
|
||||
KEEP_CURRENT="${PACKAGE}_${CHANGELOG_VERSION}.tar.gz"
|
||||
echo " Keeping only current version: ${KEEP_CURRENT}"
|
||||
fi
|
||||
|
||||
for old_file in $(echo "$OBS_FILES" | grep -oP '(?<=name=")[^"]*\.(tar\.gz|tar\.xz|tar\.bz2)(?=")' || true); do
|
||||
if [[ -n "$KEEP_PATTERN" ]] && [[ "$old_file" == ${KEEP_PATTERN}* ]]; then
|
||||
echo " - Keeping current version: $old_file"
|
||||
if [[ "$old_file" == "$KEEP_CURRENT" ]]; then
|
||||
echo " - Keeping: $old_file"
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -835,14 +862,11 @@ else
|
||||
echo " ⚠️ Could not fetch file list from server, skipping cleanup"
|
||||
fi
|
||||
|
||||
# Fallback update with --server-side-source-service-files flag only syncs metadata (spec, dsc, _service)
|
||||
# Update working copy to latest revision (without expanding service files to avoid revision conflicts)
|
||||
echo "==> Updating working copy"
|
||||
if ! osc up --server-side-source-service-files 2>/dev/null; then
|
||||
echo " Note: Using regular update (--server-side-source-service-files not supported)"
|
||||
if ! osc up; then
|
||||
echo "Error: Failed to update working copy"
|
||||
exit 1
|
||||
fi
|
||||
if ! osc up 2>/dev/null; then
|
||||
echo "Error: Failed to update working copy"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Ensure we're in WORK_DIR and it exists
|
||||
@@ -882,6 +906,15 @@ elif [[ "$UPLOAD_OPENSUSE" == true ]]; then
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [[ "$(pwd)" != "$WORK_DIR" ]]; then
|
||||
echo "ERROR: Lost directory context. Expected: $WORK_DIR, Got: $(pwd)"
|
||||
cd "$WORK_DIR" || {
|
||||
echo "FATAL: Cannot recover - unable to cd to WORK_DIR"
|
||||
exit 1
|
||||
}
|
||||
echo "WARNING: Recovered directory context"
|
||||
fi
|
||||
|
||||
osc addremove 2>&1 | grep -v "Git SCM package" || true
|
||||
|
||||
SOURCE_TARBALL="${PACKAGE}-source.tar.gz"
|
||||
@@ -908,7 +941,7 @@ if ! osc status 2>/dev/null | grep -qE '^[MAD]|^[?]'; then
|
||||
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"
|
||||
osc commit --skip-local-service-run -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
|
||||
|
||||
@@ -19,9 +19,10 @@ Item {
|
||||
property bool longPressing: false
|
||||
property bool dragging: false
|
||||
property point dragStartPos: Qt.point(0, 0)
|
||||
property point dragOffset: Qt.point(0, 0)
|
||||
property real dragAxisOffset: 0
|
||||
property int targetIndex: -1
|
||||
property int originalIndex: -1
|
||||
property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
property bool showWindowTitle: false
|
||||
property string windowTitle: ""
|
||||
property bool isHovered: mouseArea.containsMouse && !dragging
|
||||
@@ -95,7 +96,7 @@ Item {
|
||||
return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || [];
|
||||
}
|
||||
onIsHoveredChanged: {
|
||||
if (mouseArea.pressed)
|
||||
if (mouseArea.pressed || dragging)
|
||||
return;
|
||||
if (isHovered) {
|
||||
exitAnimation.stop();
|
||||
@@ -128,8 +129,8 @@ Item {
|
||||
running: false
|
||||
|
||||
NumberAnimation {
|
||||
target: iconTransform
|
||||
property: animateX ? "x" : "y"
|
||||
target: root
|
||||
property: "hoverAnimOffset"
|
||||
to: animationDirection * animationDistance * 0.25
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
@@ -137,8 +138,8 @@ Item {
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: iconTransform
|
||||
property: animateX ? "x" : "y"
|
||||
target: root
|
||||
property: "hoverAnimOffset"
|
||||
to: animationDirection * animationDistance * 0.2
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
@@ -150,8 +151,8 @@ Item {
|
||||
id: exitAnimation
|
||||
|
||||
running: false
|
||||
target: iconTransform
|
||||
property: animateX ? "x" : "y"
|
||||
target: root
|
||||
property: "hoverAnimOffset"
|
||||
to: 0
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
@@ -187,16 +188,79 @@ Item {
|
||||
}
|
||||
onReleased: mouse => {
|
||||
longPressTimer.stop();
|
||||
if (longPressing) {
|
||||
if (dragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps) {
|
||||
dockApps.movePinnedApp(originalIndex, targetIndex);
|
||||
}
|
||||
|
||||
longPressing = false;
|
||||
dragging = false;
|
||||
dragOffset = Qt.point(0, 0);
|
||||
targetIndex = -1;
|
||||
originalIndex = -1;
|
||||
const wasDragging = dragging;
|
||||
const didReorder = wasDragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps;
|
||||
|
||||
if (didReorder)
|
||||
dockApps.movePinnedApp(originalIndex, targetIndex);
|
||||
|
||||
longPressing = false;
|
||||
dragging = false;
|
||||
dragAxisOffset = 0;
|
||||
targetIndex = -1;
|
||||
originalIndex = -1;
|
||||
|
||||
if (dockApps && !didReorder) {
|
||||
dockApps.draggedIndex = -1;
|
||||
dockApps.dropTargetIndex = -1;
|
||||
}
|
||||
|
||||
if (wasDragging || mouse.button !== Qt.LeftButton)
|
||||
return;
|
||||
|
||||
handleLeftClick();
|
||||
}
|
||||
|
||||
function handleLeftClick() {
|
||||
if (!appData)
|
||||
return;
|
||||
|
||||
switch (appData.type) {
|
||||
case "pinned":
|
||||
if (!appData.appId)
|
||||
return;
|
||||
const pinnedEntry = cachedDesktopEntry;
|
||||
if (pinnedEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": pinnedEntry.name || appData.appId,
|
||||
"icon": pinnedEntry.icon || "",
|
||||
"exec": pinnedEntry.exec || "",
|
||||
"comment": pinnedEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(pinnedEntry);
|
||||
break;
|
||||
case "window":
|
||||
const windowToplevel = getToplevelObject();
|
||||
if (windowToplevel)
|
||||
windowToplevel.activate();
|
||||
break;
|
||||
case "grouped":
|
||||
if (appData.windowCount === 0) {
|
||||
if (!appData.appId)
|
||||
return;
|
||||
const groupedEntry = cachedDesktopEntry;
|
||||
if (groupedEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": groupedEntry.name || appData.appId,
|
||||
"icon": groupedEntry.icon || "",
|
||||
"exec": groupedEntry.exec || "",
|
||||
"comment": groupedEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(groupedEntry);
|
||||
} else if (appData.windowCount === 1) {
|
||||
const groupedToplevel = getToplevelObject();
|
||||
if (groupedToplevel)
|
||||
groupedToplevel.activate();
|
||||
} else if (contextMenu) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
onPositionChanged: mouse => {
|
||||
@@ -206,90 +270,47 @@ Item {
|
||||
dragging = true;
|
||||
targetIndex = index;
|
||||
originalIndex = index;
|
||||
if (dockApps) {
|
||||
dockApps.draggedIndex = index;
|
||||
dockApps.dropTargetIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dragging) {
|
||||
dragOffset = Qt.point(mouse.x - dragStartPos.x, mouse.y - dragStartPos.y);
|
||||
if (dockApps) {
|
||||
const threshold = actualIconSize;
|
||||
let newTargetIndex = targetIndex;
|
||||
if (dragOffset.x > threshold && targetIndex < dockApps.pinnedAppCount - 1) {
|
||||
newTargetIndex = targetIndex + 1;
|
||||
} else if (dragOffset.x < -threshold && targetIndex > 0) {
|
||||
newTargetIndex = targetIndex - 1;
|
||||
}
|
||||
if (newTargetIndex !== targetIndex) {
|
||||
targetIndex = newTargetIndex;
|
||||
dragStartPos = Qt.point(mouse.x, mouse.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dragging || !dockApps)
|
||||
return;
|
||||
|
||||
const axisOffset = isVertical ? (mouse.y - dragStartPos.y) : (mouse.x - dragStartPos.x);
|
||||
dragAxisOffset = axisOffset;
|
||||
|
||||
const spacing = Math.min(8, Math.max(4, actualIconSize * 0.08));
|
||||
const itemSize = actualIconSize * 1.2 + spacing;
|
||||
const slotOffset = Math.round(axisOffset / itemSize);
|
||||
const newTargetIndex = Math.max(0, Math.min(dockApps.pinnedAppCount - 1, originalIndex + slotOffset));
|
||||
|
||||
if (newTargetIndex !== targetIndex) {
|
||||
targetIndex = newTargetIndex;
|
||||
dockApps.dropTargetIndex = newTargetIndex;
|
||||
}
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (!appData || longPressing) {
|
||||
if (!appData)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (appData.type === "pinned") {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry;
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry);
|
||||
}
|
||||
} else if (appData.type === "window") {
|
||||
const toplevel = getToplevelObject();
|
||||
if (toplevel) {
|
||||
toplevel.activate();
|
||||
}
|
||||
} else if (appData.type === "grouped") {
|
||||
if (appData.windowCount === 0) {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry;
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry);
|
||||
}
|
||||
} else if (appData.windowCount === 1) {
|
||||
// For single window, activate directly
|
||||
const toplevel = getToplevelObject();
|
||||
if (toplevel) {
|
||||
console.log("Activating grouped app window:", appData.windowTitle);
|
||||
toplevel.activate();
|
||||
} else {
|
||||
console.warn("No toplevel found for grouped app");
|
||||
}
|
||||
} else {
|
||||
if (contextMenu) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
if (appData?.type === "window") {
|
||||
appData?.toplevel?.close();
|
||||
} else if (appData?.type === "grouped") {
|
||||
if (mouse.button === Qt.MiddleButton) {
|
||||
switch (appData.type) {
|
||||
case "window":
|
||||
appData.toplevel?.close();
|
||||
break;
|
||||
case "grouped":
|
||||
if (contextMenu) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
}
|
||||
} else if (appData && appData.appId) {
|
||||
break;
|
||||
default:
|
||||
if (!appData.appId)
|
||||
return;
|
||||
const desktopEntry = cachedDesktopEntry;
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
@@ -301,26 +322,39 @@ Item {
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry);
|
||||
break;
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (contextMenu && appData) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
} else {
|
||||
console.warn("No context menu or appData available");
|
||||
}
|
||||
if (!contextMenu)
|
||||
return;
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property real hoverAnimOffset: 0
|
||||
|
||||
Item {
|
||||
id: visualContent
|
||||
anchors.fill: parent
|
||||
|
||||
transform: Translate {
|
||||
id: iconTransform
|
||||
x: 0
|
||||
y: 0
|
||||
x: {
|
||||
if (dragging && !isVertical)
|
||||
return dragAxisOffset;
|
||||
if (!dragging && isVertical)
|
||||
return hoverAnimOffset;
|
||||
return 0;
|
||||
}
|
||||
y: {
|
||||
if (dragging && isVertical)
|
||||
return dragAxisOffset;
|
||||
if (!dragging && !isVertical)
|
||||
return hoverAnimOffset;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -17,6 +14,9 @@ Item {
|
||||
property bool isVertical: false
|
||||
property var dockScreen: null
|
||||
property real iconSize: 40
|
||||
property int draggedIndex: -1
|
||||
property int dropTargetIndex: -1
|
||||
property bool suppressShiftAnimation: false
|
||||
|
||||
clip: false
|
||||
implicitWidth: isVertical ? appLayout.height : appLayout.width
|
||||
@@ -24,18 +24,18 @@ Item {
|
||||
|
||||
function movePinnedApp(fromIndex, toIndex) {
|
||||
if (fromIndex === toIndex) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPinned = [...(SessionData.pinnedApps || [])]
|
||||
const currentPinned = [...(SessionData.pinnedApps || [])];
|
||||
if (fromIndex < 0 || fromIndex >= currentPinned.length || toIndex < 0 || toIndex >= currentPinned.length) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const movedApp = currentPinned.splice(fromIndex, 1)[0]
|
||||
currentPinned.splice(toIndex, 0, movedApp)
|
||||
const movedApp = currentPinned.splice(fromIndex, 1)[0];
|
||||
currentPinned.splice(toIndex, 0, movedApp);
|
||||
|
||||
SessionData.setPinnedApps(currentPinned)
|
||||
SessionData.setPinnedApps(currentPinned);
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -53,202 +53,250 @@ Item {
|
||||
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
spacing: Math.min(8, Math.max(4, root.iconSize * 0.08))
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
property var dockItems: []
|
||||
property var dockItems: []
|
||||
|
||||
model: ScriptModel {
|
||||
values: repeater.dockItems
|
||||
objectProp: "uniqueKey"
|
||||
}
|
||||
model: ScriptModel {
|
||||
values: repeater.dockItems
|
||||
objectProp: "uniqueKey"
|
||||
}
|
||||
|
||||
Component.onCompleted: updateModel()
|
||||
Component.onCompleted: updateModel()
|
||||
|
||||
function updateModel() {
|
||||
const items = []
|
||||
const pinnedApps = [...(SessionData.pinnedApps || [])]
|
||||
const sortedToplevels = CompositorService.sortedToplevels
|
||||
function updateModel() {
|
||||
const items = [];
|
||||
const pinnedApps = [...(SessionData.pinnedApps || [])];
|
||||
const sortedToplevels = CompositorService.sortedToplevels;
|
||||
|
||||
if (root.groupByApp) {
|
||||
const appGroups = new Map()
|
||||
if (root.groupByApp) {
|
||||
const appGroups = new Map();
|
||||
|
||||
pinnedApps.forEach(rawAppId => {
|
||||
const appId = Paths.moddedAppId(rawAppId)
|
||||
appGroups.set(appId, {
|
||||
appId: appId,
|
||||
isPinned: true,
|
||||
windows: []
|
||||
})
|
||||
})
|
||||
|
||||
sortedToplevels.forEach((toplevel, index) => {
|
||||
const rawAppId = toplevel.appId || "unknown"
|
||||
const appId = Paths.moddedAppId(rawAppId)
|
||||
if (!appGroups.has(appId)) {
|
||||
pinnedApps.forEach(rawAppId => {
|
||||
const appId = Paths.moddedAppId(rawAppId);
|
||||
appGroups.set(appId, {
|
||||
appId: appId,
|
||||
isPinned: false,
|
||||
isPinned: true,
|
||||
windows: []
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
sortedToplevels.forEach((toplevel, index) => {
|
||||
const rawAppId = toplevel.appId || "unknown";
|
||||
const appId = Paths.moddedAppId(rawAppId);
|
||||
if (!appGroups.has(appId)) {
|
||||
appGroups.set(appId, {
|
||||
appId: appId,
|
||||
isPinned: false,
|
||||
windows: []
|
||||
});
|
||||
}
|
||||
|
||||
appGroups.get(appId).windows.push({
|
||||
toplevel: toplevel,
|
||||
index: index
|
||||
});
|
||||
});
|
||||
|
||||
const pinnedGroups = [];
|
||||
const unpinnedGroups = [];
|
||||
|
||||
Array.from(appGroups.entries()).forEach(([appId, group]) => {
|
||||
const firstWindow = group.windows.length > 0 ? group.windows[0] : null;
|
||||
|
||||
const item = {
|
||||
uniqueKey: "grouped_" + appId,
|
||||
type: "grouped",
|
||||
appId: appId,
|
||||
toplevel: firstWindow ? firstWindow.toplevel : null,
|
||||
isPinned: group.isPinned,
|
||||
isRunning: group.windows.length > 0,
|
||||
windowCount: group.windows.length,
|
||||
allWindows: group.windows
|
||||
};
|
||||
|
||||
if (group.isPinned) {
|
||||
pinnedGroups.push(item);
|
||||
} else {
|
||||
unpinnedGroups.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
pinnedGroups.forEach(item => items.push(item));
|
||||
|
||||
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
|
||||
items.push({
|
||||
uniqueKey: "separator_grouped",
|
||||
type: "separator",
|
||||
appId: "__SEPARATOR__",
|
||||
toplevel: null,
|
||||
isPinned: false,
|
||||
isRunning: false
|
||||
});
|
||||
}
|
||||
|
||||
appGroups.get(appId).windows.push({
|
||||
toplevel: toplevel,
|
||||
index: index
|
||||
})
|
||||
})
|
||||
unpinnedGroups.forEach(item => items.push(item));
|
||||
root.pinnedAppCount = pinnedGroups.length;
|
||||
} else {
|
||||
pinnedApps.forEach(rawAppId => {
|
||||
const appId = Paths.moddedAppId(rawAppId);
|
||||
items.push({
|
||||
uniqueKey: "pinned_" + appId,
|
||||
type: "pinned",
|
||||
appId: appId,
|
||||
toplevel: null,
|
||||
isPinned: true,
|
||||
isRunning: false
|
||||
});
|
||||
});
|
||||
|
||||
const pinnedGroups = []
|
||||
const unpinnedGroups = []
|
||||
root.pinnedAppCount = pinnedApps.length;
|
||||
|
||||
Array.from(appGroups.entries()).forEach(([appId, group]) => {
|
||||
const firstWindow = group.windows.length > 0 ? group.windows[0] : null
|
||||
|
||||
const item = {
|
||||
uniqueKey: "grouped_" + appId,
|
||||
type: "grouped",
|
||||
appId: appId,
|
||||
toplevel: firstWindow ? firstWindow.toplevel : null,
|
||||
isPinned: group.isPinned,
|
||||
isRunning: group.windows.length > 0,
|
||||
windowCount: group.windows.length,
|
||||
allWindows: group.windows
|
||||
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
|
||||
items.push({
|
||||
uniqueKey: "separator_ungrouped",
|
||||
type: "separator",
|
||||
appId: "__SEPARATOR__",
|
||||
toplevel: null,
|
||||
isPinned: false,
|
||||
isRunning: false
|
||||
});
|
||||
}
|
||||
|
||||
if (group.isPinned) {
|
||||
pinnedGroups.push(item)
|
||||
} else {
|
||||
unpinnedGroups.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
pinnedGroups.forEach(item => items.push(item))
|
||||
|
||||
if (pinnedGroups.length > 0 && unpinnedGroups.length > 0) {
|
||||
items.push({
|
||||
uniqueKey: "separator_grouped",
|
||||
type: "separator",
|
||||
appId: "__SEPARATOR__",
|
||||
toplevel: null,
|
||||
isPinned: false,
|
||||
isRunning: false
|
||||
})
|
||||
}
|
||||
|
||||
unpinnedGroups.forEach(item => items.push(item))
|
||||
root.pinnedAppCount = pinnedGroups.length
|
||||
} else {
|
||||
pinnedApps.forEach(rawAppId => {
|
||||
const appId = Paths.moddedAppId(rawAppId)
|
||||
items.push({
|
||||
uniqueKey: "pinned_" + appId,
|
||||
type: "pinned",
|
||||
appId: appId,
|
||||
toplevel: null,
|
||||
isPinned: true,
|
||||
isRunning: false
|
||||
})
|
||||
})
|
||||
|
||||
root.pinnedAppCount = pinnedApps.length
|
||||
|
||||
if (pinnedApps.length > 0 && sortedToplevels.length > 0) {
|
||||
items.push({
|
||||
uniqueKey: "separator_ungrouped",
|
||||
type: "separator",
|
||||
appId: "__SEPARATOR__",
|
||||
toplevel: null,
|
||||
isPinned: false,
|
||||
isRunning: false
|
||||
})
|
||||
}
|
||||
|
||||
sortedToplevels.forEach((toplevel, index) => {
|
||||
let uniqueKey = "window_" + index
|
||||
if (CompositorService.isHyprland && Hyprland.toplevels) {
|
||||
const hyprlandToplevels = Array.from(Hyprland.toplevels.values)
|
||||
for (let i = 0; i < hyprlandToplevels.length; i++) {
|
||||
if (hyprlandToplevels[i].wayland === toplevel) {
|
||||
uniqueKey = "window_" + hyprlandToplevels[i].address
|
||||
break
|
||||
sortedToplevels.forEach((toplevel, index) => {
|
||||
let uniqueKey = "window_" + index;
|
||||
if (CompositorService.isHyprland && Hyprland.toplevels) {
|
||||
const hyprlandToplevels = Array.from(Hyprland.toplevels.values);
|
||||
for (let i = 0; i < hyprlandToplevels.length; i++) {
|
||||
if (hyprlandToplevels[i].wayland === toplevel) {
|
||||
uniqueKey = "window_" + hyprlandToplevels[i].address;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
uniqueKey: uniqueKey,
|
||||
type: "window",
|
||||
appId: Paths.moddedAppId(toplevel.appId),
|
||||
toplevel: toplevel,
|
||||
isPinned: false,
|
||||
isRunning: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
dockItems = items;
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
property alias dockButton: button
|
||||
property var itemData: modelData
|
||||
clip: false
|
||||
z: button.dragging ? 100 : 0
|
||||
|
||||
width: itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)
|
||||
height: itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)
|
||||
|
||||
property real shiftOffset: {
|
||||
if (root.draggedIndex < 0 || !itemData.isPinned || itemData.type === "separator")
|
||||
return 0;
|
||||
if (model.index === root.draggedIndex)
|
||||
return 0;
|
||||
|
||||
const dragIdx = root.draggedIndex;
|
||||
const dropIdx = root.dropTargetIndex;
|
||||
const myIdx = model.index;
|
||||
const shiftAmount = root.iconSize * 1.2 + layoutFlow.spacing;
|
||||
|
||||
if (dropIdx < 0)
|
||||
return 0;
|
||||
if (dragIdx < dropIdx && myIdx > dragIdx && myIdx <= dropIdx)
|
||||
return -shiftAmount;
|
||||
if (dragIdx > dropIdx && myIdx >= dropIdx && myIdx < dragIdx)
|
||||
return shiftAmount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
x: root.isVertical ? 0 : delegateItem.shiftOffset
|
||||
y: root.isVertical ? delegateItem.shiftOffset : 0
|
||||
|
||||
Behavior on x {
|
||||
enabled: !root.suppressShiftAnimation
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
uniqueKey: uniqueKey,
|
||||
type: "window",
|
||||
appId: Paths.moddedAppId(toplevel.appId),
|
||||
toplevel: toplevel,
|
||||
isPinned: false,
|
||||
isRunning: true
|
||||
})
|
||||
})
|
||||
}
|
||||
Behavior on y {
|
||||
enabled: !root.suppressShiftAnimation
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dockItems = items
|
||||
}
|
||||
Rectangle {
|
||||
visible: itemData.type === "separator"
|
||||
width: root.isVertical ? root.iconSize * 0.5 : 2
|
||||
height: root.isVertical ? 2 : root.iconSize * 0.5
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
radius: 1
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: delegateItem
|
||||
property alias dockButton: button
|
||||
property var itemData: modelData
|
||||
clip: false
|
||||
DockAppButton {
|
||||
id: button
|
||||
visible: itemData.type !== "separator"
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: itemData.type === "separator" ? (root.isVertical ? root.iconSize : 8) : (root.isVertical ? root.iconSize : root.iconSize * 1.2)
|
||||
height: itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)
|
||||
width: delegateItem.width
|
||||
height: delegateItem.height
|
||||
actualIconSize: root.iconSize
|
||||
|
||||
Rectangle {
|
||||
visible: itemData.type === "separator"
|
||||
width: root.isVertical ? root.iconSize * 0.5 : 2
|
||||
height: root.isVertical ? 2 : root.iconSize * 0.5
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
radius: 1
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
appData: itemData
|
||||
contextMenu: root.contextMenu
|
||||
dockApps: root
|
||||
index: model.index
|
||||
parentDockScreen: root.dockScreen
|
||||
|
||||
DockAppButton {
|
||||
id: button
|
||||
visible: itemData.type !== "separator"
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: delegateItem.width
|
||||
height: delegateItem.height
|
||||
actualIconSize: root.iconSize
|
||||
|
||||
appData: itemData
|
||||
contextMenu: root.contextMenu
|
||||
dockApps: root
|
||||
index: model.index
|
||||
parentDockScreen: root.dockScreen
|
||||
|
||||
showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped"
|
||||
windowTitle: {
|
||||
const title = itemData?.toplevel?.title || "(Unnamed)"
|
||||
return title.length > 50 ? title.substring(0, 47) + "..." : title
|
||||
showWindowTitle: itemData?.type === "window" || itemData?.type === "grouped"
|
||||
windowTitle: {
|
||||
const title = itemData?.toplevel?.title || "(Unnamed)";
|
||||
return title.length > 50 ? title.substring(0, 47) + "..." : title;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
function onToplevelsChanged() {
|
||||
repeater.updateModel()
|
||||
repeater.updateModel();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: SessionData
|
||||
function onPinnedAppsChanged() {
|
||||
repeater.updateModel()
|
||||
root.suppressShiftAnimation = true;
|
||||
root.draggedIndex = -1;
|
||||
root.dropTargetIndex = -1;
|
||||
repeater.updateModel();
|
||||
Qt.callLater(() => {
|
||||
root.suppressShiftAnimation = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onGroupByAppChanged: {
|
||||
repeater.updateModel()
|
||||
repeater.updateModel();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user