Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,27 @@ jobs:
cd dist
sha256sum *.zip | tee SHA256SUMS.txt

- name: Build release notes from CHANGELOG.md
run: |
set -euo pipefail
VERSION="${{ needs.build-windows.outputs.version }}"
./scripts/extract-changelog-section.sh "$VERSION" > release-notes.md
{
echo ""
echo "---"
echo ""
echo "### Downloads"
echo "- **Linux**: \`Querya-Desktop-${VERSION}-linux.zip\`"
echo "- **Windows**: \`Querya-Desktop-${VERSION}-windows.zip\`"
echo "- **macOS**: \`Querya-Desktop-${VERSION}-macos.zip\` (unsigned \`.app\` in zip; right-click → Open on first launch)"
echo ""
echo "Verify checksums: \`SHA256SUMS.txt\`"
echo ""
echo "### Build info"
echo "- **pubspec**: ${{ needs.build-windows.outputs.full_version }}"
echo "- **Commit**: ${{ github.sha }}"
} >> release-notes.md

- name: Release tag name
id: rel
run: |
Expand All @@ -206,19 +227,7 @@ jobs:
with:
tag_name: ${{ steps.rel.outputs.tag }}
name: Querya Desktop ${{ needs.build-windows.outputs.version }}
body: |
## Querya Desktop ${{ needs.build-windows.outputs.version }}

### Downloads
- **Linux**: `Querya-Desktop-${{ needs.build-windows.outputs.version }}-linux.zip`
- **Windows**: `Querya-Desktop-${{ needs.build-windows.outputs.version }}-windows.zip`
- **macOS**: `Querya-Desktop-${{ needs.build-windows.outputs.version }}-macos.zip` (unsigned `.app` in zip; right-click → Open on first launch)

Verify checksums: `SHA256SUMS.txt`

