Skip to content

build: Flutter 3.47.8, latest pub dependencies and tray_manager native API - #39

Merged
acking-you merged 9 commits into
mainfrom
chore/upgrade-deps-2026-10
Oct 27, 2026
Merged

acking-you merged 9 commits into
mainfrom
chore/upgrade-deps-2026-10

Conversation

@acking-you

Copy link
Copy Markdown
Contributor

Upgrades the UI's SDK and dependencies to their latest releases and moves the tray to tray_manager's current API. Part of the dependency refresh in acking-you/proxy-everything; no native library change is needed.

What moved

Item Old → new
Flutter SDK 3.47.7 → 3.47.8 (Dart 3.13.5 → 3.13.7): .fvmrc, FLUTTER_VERSION in ci.yml/build.yaml, READMEs
FVM in CI (setup-fvm) 4.1.0 → 4.3.2
toastification 3.2.0 → 3.2.2
crypto (dev) 3.0.7 → 3.0.8
material_color_utilities any → ^0.13.0
Transitive equatable 2.1.0 → 3.0.0, shared_preferences_android 2.4.28 → 2.5.4, shared_preferences_foundation 2.5.7 → 2.6.1, vector_math 2.4.3 → 2.4.4, vm_service 15.3.0 → 15.4.0, web 1.1.1 → 1.1.2
Other direct deps already latest; lower bounds tightened to the versions in use
GitHub Actions already latest
Podfiles unchanged (macOS 12.0 / iOS 15.0 meet every plugin minimum; Podfile.lock is not tracked)

Tray: tray_manager/legacy.dart → nativeapi

lib/src/services/tray_service.dart no longer uses the deprecated 0.5-compatible trayManager/MenuItem bridge. nativeapi calls are synchronous, so the update queue, per-call timeouts and MissingPluginException/PlatformException handling are gone, along with the unused refreshMenu; rebuild()/handleSystemResume() no longer return futures. Kept: checkbox state re-assert after a click (GTK toggles on its own), the 20 s icon re-assert, rebuild on resume/relaunch, and freeing every native tray handle before exit (the menu is now released synchronously on teardown so an immediate exit(0) cannot find it alive). One behaviour difference: right-click opens the menu natively (ContextMenuTrigger.rightClicked) instead of Dart receiving the click and opening it.

Held back

  • screen_retriever 0.3.0: window_manager 0.5.2 (latest) requires ^0.2.2.
  • cross_file 0.4.0: blocked by the file_selector platform packages.
  • material_color_utilities 0.13.1, test_api 0.7.15: pinned by the Flutter SDK.
  • Android Gradle 8.14.3 / AGP 8.11.1 / Kotlin 2.2.20: no Android SDK on the machine that did this, so an AGP 9 move (template defaults Gradle 9.3.1 / AGP 9.1.0 / Kotlin 2.4.0) could not be verified. Current values are Flutter 3.47.8's lowest accepted ones.

Verified

  • fvm flutter analyze --no-fatal-infos: no issues (26 before, incl. the tray deprecations).
  • fvm dart format --set-exit-if-changed lib/ test/: clean. fvm flutter test: 204 passed, 7 skipped. Packaging Python tests from ci.yml: pass.
  • fvm flutter build macos --debug (throwaway bundle id) succeeded with the tray library and assets.

Not verified

  • The tray has not been exercised in a running app. Please check on macOS and Windows: left-click raises the window, right-click opens the menu, the Proxy/TUN checkboxes and node switching work, Quit exits cleanly (also the Windows elevation handoff).
  • Android and iOS builds; Windows/Linux builds.

🤖 Generated with Claude Code

acking-you and others added 5 commits October 27, 2026 16:27
Pins the latest stable SDK (Dart 3.13.7) in .fvmrc, both workflows and the
READMEs, and activates FVM 4.3.2 in the shared setup action. The pinned SDK
still satisfies the ^3.13.0 Dart constraint, so pubspec keeps it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pub upgrade --major-versions --tighten moves toastification to 3.2.2, crypto
to 3.0.8, and transitively equatable to 3.0.0, shared_preferences_android to
2.5.4, shared_preferences_foundation to 2.6.1, vector_math to 2.4.4,
vm_service to 15.4.0 and web to 1.1.2. Lower bounds now name the resolved
versions, and material_color_utilities gets a real ^0.13.0 constraint
instead of `any`.

Still behind, because a dependency pins them: screen_retriever 0.3.0
(window_manager 0.5.2 requires ^0.2.2), cross_file 0.4.0 (file_selector
platform packages), material_color_utilities 0.13.1 and test_api 0.7.15
(the Flutter SDK).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tray_manager 0.7 moved the 0.5.x API to a deprecated bridge
(package:tray_manager/legacy.dart) that will be removed. The service now
owns a nativeapi TrayIcon and builds its context menu from Menu/MenuItem,
with a click listener per item.

