UI: implement Windows 11 Mica background effect #76
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build QuickRotate | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'version.h' | |
| - 'QuickRotate.cpp' | |
| - 'QuickRotate.rc' | |
| - 'assets/icon.ico' | |
| workflow_dispatch: | |
| inputs: | |
| make_release: | |
| description: 'Create a Release?' | |
| required: true | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-and-release: | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout Code | |
| uses: actions/checkout@v7 | |
| - name: Set up MSYS2 | |
| uses: msys2/setup-msys2@v2 | |
| with: | |
| msystem: MINGW32 | |
| install: mingw-w64-i686-gcc | |
| update: true | |
| - name: Compile Resources & Executables | |
| shell: msys2 {0} | |
| run: | | |
| windres QuickRotate.rc -O coff -o QuickRotate_res.o | |
| g++ QuickRotate.cpp QuickRotate_res.o -o QuickRotate.exe -static -nostartfiles -e _WinMain@16 -Os -s -fno-exceptions -fno-rtti -fno-stack-protector -fomit-frame-pointer "-Wl,--gc-sections" -lgdi32 -luser32 -lgdiplus -lshell32 -lole32 -luuid -ladvapi32 -mwindows | |
| windres -DLITE QuickRotate.rc -O coff -o QuickRotate_lite_res.o | |
| g++ -DLITE QuickRotate.cpp QuickRotate_lite_res.o -o QuickRotate_L.exe -static -nostartfiles -e _WinMain@16 -Os -s -fno-exceptions -fno-rtti -fno-stack-protector -fno-unwind-tables -fno-asynchronous-unwind-tables -fomit-frame-pointer "-Wl,--gc-sections" -lgdi32 -luser32 -lgdiplus -lshell32 -lole32 -luuid -ladvapi32 -mwindows | |
| - name: Compress Lite Build with UPX | |
| shell: pwsh | |
| run: | | |
| choco install upx --no-progress | |
| upx --best --lzma -o QuickRotate_Lite.exe QuickRotate_L.exe | |
| Remove-Item QuickRotate_L.exe -Force | |
| - name: Restore Signing Certificate | |
| shell: pwsh | |
| env: | |
| CERT_BASE64: ${{ secrets.SIGNING_CERT }} | |
| run: | | |
| $certBytes = [System.Convert]::FromBase64String($env:CERT_BASE64) | |
| [System.IO.File]::WriteAllBytes("certificate.pfx", $certBytes) | |
| - name: Sign QuickRotate (Full Build Only) | |
| shell: pwsh | |
| env: | |
| CERT_PASS: ${{ secrets.SIGNING_PASS }} | |
| run: | | |
| $signtool = Get-ChildItem -Path "C:\Program Files (x86)\Windows Kits" -Recurse -Filter "signtool.exe" | Select-Object -First 1 | |
| if (-not $signtool) { Write-Error "Signtool not found!"; exit 1 } | |
| & $signtool.FullName sign /f "certificate.pfx" /p "$env:CERT_PASS" /fd SHA256 /d "Quick Rotate by ArKT-7" /du "https://github.com/ArKT-7" /tr http://timestamp.digicert.com /td sha256 "QuickRotate.exe" | |
| Remove-Item "certificate.pfx" -Force | |
| - name: VirusTotal Scan | |
| id: vt | |
| uses: crazy-max/ghaction-virustotal@v5 | |
| with: | |
| vt_api_key: ${{ secrets.VT_API_KEY }} | |
| files: | | |
| QuickRotate.exe | |
| QuickRotate_Lite.exe | |
| - name: Get Version & Date | |
| id: info | |
| shell: pwsh | |
| run: | | |
| $verLine = Get-Content version.h | Select-String "VERSION_STR" | Select-Object -First 1 | |
| $version = $verLine.ToString().Split('"')[1] | |
| echo "APP_VERSION=$version" >> $env:GITHUB_ENV | |
| $date = (Get-Date).ToUniversalTime().ToString("d MMMM yyyy") | |
| $time = (Get-Date).ToUniversalTime().ToString("HH:mm 'UTC'") | |
| echo "BUILD_DATE=$date" >> $env:GITHUB_ENV | |
| echo "BUILD_TIME=$time" >> $env:GITHUB_ENV | |
| - name: Upload Build Artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: QuickRotate-${{ env.APP_VERSION }} | |
| path: | | |
| QuickRotate.exe | |
| QuickRotate_Lite.exe | |
| retention-days: 7 | |
| - name: Generate Release Notes | |
| if: (github.event_name == 'push' && contains(github.event.head_commit.message, '[release]')) || (github.event_name == 'workflow_dispatch' && inputs.make_release == true) | |
| shell: pwsh | |
| run: | | |
| $repo = "${{ github.repository }}" | |
| $ver = "${{ env.APP_VERSION }}" | |
| $file_full = "QuickRotate.exe" | |
| $file_lite = "QuickRotate_Lite.exe" | |
| $sizeBytes = (Get-Item $file_full).Length | |
| $sizeKB = "{0:N2} KB" -f ($sizeBytes / 1KB) | |
| $sizeBytes_lite = (Get-Item $file_lite).Length | |
| $sizeKB_lite = "{0:N2} KB" -f ($sizeBytes_lite / 1KB) | |
| $md5_full = (Get-FileHash $file_full -Algorithm MD5).Hash | |
| $sha1_full = (Get-FileHash $file_full -Algorithm SHA1).Hash | |
| $sha256_full = (Get-FileHash $file_full -Algorithm SHA256).Hash | |
| $md5_lite = (Get-FileHash $file_lite -Algorithm MD5).Hash | |
| $sha1_lite = (Get-FileHash $file_lite -Algorithm SHA1).Hash | |
| $sha256_lite = (Get-FileHash $file_lite -Algorithm SHA256).Hash | |
| $raw_vt = "${{ steps.vt.outputs.analysis }}" | |
| $vt_parts = $raw_vt -split ',' | |
| $vt_url_full = $vt_parts[0] | |
| if ($vt_url_full.Contains('=')) { $vt_url_full = $vt_url_full.Substring($vt_url_full.IndexOf('=') + 1) } | |
| $vt_url_lite = $vt_parts[1] | |
| if ($vt_url_lite.Contains('=')) { $vt_url_lite = $vt_url_lite.Substring($vt_url_lite.IndexOf('=') + 1) } | |
| $body = @" | |
| # <sub>[<img src="./assets/icon.png" width="40" height="40">](https://github.com/$repo/releases/latest)</sub> Quick Rotate v$ver | |
| --- | |
| - **Build Date:** ``${{ env.BUILD_DATE }}`` | |
| - **Build Time:** ``${{ env.BUILD_TIME }}`` | |
| - **File Size:** ``$sizeKB`` | |
| - **VirusTotal:** [``Security Report``]($vt_url_full) | |
| --- | |
| ### 📥 Install & Update Options | |
| * **Direct Download (Latest) ⚡** | |
| <a href="https://github.com/$repo/releases/download/v$ver/$file_full"><img alt="Direct Download .exe" width="200px" src="https://github.com/$repo/blob/main/assets/github-button.svg?raw=true" /></a> | |
| > [!IMPORTANT] | |
| > **Heads up:** It takes a little while for the **``Microsoft Store``** and **``WinGet``** to review and publish new updates. If you don't want to wait, grab the **``Direct Download``** above to get it right now! 😉 | |
| * **Microsoft Store**<br> | |
| <a href="https://aka.ms/AA132927"><img alt="Get it from Microsoft" width="200" src="https://get.microsoft.com/images/en-us%20dark.svg" /></a> | |
| * **WinGet CLI** | |
| ``````powershell | |
| winget install QuickRotate # Install | |
| winget upgrade QuickRotate # Update | |
| `````` | |
| --- | |
| ### 🔒 Integrity Checksums — **``QuickRotate.exe``** | |
| | Algorithm | Hash | | |
| | :--- | :--- | | |
| | **MD5** | ``$md5_full`` | | |
| | **SHA-1** | ``$sha1_full`` | | |
| | **SHA-256** | ``$sha256_full`` | | |
| --- | |
| ### 😙 The Lite Edition | |
| > [!WARNING] | |
| > **About the Lite Build:** To hit the smallest possible size, the ``Lite`` build is UPX-compressed and left unsigned. UPX compression is also commonly used by malware to hide its code, so many antivirus engines flag this file purely based on that pattern 😒, not because there's actually anything wrong with it. It's safe to use, although if you prefer having a signed exe with no warnings, you can download and use the **Full** build instead 😉 | |
| > | |
| - **File Size:** ``$sizeKB_lite`` ⚡ | |
| - **VirusTotal:** [``Security Report``]($vt_url_lite) | |
| #### 🔒 Integrity Checksums — **``QuickRotate_Lite.exe``** | |
| | Algorithm | Hash | | |
| | :--- | :--- | | |
| | **MD5** | ``$md5_lite`` | | |
| | **SHA-1** | ``$sha1_lite`` | | |
| | **SHA-256** | ``$sha256_lite`` | | |
| --- | |
| ### [``📖 View Readme & Usage Guide 🙂↔️``](https://github.com/$repo/blob/main/README.md#-usage-guide) | |
| --- | |
| "@ | |
| [System.IO.File]::WriteAllText("release_notes.md", $body) | |
| - name: Create Release | |
| if: (github.event_name == 'push' && contains(github.event.head_commit.message, '[release]')) || (github.event_name == 'workflow_dispatch' && inputs.make_release == true) | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: v${{ env.APP_VERSION }} | |
| name: Quick Rotate v${{ env.APP_VERSION }} | |
| body_path: release_notes.md | |
| files: | | |
| QuickRotate.exe | |
| QuickRotate_Lite.exe |