### Build info
- **pubspec**: ${{ needs.build-windows.outputs.full_version }}
- **Commit**: ${{ github.sha }}
body_path: release-notes.md
fail_on_unmatched_files: true
files: |
dist/*.zip
Expand Down
13 changes: 11 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Planned (0.4.3)
## [0.4.3] - 2026-06-15

Theme and extensions follow-ups — see [docs/planned-0.4.3.md](docs/planned-0.4.3.md): file watcher (TP-F1), marketplace metadata (TP-F2), visual theme editor (TP-F3), remote theme install (TP-F4).
Theme follow-ups release (TP-F1–TP-F4, GitHub issues **#159–#163**). Git tag **`0.4.3`**.

### Added

- **Theme folder watcher (TP-F1)** — debounced `Directory.watch` on `{appSupport}/themes/` auto-refreshes the registry when files are added, removed, or renamed.
- **Marketplace metadata (TP-F2)** — optional manifest fields (`homepage`, `license`, `preview`, `tags`); theme picker shows author/tags; `ExtensionManifest` stub in `lib/core/market/` for future Explore UI.
- **Visual theme editor (TP-F3)** — Preferences section to tweak workbench colors with live preview and export `querya.theme.v1` JSON.
- **Remote theme install (TP-F4)** — **Install from URL…** (HTTPS-only, public hosts, optional SHA-256); `ThemeRemoteInstallService` with checksum verify before import.
- **Docs / QA** — remote install section in [theme-import.md](docs/theme-import.md); 0.4.3 items in [release-checklist.md](docs/release-checklist.md).
- **Tests** — file watcher, remote install policy/service, theme editor and metadata coverage.

## [0.4.2] - 2026-06-14

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ a clean, dark UI inspired by tools like pgAdmin.
statement timeouts, query history, and CSV/JSON export.
- **Object browsing** — connection tree with databases, tables, views, and
server stats.
- **Themeable** — dark/light/system, **VS Code theme import**, custom `querya.theme.v1` registry, and bundled themes (0.4.2).
- **Themeable** — dark/light/system, **VS Code theme import**, custom `querya.theme.v1` registry, visual editor, remote install, and bundled themes (0.4.3).
- **Scalable UI** — global interface scaling for high-DPI and accessibility.
- **Secure by default** — passwords and connection strings live in the OS secure
store, never in plaintext.
Expand Down
4 changes: 3 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ Index of Querya Desktop documentation, grouped by audience.
## Planning

- [Roadmap](roadmap.md) — current direction and follow-ups.
- [Planned 0.4.3](planned-0.4.3.md) — deferred theme/extensions follow-ups after 0.4.2.
- [Planned 0.4.3](planned-0.4.3.md) — shipped theme follow-ups (TP-F1–TP-F4).
- [Planned 0.4.4](planned-0.4.4.md) — UI motion polish and high refresh rate.
- [Motion and high refresh rate](motion-and-high-refresh.md) — 0.4.4 research, audit, and per-platform Hz design.
- [Custom theme parser requirements](scheme-parcer.md) — JSON theme format and scaling spec.
- [Theme parser implementation plan](theme-parser-implementation-tasks.md) — task breakdown and architecture.
- [Theme parser GitHub issues](theme-parser-github-issues.md) — issue templates for epic #96–#125.
Expand Down
144 changes: 144 additions & 0 deletions docs/motion-and-high-refresh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# Motion system and high-refresh-rate support (0.4.4 research)

**Status:** research / design for **0.4.4**.
**Scope:** Querya Desktop is **desktop-only** (Linux, Windows, macOS — see [`linux/`](../linux), [`windows/`](../windows), [`macos/`](../macos)). Toolchain at time of writing: **Flutter 3.41.6 stable**, Impeller engine.

Goal of 0.4.4: make every animation **smooth and pleasant**, driven by a single motion system, and make the app actually render at the display's **native refresh rate (90/120/144 Hz)** on each OS instead of being capped at 60.

---

## 1. Why this matters

Two independent problems are often confused:

1. **Frame rate (Hz)** — how many frames the engine renders per second. If the app is locked to 60 Hz on a 120 Hz monitor, *every* animation looks half as smooth no matter how good the curves are.
2. **Motion design** — the durations, curves, and choreography of each animation. Even at 120 Hz, a linear 100 ms snap feels cheap; a well-tuned eased 180 ms feels premium.

0.4.4 must fix **both**. High-Hz is the multiplier; the motion system is the quality.

Important Flutter fact: animations are **vsync/ticker driven and frame-rate independent**. A `Duration(milliseconds: 200)` plays over 200 ms of wall-clock time and is interpolated **per frame**. So at 120 Hz the *same* animation simply gets twice as many in-between frames — no code change to durations is needed for high-Hz smoothness. The only requirement is that the engine is told it may render faster than 60.

---

## 2. Current state audit (codebase)

There is **no central motion system** today. Animations are scattered, with inconsistent durations and curves, and **no reduced-motion / accessibility handling** anywhere (`grep` for `disableAnimations` / `accessibleNavigation` → 0 matches).

| Location | What animates | Duration | Curve |
|----------|---------------|----------|-------|
| `lib/shared/widgets/app_dialog.dart` | Dialog fade + scale (0.92→1.0) + backdrop blur (8σ) | 200 ms | `easeOutCubic` |
| `lib/shared/widgets/querya_dropdown.dart` | Trigger + menu hover background | `QueryaDropdownTokens.hoverAnimationMs` | `easeOut` |
| `lib/features/settings/theme_picker_button.dart` | Hover containers; preview debounce 120 ms | 120 ms / debounce | `easeOut` |
| `lib/features/main_screen/workspace_panel.dart` | Tab/area container + `AnimatedScale` | 120 ms / 100 ms | `easeOut` |
| `lib/features/connections/connections_panel_pg_tree.dart` | Chevron `AnimatedRotation`; tooltip wait 450 ms | 100 ms | (default) |
| `lib/features/connections/connections_panel_{sidebar,mysql,mongo,redis,postgres_connection}.dart` | Row hover containers | 100 ms | (default/`easeOut`) |
| `lib/features/{mysql,postgresql}/*_workspace_home.dart` | Card hover containers | 120 ms | `easeOut` |
| `lib/features/connections/new_connection_dialog.dart` | Type-card hover | 120 ms | `easeOut` |
| `lib/core/theme/theme_controller.dart` | `ShadcnAnimatedTheme` (theme cross-fade) | engine default | — |
| `lib/features/main_screen/result_grid_view.dart` | Tooltip wait 400 ms | — | — |

### Findings

- **Inconsistent durations:** 100 ms vs 120 ms vs 200 ms for conceptually similar interactions (hover, expand, dialog).
- **Curve monoculture:** almost everything is `Curves.easeOut`; no distinction between *enter* (decelerate), *exit* (accelerate), and *emphasized* motion.
- **No tokens:** magic `Duration(...)` literals repeated ~20 places. Only `QueryaDropdownTokens` partially tokenizes one widget.
- **No reduced-motion support:** users who set "reduce motion" at the OS level still get all animations.
- **Theme switch** is the only "big" transition and it is off by default (`themeAnimationEnabled = false`).
- **No expand/collapse height animation** on tree nodes — they pop in/out (`if (_expanded) ...`), only the chevron rotates.

---

## 3. How high refresh rate works in Flutter (per platform)

Summary of current engine behavior (Flutter 3.24+ / Impeller). Sources in §7.

| Platform | Renders at display Hz by default? | How to unlock > 60 Hz | Notes |
|----------|-----------------------------------|------------------------|-------|
| **Windows** | Usually yes (follows monitor via DWM) | No app API needed | Verify on a 120/144 Hz monitor; engine vsyncs to the compositor. |
| **Linux** | Depends on compositor (GTK embedder) | No app API; compositor-dependent | Wayland compositors with VRR may need monitor config; X11 follows monitor. |
| **macOS** | Capped to 60 on some setups | macOS 14+ can opt into ProMotion/high-Hz | Historically Flutter macOS did not always hit ProMotion; needs verification. |
| **iOS** (future) | No — capped to 60 | `CADisableMinimumFrameDurationOnPhone=true` in `Info.plist` | Not applicable today (no `ios/`), document for when mobile lands. |
| **Android** (future) | No — often picks 60 | `flutter_displaymode` / `Surface.setFrameRate()` | Not applicable today (no `android/`). |

Root cause (engine): per `flutter/flutter#160952`, the engine "can render at 120 Hz (Impeller since 3.24) but never tells the OS compositor it can handle more" on several platforms. Community package **`refresh_rate`** (pub.dev) works around this and additionally provides **query / live FPS overlay / benchmark** on all six platforms, with actual *unlock* on Android, iOS 15+, and macOS 14+.

### Practical implication for Querya (desktop)

- **Windows / Linux:** most likely already render at monitor Hz; the job is to **measure and verify**, then ensure no app-side code caps frames (e.g. heavy `setState`, unbounded rebuilds during animation).
- **macOS:** the real high-Hz work — confirm ProMotion behavior; unlock via `refresh_rate` if capped at 60.
- Use `refresh_rate` (or a thin wrapper) primarily for **diagnostics**: a debug-only FPS/Hz overlay and a benchmark to prove smoothness on each machine, plus the macOS unlock call in `main()`.

---

## 4. Proposed motion design system

Introduce `lib/core/motion/` with a single source of truth for durations and curves, scaled by accessibility settings.

### 4.1 Duration tokens (`QueryaMotion`)

| Token | Value | Use |
|-------|-------|-----|
| `instant` | 0 ms | reduced-motion / disabled |
| `fast` | 120 ms | hover, small state changes |
| `standard` | 200 ms | dialogs, menus, expand/collapse |
| `slow` | 320 ms | emphasized / large surfaces, theme cross-fade |

### 4.2 Curve tokens

| Token | Curve | Use |
|-------|-------|-----|
| `enter` | `easeOutCubic` | elements appearing (decelerate) |
| `exit` | `easeInCubic` | elements leaving (accelerate) |
| `standard` | `easeInOutCubic` | move/resize in place |
| `emphasized` | `Curves.easeInOutCubicEmphasized` | hero / theme transitions |

### 4.3 Reduced motion / accessibility

- Read `MediaQuery.disableAnimationsOf(context)` (OS "reduce motion") and an optional in-app Preferences toggle.
- When reduced: collapse all durations to `instant` (or a short cross-fade), never fully remove feedback.
- Provide a helper `context.motion(Token)` that returns the effective duration after applying the reduced-motion factor.

### 4.4 Targeted animation upgrades

- **Dialogs** (`app_dialog.dart`): keep the blur+scale pattern, retune to `standard`/`enter`; ensure backdrop and card share one curve.
- **Dropdowns / menus**: add an enter scale+fade (currently only hover color), `standard`/`enter`.
- **Tree expand/collapse**: animate height with `AnimatedSize` (+ chevron rotation already present) instead of pop-in.
- **Tab / workspace switches**: cross-fade content via `AnimatedSwitcher` with `standard`.
- **Hover states**: unify all row/card hovers to `fast`/`standard` curve.
- **Theme switch**: enable a tasteful `emphasized` cross-fade and consider making it on-by-default.
- **List/grid item insertion** (results, history): subtle staggered fade-in for first paint only (no per-scroll cost).

---

## 5. Implementation plan (proposed issues)

Milestone **0.4.4** (see [planned-0.4.4.md](planned-0.4.4.md)).

1. **UI-A1 — Motion tokens core.** `lib/core/motion/` with `QueryaMotion` durations/curves + `context.motion()` reduced-motion helper. Unit tests.
2. **UI-A2 — Adopt tokens across widgets.** Replace magic `Duration(...)`/`Curves.easeOut` literals in dialogs, dropdowns, tree, workspace panel, connection forms. No behavior regressions in layout tests.
3. **UI-A3 — Smoother transitions.** Dialog retune, dropdown enter animation, tree `AnimatedSize` expand/collapse, tab `AnimatedSwitcher`.
4. **UI-A4 — High-refresh-rate enablement.** Add `refresh_rate` (or wrapper); unlock on macOS 14+ in `main()`; query active Hz; debug-only FPS/Hz overlay behind a flag.
5. **UI-A5 — Reduced-motion + Preferences.** Honor OS "reduce motion"; add **Preferences → Appearance → Motion** (Full / Reduced / Off) wired to the motion helper.
6. **UI-A6 — Measurement & docs.** DevTools timeline checklist in [perf-baseline.md](perf-baseline.md); per-OS Hz verification table; update this doc with measured results.

Suggested order: A1 → A2 → A3 in parallel with A4; then A5; A6 closes the milestone.

---

## 6. Testing & measurement

- **DevTools → Performance / Frame chart:** confirm frame build/raster times stay under the budget at the monitor's Hz (8.3 ms @ 120 Hz, 6.9 ms @ 144 Hz).
- **`refresh_rate` overlay / benchmark:** prove the real on-device Hz before/after; capture numbers per OS.
- **Reduced-motion test:** widget test that durations collapse when `disableAnimations: true` is injected via `MediaQuery`.
- **Regression:** existing layout/overflow tests must stay green; animations must not change final layout geometry.

---

## 7. References

- Flutter engine — high refresh rate gap: `flutter/flutter#160952`, `#90675` (ProMotion scrolling), `#94508` (`CADisableMinimumFrameDurationOnPhone` default).
- `refresh_rate` package (query/unlock/overlay/benchmark, all platforms): https://pub.dev/packages/refresh_rate
- `flutter_displaymode` (Android high-Hz): https://pub.dev/packages/flutter_displaymode
- Apple — Optimizing for ProMotion: https://developer.apple.com/documentation/quartzcore/optimizing-iphone-and-ipad-apps-to-support-promotion-displays
- Flutter blog — iOS variable refresh rate (Flutter 3): https://blog.flutter.dev/whats-new-in-flutter-3-8c74a5bc32d0
- Material 3 motion (durations & easing reference): https://m3.material.io/styles/motion/overview
22 changes: 11 additions & 11 deletions docs/planned-0.4.3.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Planned release 0.4.3 — theme and extensions follow-ups

**Status:** planning (not started).
**Status:** **shipped in 0.4.3** (GitHub milestone [**0.4.3**](https://github.com/QueryaHub/Querya-Desktop/milestone/2), epic **#159** closed).
**Depends on:** **0.4.2** custom theme registry (TP-01–TP-30, shipped).

This document captures work intentionally deferred from the first custom-theme pass.
Expand All @@ -9,22 +9,22 @@ See also [theme-parser-github-issues.md](theme-parser-github-issues.md) (TP-F1

## Theme folder and discovery

| ID | Scope | Summary |
|----|--------|---------|
| **TP-F1** | `theme`, `filesystem` | **File watcher** for `{appSupport}/themes/` — auto-refresh the registry when files are added, removed, or renamed. Deferred: OS-specific watcher APIs and app lifecycle edge cases. |
| ID | Issue | Scope | Summary |
|----|-------|--------|---------|
| **TP-F1** | [#160](https://github.com/QueryaHub/Querya-Desktop/issues/160) | `theme`, `filesystem` | **File watcher** for `{appSupport}/themes/` — auto-refresh the registry when files are added, removed, or renamed. Deferred: OS-specific watcher APIs and app lifecycle edge cases. |

## Theme distribution and metadata

| ID | Scope | Summary |
|----|--------|---------|
| **TP-F2** | `theme`, `marketplace` | **Marketplace metadata** on `ThemeDefinition` / manifests — preview image, tags, homepage, license, author. Prerequisite for listing themes in a future Extensions UI. |
| **TP-F4** | `theme`, `network` | **Remote theme install** — download from URL with checksum/trust policy. Requires security review (HTTPS, signatures, user consent). |
| ID | Issue | Scope | Summary |
|----|-------|--------|---------|
| **TP-F2** | [#161](https://github.com/QueryaHub/Querya-Desktop/issues/161) | `theme`, `marketplace` | **Marketplace metadata** on `ThemeDefinition` / manifests — preview image, tags, homepage, license, author. Prerequisite for listing themes in a future Extensions UI. |
| **TP-F4** | [#163](https://github.com/QueryaHub/Querya-Desktop/issues/163) | `theme`, `network` | **Remote theme install** — download from URL with checksum/trust policy. Requires security review (HTTPS, signatures, user consent). |

## Authoring UX

| ID | Scope | Summary |
|----|--------|---------|
| **TP-F3** | `theme`, `settings` | **Visual theme editor** in Preferences — tweak colors, export `querya.theme.v1`. Larger than parser/import; likely multiple PRs. |
| ID | Issue | Scope | Summary |
|----|-------|--------|---------|
| **TP-F3** | [#162](https://github.com/QueryaHub/Querya-Desktop/issues/162) | `theme`, `settings` | **Visual theme editor** in Preferences — tweak colors, export `querya.theme.v1`. Larger than parser/import; likely multiple PRs. |

## Extensions marketplace (optional overlap)

Expand Down
Loading
Loading