nativeapi calls are synchronous FFI, so the method-channel era scaffolding
goes with the bridge: the serialized update queue, the per-call timeouts and
the MissingPlugin/PlatformException latch. Support is asked once through
TrayManager.isSupported, and right-click opens the menu natively at the
cursor through ContextMenuTrigger.rightClicked. The unused refreshMenu is
removed; rebuild and handleSystemResume no longer return futures.

Behaviour kept from the bridge: replaced menus are disposed after the current
event, check items re-assert their state after a click (GTK toggles them),
the icon and menu are re-asserted every 20 seconds, and shutdown frees the
icon before exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A private named parameter, `this._enableTunOnStartup`, keeps the public
`enableTunOnStartup:` name for callers and clears the
prefer_initializing_formals info from `flutter analyze`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Teardown deferred the menu's release to Timer.run, which never fires when
exit(0) follows immediately (the elevation handoff). The exit-ordering crash
shutdown() guards against needs every native tray handle released first, and
teardown never runs inside a menu item's own callback, so free it now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
acking-you and others added 4 commits October 27, 2026 21:12
Review of #39 found that nativeapi opens the menu natively while Dart keeps
running, so the 20 s tick (which cleared the menu signature) and any state
change rebuilt the menu, swapped it in and freed the old one under an open
menu: a use-after-free in the Windows menu loop, and on macOS a stale menu
left attached to the status item with dead items.

- One root menu now lives as long as its structure (the kind and key of
  each line). Labels, check marks and enabled states update in place, which
  is safe while the menu is on screen.
- A structural rebuild, or rebuild() on resume/relaunch, that falls due
  while the menu reports itself open waits for its MenuClosedEvent.
- The 20 s tick re-asserts only the icon, now including setVisible(true):
  the legacy setIcon ended with it, and it is what re-adds an icon the shell
  dropped (NIM_ADD) where the icon and tooltip setters cannot.
- Replaced menus are freed right away. Item clicks reach Dart through
  NativeCallable.listener after the native callback returns, so the
  Timer.run deferral was unnecessary, and it could leave a replaced menu
  alive at exit.
- material_color_utilities goes back to `any`: the Flutter SDK pins it, so a
  caret constraint would break `pub get` on the next SDK bump.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Second review of #39: in-place menu updates never reach Linux panels (only
