Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
e08e90e
fix(macos): enable bitsdojo custom frame and traffic-light inset
ZhuchkaTriplesix Jul 28, 2026
a2b151c
Merge pull request #474 from QueryaHub/issue/473-macos-bitsdojo-frame
ZhuchkaTriplesix Jul 28, 2026
cd59a33
ui(icons): unify mini-icon registry for trees and connection chrome
ZhuchkaTriplesix Jul 28, 2026
02bf9a1
fix: drop unused SelectableText import from connections panel
ZhuchkaTriplesix Jul 28, 2026
5a1c030
Merge pull request #475 from QueryaHub/issue/472-unify-mini-icons
ZhuchkaTriplesix Jul 28, 2026
93b709d
ui(trees): align Redis sidebar tree with shared row design
ZhuchkaTriplesix Jul 28, 2026
906bcd6
ui(trees): unify SDUI/SQLite leaf styling and tree indentation
ZhuchkaTriplesix Jul 28, 2026
0036c76
test: update SDUI icon and tree builder expectations
ZhuchkaTriplesix Jul 28, 2026
6cdf59d
Merge pull request #476 from QueryaHub/issue/472-tree-visual-unify
ZhuchkaTriplesix Jul 28, 2026
0fc0c2e
ui(motion): morph home↔object workspace switches (#478)
ZhuchkaTriplesix Jul 28, 2026
70c82d8
Merge pull request #483 from QueryaHub/issue/478-workspace-object-morph
ZhuchkaTriplesix Jul 28, 2026
b93be97
ui(motion): put SDUI tree chevrons on QueryaMotion tokens
ZhuchkaTriplesix Jul 28, 2026
caa43bf
fix: drop unused querya_motion import in SDUI tests
ZhuchkaTriplesix Jul 28, 2026
17a4f77
Merge pull request #484 from QueryaHub/issue/479-sdui-tree-motion
ZhuchkaTriplesix Jul 28, 2026
a14f472
ui(motion): unify tree expand chevron and height tokens (#480)
ZhuchkaTriplesix Jul 28, 2026
e985b74
Merge pull request #485 from QueryaHub/issue/480-tree-expand-choreogr…
ZhuchkaTriplesix Jul 28, 2026
9a2e3f9
ui(motion): reserve springsEnabled for real SpringSimulation (#481)
ZhuchkaTriplesix Jul 28, 2026
05f267d
Merge pull request #486 from QueryaHub/issue/481-honest-fluid-spring
ZhuchkaTriplesix Jul 28, 2026
5215723
ui(motion): adopt HoverSurface on type cards; quiet update badge (#482)
ZhuchkaTriplesix Jul 28, 2026
8bfaa4e
Merge pull request #487 from QueryaHub/issue/482-hover-surface-badge
ZhuchkaTriplesix Jul 28, 2026
4a6c48a
ui(motion): Extension Manager TabStrip + CrossFadeStack (#488)
ZhuchkaTriplesix Jul 28, 2026
65ef11c
Merge pull request #489 from QueryaHub/issue/488-extension-manager-mo…
ZhuchkaTriplesix Jul 28, 2026
037d0c4
fix(ui): replace CheckboxListTile under opaque dialog chrome (#491 #492)
ZhuchkaTriplesix Jul 28, 2026
c4d7892
Merge pull request #502 from QueryaHub/issue/491-492-listtile-decorat…
ZhuchkaTriplesix Jul 28, 2026
61e1706
ui(motion): TabStrip Reduced uses cubic indicator (#493)
ZhuchkaTriplesix Jul 28, 2026
d20f9fd
Merge pull request #503 from QueryaHub/issue/493-tabstrip-reduced-cubic
ZhuchkaTriplesix Jul 28, 2026
700c440
ui(motion): morph connection A→B switches in WorkspacePanel (#494)
ZhuchkaTriplesix Jul 28, 2026
314a5a3
Merge pull request #504 from QueryaHub/issue/494-connection-switch-morph
ZhuchkaTriplesix Jul 28, 2026
950fb2c
ui(extensions): honest Updates tab until Marketplace API (#495)
ZhuchkaTriplesix Jul 28, 2026
6d7780b
Merge pull request #505 from QueryaHub/issue/495-updates-tab-honesty
ZhuchkaTriplesix Jul 28, 2026
5cf918d
ui(trees): tokenize sidebar header chevrons and connection icons (#496)
ZhuchkaTriplesix Jul 28, 2026
3a4bac4
Merge pull request #506 from QueryaHub/issue/496-sidebar-header-icons
ZhuchkaTriplesix Jul 28, 2026
4883729
ui(icons): drop unused QueryaIconSizes.sduiNode (#497)
ZhuchkaTriplesix Jul 28, 2026
392735d
ci(packaging): automate AUR publish on Release (#507)
Reei-dp Jul 28, 2026
339eaed
Merge pull request #509 from QueryaHub/issue/507-aur-ci-publish
ZhuchkaTriplesix Jul 28, 2026
224a6c8
Merge pull request #508 from QueryaHub/issue/497-sdui-node-token
ZhuchkaTriplesix Jul 28, 2026
fe24af9
ui(trees): align Mongo sidebar Databases group with other drivers (#498)
ZhuchkaTriplesix Jul 28, 2026
e47fa90
Merge pull request #511 from QueryaHub/issue/498-mongo-tree-hierarchy
ZhuchkaTriplesix Jul 28, 2026
22a7136
ui(settings): theme picker exit motion and compact trigger expand (#499)
ZhuchkaTriplesix Jul 28, 2026
5b7c39e
fix(macos): hide duplicate bitsdojo window buttons in title bar (#500)
ZhuchkaTriplesix Jul 28, 2026
77be55a
Merge pull request #512 from QueryaHub/issue/499-theme-picker-exit
ZhuchkaTriplesix Jul 28, 2026
a2a7245
Merge pull request #513 from QueryaHub/issue/500-macos-hide-window-bu…
ZhuchkaTriplesix Jul 28, 2026
9ac6617
ui: ship opportunistic P2 polish batch (#501)
ZhuchkaTriplesix Jul 28, 2026
c1cde76
fix(ui): take Color for tree leaf tint to avoid ColorScheme clash
ZhuchkaTriplesix Jul 28, 2026
8af9b4f
Merge pull request #515 from QueryaHub/issue/501-p2-polish
ZhuchkaTriplesix Jul 28, 2026
57523ba
ui: finish P2 leftovers — TreeLoadError, semantics, SDUI dropdown, di…
ZhuchkaTriplesix Jul 28, 2026
45354e9
fix(ui): keep ambient text style under QueryaDialogCard Material
ZhuchkaTriplesix Jul 28, 2026
f3f133d
Merge pull request #516 from QueryaHub/issue/514-p2-leftovers
ZhuchkaTriplesix Jul 28, 2026
662be20
feat(connections): edit existing connection from sidebar context menu…
ZhuchkaTriplesix Jul 28, 2026
ceb9edf
Merge pull request #517 from QueryaHub/issue/510-edit-connection
ZhuchkaTriplesix Jul 28, 2026
54895e9
fix(extensions): edit-connection password keep and UI parity
ZhuchkaTriplesix Jul 28, 2026
bd84e67
Merge pull request #519 from QueryaHub/issue/518-extension-edit-ui-pa…
ZhuchkaTriplesix Jul 28, 2026
022c1f9
ui(connections): migrate connection forms to QueryaDialogCard
ZhuchkaTriplesix Jul 28, 2026
d1a4530
Merge pull request #521 from QueryaHub/issue/520-connection-forms-dia…
ZhuchkaTriplesix Jul 29, 2026
bb1cc57
perf(database): adaptive compute offload for large SQL result sets (#…
ZhuchkaTriplesix Jul 29, 2026
c5f1ccb
Merge pull request #523 from QueryaHub/issue/522-compute-offload-resu…
ZhuchkaTriplesix Jul 29, 2026
424df91
perf(ui): use binary search for visible column window in VirtualResul…
ZhuchkaTriplesix Jul 29, 2026
378ec1d
Merge pull request #527 from QueryaHub/issue/524-binary-search-column…
ZhuchkaTriplesix Jul 29, 2026
35a6034
perf(db): optimize SQL history pruning to use batching instead of per…
ZhuchkaTriplesix Jul 29, 2026
5366e75
Merge pull request #528 from QueryaHub/issue/525-batch-sql-history-pr…
ZhuchkaTriplesix Jul 29, 2026
c8e73e7
fix(sandbox): prevent false-positive SIGKILL in SandboxWatchdog durin…
ZhuchkaTriplesix Jul 29, 2026
c670940
Merge pull request #529 from QueryaHub/issue/526-sandbox-watchdog-bus…
ZhuchkaTriplesix Jul 29, 2026
2407c0e
refactor: replace .map().toList() with collection for loops in UI com…
ZhuchkaTriplesix Jul 29, 2026
8182fd3
Merge pull request #534 from QueryaHub/refactor/issue-530
ZhuchkaTriplesix Jul 29, 2026
b3d6d69
perf: replace empty setState calls with scoped ListenableBuilder and …
ZhuchkaTriplesix Jul 29, 2026
4169fc5
Merge pull request #535 from QueryaHub/perf/issue-531
ZhuchkaTriplesix Jul 29, 2026
b66eb3b
refactor: add context.theme and context.colors BuildContext extension…
ZhuchkaTriplesix Jul 29, 2026
f4bc138
chore: remove redundant querya_theme_scope imports now re-exported by…
ZhuchkaTriplesix Jul 29, 2026
9620da5
Merge pull request #536 from QueryaHub/refactor/issue-532
ZhuchkaTriplesix Jul 29, 2026
4bed24c
perf: replace .length > 0 with .isNotEmpty on iterables
ZhuchkaTriplesix Jul 29, 2026
7a25784
Merge pull request #537 from QueryaHub/perf/issue-533
ZhuchkaTriplesix Jul 29, 2026
5c5ae4a
perf: offload heavy JSON decoding to isolate
ZhuchkaTriplesix Jul 29, 2026
1e71eb2
perf: use cacheWidth/cacheHeight for image downsampling
ZhuchkaTriplesix Jul 29, 2026
c761a4c
Merge pull request #542 from QueryaHub/perf/issue-538
ZhuchkaTriplesix Jul 29, 2026
4364e06
Merge pull request #543 from QueryaHub/perf/issue-539
ZhuchkaTriplesix Jul 29, 2026
43b4c6d
chore: update flutter SDK constraints and major dependencies
ZhuchkaTriplesix Jul 29, 2026
7a6157a
fix: adjust SDK constraint to >=3.5.0 for compatibility with Dart 3.11.4
ZhuchkaTriplesix Jul 29, 2026
6f8f55d
fix: revert scrollCacheExtent to cacheExtent for backwards compatibil…
ZhuchkaTriplesix Jul 29, 2026
040edeb
Merge pull request #545 from QueryaHub/chore/update-flutter-deps
ZhuchkaTriplesix Jul 29, 2026
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
47 changes: 47 additions & 0 deletions .github/workflows/aur-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Manual AUR publish (hotfix / re-publish). Normal path: Release workflow → publish-aur job.
#
# First push creates the AUR repo automatically. Requires secret AUR_SSH_PRIVATE_KEY.

name: Publish AUR (querya-desktop)

on:
workflow_dispatch:
inputs:
version:
description: 'pkgver (e.g. 0.4.12) — Querya-Desktop-{version}-linux.zip must exist on GitHub Releases'
required: true
type: string
release_tag:
description: 'GitHub Release tag if different from version (e.g. v0.4.12); leave empty to auto-try'
required: false
type: string

jobs:
aur:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Require AUR SSH secret
env:
KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
run: |
if [ -z "${KEY:-}" ]; then
echo "Missing repository secret AUR_SSH_PRIVATE_KEY" >&2
exit 1
fi

- name: SSH agent
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}

- name: Publish to AUR
env:
RELEASE_TAG: ${{ github.event.inputs.release_tag }}
run: |
set -euo pipefail
VER="${{ github.event.inputs.version }}"
TAG="${RELEASE_TAG:-$VER}"
chmod +x ./scripts/linux/aur_publish.sh
./scripts/linux/aur_publish.sh "$VER" "$TAG"
43 changes: 42 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ jobs:
name: Publish GitHub Release
needs: [build-windows, build-linux, build-macos]
runs-on: ubuntu-latest
outputs:
version: ${{ needs.build-windows.outputs.version }}
release_tag: ${{ steps.rel.outputs.tag }}
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -320,7 +323,7 @@ jobs:
echo "- **Linux Flatpak**: \`Querya-Desktop-${VERSION}-linux.flatpak\` — \`flatpak install --user ./Querya-Desktop-${VERSION}-linux.flatpak\`"
echo "- **Windows setup**: \`Querya-Desktop-${VERSION}-windows-setup.exe\` (Inno Setup)"
echo ""
echo "**Arch (AUR):** PKGBUILD in \`packaging/linux/aur/\` (community-maintained)."
echo "**Arch (AUR):** \`querya-desktop\` — \`yay -S querya-desktop\` (auto-published when \`AUR_SSH_PRIVATE_KEY\` is configured)."
echo ""
echo "Verify checksums: \`SHA256SUMS.txt\`"
echo ""
Expand Down Expand Up @@ -355,3 +358,41 @@ jobs:
dist/SHA256SUMS.txt
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

publish-aur:
name: Publish AUR (querya-desktop)
needs: [publish]
runs-on: ubuntu-latest
steps:
- name: Check AUR secret
id: aur
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
run: |
if [ -n "${AUR_SSH_PRIVATE_KEY}" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
fi

- name: Wait for release assets
if: steps.aur.outputs.enabled == 'true'
run: sleep 15

- uses: actions/checkout@v4
if: steps.aur.outputs.enabled == 'true'

- name: SSH agent
if: steps.aur.outputs.enabled == 'true'
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}

- name: Publish to AUR
if: steps.aur.outputs.enabled == 'true'
run: |
set -euo pipefail
VER="${{ needs.publish.outputs.version }}"
TAG="${{ needs.publish.outputs.release_tag }}"
chmod +x ./scripts/linux/aur_publish.sh
./scripts/linux/aur_publish.sh "$VER" "$TAG"
11 changes: 10 additions & 1 deletion .github/workflows/version-bump.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,20 @@ jobs:
sed -i "s/^version: .*/version: ${NEW_VERSION}+${NEW_BUILD}/" pubspec.yaml
grep "^version:" pubspec.yaml

- name: Sync AUR PKGBUILD pkgver with pubspec
if: steps.check.outputs.merged == 'true'
run: |
NEW_VERSION="${{ steps.bump.outputs.new_version }}"
sed -i "s/^pkgver=.*/pkgver=${NEW_VERSION}/" packaging/linux/aur/PKGBUILD
sed -i "s/^pkgrel=.*/pkgrel=1/" packaging/linux/aur/PKGBUILD
sed -i "s/^sha256sums=.*/sha256sums=('SKIP' 'SKIP' 'SKIP')/" packaging/linux/aur/PKGBUILD
grep ^pkgver packaging/linux/aur/PKGBUILD

- name: Commit version bump
if: steps.check.outputs.merged == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add pubspec.yaml
git add pubspec.yaml packaging/linux/aur/PKGBUILD
git commit -m "Bump version to ${{ steps.bump.outputs.new_version }}+${{ steps.bump.outputs.new_build }}"
git push origin main
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ version locally to avoid "works on my machine" drift. When bumping the pin, run

For animated UI, **do not invent magic `Duration(...)` / raw curves** in widgets.

- Use `QueryaMotion` tokens (`fast` / `standard` / `slow`) via
- Use `QueryaMotion` tokens (`fast` / `standard` / `slow` / `treeExpand`) via
`context.motionDuration` / `context.motionCurve` (or `QueryaMotion.effective*`).
- Interactive Fluid motion: `QueryaSpring` / `QueryaSpringController` when
`QueryaSpring.springsEnabled` (Full motion only).
- **Real springs only:** `QueryaSpring` / `QueryaSpringController` when
`QueryaSpring.springsEnabled` (Full motion) — tab indicator, drag settle, etc.
Do not use `springsEnabled` just to pick an emphasized cubic for fades/dialogs.
- Honor Preferences Motion Full / Reduced / Off and OS `disableAnimations`.
- Mid-drag layout (split panes) stays 1:1; spring settle only on drag-end.
- Do not animate virtualized grid rows on scroll.
Expand Down
10 changes: 8 additions & 2 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ include: package:flutter_lints/flutter.yaml

analyzer:
exclude:
- third_party/**
- build/**
- "third_party/**"
- "build/**"
errors:
unnecessary_underscores: ignore
prefer_initializing_formals: ignore
use_null_aware_elements: ignore
deprecated_member_use: ignore

linter:
rules:
- prefer_const_constructors
- prefer_const_declarations

26 changes: 23 additions & 3 deletions docs/motion-and-high-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ Introduce `lib/core/motion/` with a single source of truth for durations and cur
|-------|-------|-----|
| `instant` | 0 ms | reduced-motion / disabled |
| `fast` | 120 ms | hover, small state changes |
| `standard` | 200 ms | dialogs, menus, expand/collapse |
| `standard` | 200 ms | dialogs, menus, general surfaces |
| `treeExpand` | 200 ms (= `standard`) | connection/SDUI tree: **chevron + height** share one clock (#480) |
| `slow` | 320 ms | emphasized / large surfaces, theme cross-fade |

### 4.2 Curve tokens
Expand All @@ -91,7 +92,8 @@ Introduce `lib/core/motion/` with a single source of truth for durations and cur
|-------|-------|-----|
| `enter` | `easeOutCubic` | elements appearing (decelerate) |
| `exit` | `easeInCubic` | elements leaving (accelerate) |
| `standard` | `easeInOutCubic` | move/resize in place |
| `standardCurve` | `easeInOutCubic` | move/resize in place |
| `treeExpandCurve` | = `enter` | tree expand chevron + `QueryaAnimatedExpand` |
| `emphasized` | `Curves.easeInOutCubicEmphasized` | hero / theme transitions |

### 4.3 Reduced motion / accessibility
Expand All @@ -110,6 +112,16 @@ Introduce `lib/core/motion/` with a single source of truth for durations and cur
- **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).

### 4.5 Springs vs duration-token cubics (#481)

`QueryaSpring.springsEnabled` (Full motion only) means **real** `SpringSimulation` /
`QueryaSpringController` — tab strip indicator, split drag settle, and similar
interruptible physics.

Shell morphs (`QueryaFadeSlide`, `QueryaSwitchingBody`, `showAppDialog`) always use
duration tokens (`standard` + `enter`/`exit`). Do **not** treat `emphasized` cubic
as a stand-in for “Fluid spring.”

---

## 5. Implementation plan (proposed issues)
Expand Down Expand Up @@ -151,13 +163,21 @@ When reviewing PRs that touch animation:
2. Require Full / Reduced / Off + OS `disableAnimations` coverage for new transitions.
3. Split / resize: no spring or lag mid-drag; settle only on release / focus chrome.
4. Never stagger or fade virtualized result rows while scrolling.
5. Tree expand: chevron `AnimatedRotation` and `QueryaAnimatedExpand` **must** use
`QueryaMotion.treeExpand` + `treeExpandCurve` (not `fast`/`standardCurve` mixed
with `standard`/`enter`).
6. **Springs vs cubics (#481):** `QueryaSpring.springsEnabled` gates **real**
`SpringSimulation` / `QueryaSpringController` only (tab strip indicator, split
drag settle). Shell morphs (`QueryaFadeSlide`, `QueryaSwitchingBody`,
`showAppDialog`) use duration-token cubics (`standard`/`enter`/`exit`) — do not
brand emphasized ease as “spring”.

**Allowed named non-token durations** (named + documented — not magic literals at call sites):

| Constant | Value | Where |
|----------|-------|--------|
| `kQueryaStaggerStep` | 30 ms | `QueryaStagger` first-paint choreography |
| `kUpdateBadgePulsePeriod` | 1400 ms | Update title-bar chip pulse (chrome; see #363) |
| `kUpdateBadgePulsePeriod` | 1400 ms | Update title-bar chip pulse at Full; Reduced halves via `effectiveDuration`; Off / OS disable stop (#363, #482) |

Checklist for 120 Hz verification: [perf-baseline.md](perf-baseline.md) § Fluid shell.

Expand Down
2 changes: 1 addition & 1 deletion docs/packaging.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ payload as the portable zip and AppImage.
| `.deb` | [`scripts/linux/build_deb.sh`](../scripts/linux/build_deb.sh) | `sudo apt install ./Querya-Desktop-{ver}-linux.deb` |
| `.rpm` | [`scripts/linux/build_rpm.sh`](../scripts/linux/build_rpm.sh) | `sudo dnf install ./Querya-Desktop-{ver}-linux.rpm` |
| Flatpak | [`scripts/linux/build_flatpak.sh`](../scripts/linux/build_flatpak.sh) | `flatpak install --user ./Querya-Desktop-{ver}-linux.flatpak` |
| AUR | [`packaging/linux/aur/`](../packaging/linux/aur/) | Community PKGBUILD (Release zip under `/opt`) |
| AUR | [`packaging/linux/aur/`](../packaging/linux/aur/) | `yay -S querya-desktop` (CI publishes on Release when `AUR_SSH_PRIVATE_KEY` is set) |

**Runtime dependencies (deb/rpm):** GTK 3, libsecret, GLib; app indicator recommended for tray.

Expand Down
2 changes: 1 addition & 1 deletion docs/tags-and-releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ sudo dnf install ./Querya-Desktop-X.Y.Z-linux.rpm
flatpak install --user ./Querya-Desktop-X.Y.Z-linux.flatpak
```

**Arch (AUR):** community PKGBUILD — [`packaging/linux/aur/`](../packaging/linux/aur/) (installs the Release portable zip under `/opt`).
**Arch (AUR):** `yay -S querya-desktop` — auto-published by Release CI when `AUR_SSH_PRIVATE_KEY` is configured ([`packaging/linux/aur/`](../packaging/linux/aur/)).

## Changelog в GitHub Release

Expand Down
6 changes: 3 additions & 3 deletions lib/app/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ class QueryaApp extends StatelessWidget {

return ListenableBuilder(
listenable: themeController,
builder: (context, _) {
builder: (context, __) {
final queryaTheme = themeController.activeTheme;
final colorScheme = queryaTheme.colorScheme;

return ListenableBuilder(
listenable: uiScaleController,
builder: (context, _) {
builder: (context, __) {
final scale = uiScaleController.scale;
return ListenableBuilder(
listenable: motionController,
builder: (context, _) {
builder: (context, __) {
final motionLevel = motionController.level;
final disableAnimations =
MediaQuery.maybeOf(context)?.disableAnimations ??
Expand Down
36 changes: 29 additions & 7 deletions lib/core/database/result_row_string_convert.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
/// Converts SQL result cells to display strings without a second isolate copy.
///
/// Prefer this over [compute] for large matrices: shipping `List<List<Object?>>`
/// across isolates often costs more than `toString()` itself and roughly
/// doubles peak memory. Yielding every [yieldEvery] rows keeps the UI isolate
/// responsive for 10k+ row caps.
library;
import 'package:flutter/foundation.dart';

const int kResultStringConvertYieldEvery = 250;
const int kResultStringConvertComputeThreshold = 1000;

/// Maps null cells to `'NULL'` and others via [Object.toString].
String resultCellToDisplayString(Object? value) =>
value == null ? 'NULL' : value.toString();

/// Converts [rowValues] to string rows synchronously.
List<List<String>> convertResultRowsToStringsSync(List<List<Object?>> rowValues) {
if (rowValues.isEmpty) return const [];
return [
for (final row in rowValues)
[for (final value in row) resultCellToDisplayString(value)],
];
}

/// Top-level function suitable for [compute] offloading.
List<List<String>> convertResultRowsToStringsCompute(List<List<Object?>> rowValues) =>
convertResultRowsToStringsSync(rowValues);

/// Converts [rowValues] to string rows, yielding periodically.
Future<List<List<String>>> convertResultRowsToStringsYielding(
List<List<Object?>> rowValues, {
Expand All @@ -31,3 +39,17 @@ Future<List<List<String>>> convertResultRowsToStringsYielding(
}
return out;
}

/// Converts [rowValues] adaptively: offloads to a background isolate via [compute]
/// if row count >= [computeThreshold], otherwise yields on the main isolate.
Future<List<List<String>>> convertResultRowsToStringsAdaptive(
List<List<Object?>> rowValues, {
int computeThreshold = kResultStringConvertComputeThreshold,
int yieldEvery = kResultStringConvertYieldEvery,
}) async {
if (rowValues.isEmpty) return const [];
if (rowValues.length >= computeThreshold) {
return compute(convertResultRowsToStringsCompute, rowValues);
}
return convertResultRowsToStringsYielding(rowValues, yieldEvery: yieldEvery);
}
2 changes: 1 addition & 1 deletion lib/core/extensions/rpc/json_rpc_payload_limits.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class _BoundedUtf8LineSplitter
},
onError: fail,
onDone: () {
if (pending.length > 0) {
if (pending.isNotEmpty) {
if (pending.length > maxLineBytes) {
fail(
JsonRpcPayloadTooLargeException(
Expand Down
6 changes: 6 additions & 0 deletions lib/core/extensions/rpc/json_rpc_stdio_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ class JsonRpcStdioClient {
StreamSubscription<String>? _subscription;
Object? _fatalError;

/// Number of RPC requests currently in-flight waiting for a response.
int get pendingRequestCount => _pending.length;

/// Returns true when there is at least one active RPC request in-flight.
bool get hasPendingRequests => _pending.isNotEmpty;

/// Serializes async line handling so large-line isolate decode stays ordered.
Future<void> _lineChain = Future<void>.value();

Expand Down
1 change: 1 addition & 0 deletions lib/core/extensions/rpc/plugin_rpc_bridge.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class PluginRpcBridge {
if (enableWatchdog) {
_watchdog = SandboxWatchdog(
recovery: _recovery,
isBusy: () => client.hasPendingRequests,
onStopped: (reason) {
if (reason == SandboxWatchdogStopReason.deadlock) {
unawaited(_audit?.record(
Expand Down
8 changes: 6 additions & 2 deletions lib/core/extensions/sandbox/sandbox_watchdog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,19 @@ enum SandboxWatchdogStopReason {
class SandboxWatchdog {
SandboxWatchdog({
this.pingInterval = const Duration(seconds: 30),
this.pongTimeout = const Duration(seconds: 5),
this.pongTimeout = const Duration(seconds: 15),
this.recovery,
bool Function()? isBusy,
Future<Object?> Function()? ping,
void Function(SandboxWatchdogStopReason reason)? onStopped,
}) : _pingOverride = ping,
}) : _isBusy = isBusy,
_pingOverride = ping,
_onStopped = onStopped;

final Duration pingInterval;
final Duration pongTimeout;
final SandboxAutoRecovery? recovery;
final bool Function()? _isBusy;
final Future<Object?> Function()? _pingOverride;
final void Function(SandboxWatchdogStopReason reason)? _onStopped;

Expand Down Expand Up @@ -107,6 +110,7 @@ class SandboxWatchdog {

Future<void> _tick() async {
if (!_running || _pingInFlight) return;
if (_isBusy?.call() ?? false) return;
_pingInFlight = true;
try {
final result = await _sendPing().timeout(pongTimeout);
Expand Down
Loading
Loading