SetContextMenu republishes the D-Bus menu), cannot touch a Windows submenu
line (it is registered under the submenu's handle), and the open/closed
events they relied on arrive asynchronously, so the flag could lag behind the
real menu, a click could be dropped when a deferred rebuild freed the menu on
close, and a Linux panel that never reports "closed" could wedge it.

- The trigger is ContextMenuTrigger.none; a TrayIconRightClickedEvent calls
  openContextMenu(), which blocks for as long as the menu is up on Windows
  (TrackPopupMenu) and macOS (performClick). _menuOpen is set and cleared
  synchronously around that call, so a rebuild falling due meanwhile always
  waits, and runs after the close once the click event has been delivered.
- Every change rebuilds the whole menu again and publishes it with
  setContextMenu, which republishes it to Linux panels and covers submenu
  lines on Windows. The in-place update machinery is gone.
- The menu replaced last stays alive until the next replacement, so a click
  already queued for it still finds its listener.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext opening

Third review of #39:

- cnativeapi exports the Linux D-Bus menu only under a native trigger; with
  ContextMenuTrigger.none panels showed no menu at all. Linux keeps
  rightClicked (the panel draws its own copy, so there is no blocking menu
  loop to track) and skips the Dart-side open.
- Two queued changes, or rebuild(), could free the menu a click was made in
  before that click was delivered. The menu shown by the latest opening now
  stays alive until the next opening, whichever path replaces it; a menu
  replaced without having been shown is freed at once, so nothing piles up.
  shutdown() frees both before exit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fourth review of #39: the Linux panel keeps naming the old items until it
has fetched the new layout, and nativeapi resolves those names to raw GTK
widget pointers. Freeing a replaced menu at once left a short window where a
click or property read could reach a destroyed widget, or a reused address.
Replaced menus on Linux are now freed after a 10 s grace period, and at
shutdown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@acking-you

Copy link
Copy Markdown
Contributor Author

Review record. This repository has no automated reviewer, so the PR went through an independent code review (a separate agent that read the code and the tray_manager / nativeapi / cnativeapi 0.5.2 sources), repeated until clean:

  1. Round 1: the menu could be replaced and freed while open (a Windows use-after-free; on macOS a stale, dead menu); the 20 s check no longer re-added a dropped Windows icon; replaced menus could still be queued for disposal at exit; material_color_utilities should stay any → fixed in 0e256d7.
  2. Round 2: in-place updates never reached Linux panels and couldn't update the Windows submenu line; the async open/close flag could lag or stick; a click could be dropped → redesigned in c8acb39 (the menu is opened from Dart with a synchronous open flag; full rebuilds republish).
  3. Round 3: with trigger none Linux published no menu; the shown menu could be freed before its click arrived → fixed in adfeeca.
  4. Round 4: Linux could free GTK widgets the panel still named → fixed in 3695647 (10 s grace period).
  5. Round 5: clean.

Residual caveats: macOS relies on AppKit's performClick: blocking while the menu is open (the standard idiom; not confirmed on a running app); and the menu was exercised only partly at runtime (icon creation, left click raises the window). CI: analyze-and-test, windows-desktop, and the Android release compile check pass.

🤖 Generated with Claude Code

@acking-you
acking-you merged commit 7cd9408 into main Oct 27, 2026
3 checks passed
acking-you added a commit to acking-you/proxy-everything that referenced this pull request Oct 27, 2026
Proxy-UI/Proxy-UI-Flutter#39 (merge 7cd9408): Flutter 3.47.8, latest pub
dependencies, and the tray moved to tray_manager's native API with the menu
opened from Dart so it is never replaced or freed while on screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
acking-you added a commit to acking-you/proxy-everything that referenced this pull request Oct 27, 2026
* build: upgrade the toolchain, dependencies and every submodule

Toolchain
- nightly-2026-01-26 -> nightly-2026-10-26 (rust-toolchain.toml and both CI
  workflows). rustfmt.toml needs nightly; the newer compiler also unblocks
  sysinfo 0.39 (cfg_select).
- CI: docker/login-action v4.7.0, Windows fvm 4.1.0 -> 4.3.2.

crates.io
- sysinfo 0.38 -> 0.39, arc-swap 1.9.3, rustls 0.23.46, plist 1.10, plus a
  lockfile refresh (tokio 1.54.1, ureq 3.5, uuid 1.29, icu 2.4, ...).
- lru dropped: nothing in the workspace uses it. proxy-core also drops ureq,
  kanal and async-broadcast, which only proxy-client/server use; anyhow is a
  Windows-only dependency of proxy-updater. Cargo's new unused_dependencies
  lint flagged all of these.
- Held: libc =0.2.189 and with it parking_lot 0.12 (0.13 needs libc 0.2.191).
  nix 0.31.3 still fails on iOS against newer libc; the fix (nix#2821) is
  unreleased.
- New lints: AtomicX::fetch_update -> try_update, as_chunks for fixed-size
  chunks, saturating_sub in proxy-tui's Up handling.

Submodules
- tun2proxy: upstream v0.8.6 merged; ArgProxy -> ProxyParameters.
- ipstack: upstream main merged.
- kanal: kanal-plus 0.2.1 (upstream main merged, branches 0.5). The parent
  now uses it as kanal-plus and patches crates.io kanal-plus to the same
  checkout, so uni-stream no longer pulls a second copy whose branches 0.3
  no longer compiles on current nightlies.
- uni-stream: dependencies upgraded, parking_lot replaced by std's RwLock.
- rust-smallvec: upstream v2 (2.0.0-beta.3) merged; smallvec! is deprecated,
  so the header buffer is built with new + resize. It is now its own Cargo
  workspace, so it and better_mimalloc_rs join the exclude list like every
  other fork (both were implicit members until now).
- better_mimalloc_rs: mimalloc_rust 0.1.52 merged, vendored mimalloc v2.5.2.
- sysproxy-rs: macOS fixes landed on a branch, unmaintained interfaces crate
  replaced by nix's getifaddrs.
- ui/flutter: Flutter 3.47.8, latest pub dependencies, tray on
  tray_manager's native API.

quinn stays at quinn-proto 0.11.19 / quinn 0.11.12, its latest release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(windows): use as_chunks_mut for the icon's BGRA swap

The new nightly's clippy (chunks_exact_to_as_chunks) rejects constant-size
chunks_exact_mut under -D warnings. This Windows-only call site was not
compiled on the platforms checked locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(packet-tunnel): bind the loopback proxy before building Args

Same shape as tun.rs; the inline form left rustfmt unable to lay out the
map_err closure after the ProxyParameters rename.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build: pin forks to their merged review fixes

- deps/ipstack: acking-you/ipstack#5, receive window opens when the read
  buffer is smaller than the MTU.
- deps/better_mimalloc_rs: acking-you/better_mimalloc_rs#2, vendored
  mimalloc exports mi_malloc_size and mi_malloc_usable_size without the
  override (upstream f46cacf6).
- deps/kanal: acking-you/kanal#2 and #3, kanal-plus 0.2.2 with batch
  receives and sends sound when a waker panics.

Each is the commit merged on the fork's default branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* build: pin the UI to its merged dependency upgrade

Proxy-UI/Proxy-UI-Flutter#39 (merge 7cd9408): Flutter 3.47.8, latest pub
dependencies, and the tray moved to tray_manager's native API with the menu
opened from Dart so it is never replaced or freed while on screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant