Skip to content

Android: lifecycle leaks in TabletModeWrapper and the conversation controller, split-ratio clamp, bubble guard, edge-to-edge inset for the Cupertino chat list - #272

Open
byaletheya-sudo wants to merge 1 commit into
OpenBubbles:rustpushfrom
byaletheya-sudo:fix/android-lifecycle-and-insets
Open

byaletheya-sudo wants to merge 1 commit into
OpenBubbles:rustpushfrom
byaletheya-sudo:fix/android-lifecycle-and-insets

Conversation

@byaletheya-sudo

@byaletheya-sudo byaletheya-sudo commented Sep 17, 2026

Copy link
Copy Markdown

Five independent, self-contained fixes; happy to split further if preferred.

  • TabletModeWrapper leaks. initState subscribes to eventDispatcher.stream and registers a debounce Worker, with no dispose(), so every rebuild (skin or theme change, entering or leaving the split layout) leaves another live listener writing splitRatio to prefs. Added dispose() and a mounted guard. (Same fix as the wrapper hunk of Fix widget, animation, and controller lifecycle leaks #227, extracted so it can land on its own.)
  • Split ratio drift. splitRatio is one shared pref; goToSearch drives it to 0.3, below the mobile minRatio, and the debounced worker persists it, so split-refresh reloaded an out-of-range value into every wrapper. Clamp on the refresh read path only; override-split stays unclamped because search deliberately goes below the minimum and restores afterwards.
  • Tablet mode inside a chat bubble. NavigatorService.isTabletMode lacked showAltLayout's !ls.isBubble guard, so in a bubble wider than 600 dp it returned true while the nested navigators were not built, and ns.push/pushLeft/backConversationView routed into navigators that are not in the tree.
  • Edge-to-edge (targetSdk 36). Android draws behind the navigation bar and ignores systemNavigationBarColor. The Material list consumes the bottom inset via BoxScrollView and the Samsung list is inside a SafeArea, but the Cupertino list's bare CustomScrollView does neither, so the last conversation sat under the gesture bar. One trailing SliverPadding of MediaQuery.padding.bottom; nothing restyled.
  • Keyboard listener leak. ConversationViewController.onInit listens to KeyboardVisibilityController().onChange; onClose cancelled shareSubscription but never this one, so every opened chat left a listener that touched the disposed scroll controller on each keyboard show/hide for the life of the process. Stored and cancelled alongside the existing subscription.

Verification. Built as a release APK (arm64) from this branch and installed on a Galaxy Z Fold 8; the app runs. Live-chat behavior (divider after search, keyboard responsiveness over many chats, the last row above the gesture bar) could not be exercised in a sideloaded build because registration needs the hosted service; each item is argued from the code above. flutter analyze reports no new diagnostics against rustpush.

🤖 Generated with Claude Code

…d tablet mode in bubbles, clear the nav bar in the Cupertino chat list, cancel the keyboard listener

- TabletModeWrapper subscribed to eventDispatcher.stream and registered a debounce
  Worker in initState with no dispose(), so every rebuild (skin/theme change, entering
  or leaving the split layout) left another live listener writing splitRatio to prefs.
  Added dispose() and a mounted guard.
- splitRatio is one shared pref; goToSearch drives it to 0.3, below the mobile minRatio,
  and the debounced worker persisted it, so split-refresh reloaded an out-of-range value.
  Clamp on the refresh read path (override-split stays unclamped on purpose).
- NavigatorService.isTabletMode lacked showAltLayout's !ls.isBubble guard, so in a chat
  bubble wider than 600dp it returned true while the nested navigators were not built.
- With targetSdk 36 (edge-to-edge enforced) the Cupertino chat list's CustomScrollView
  did not consume the bottom inset, so the last conversation sat under the gesture bar.
  Added a trailing SliverPadding of MediaQuery padding.bottom.
- ConversationViewController cancelled shareSubscription in onClose but never its
  KeyboardVisibilityController listener, which then touched the disposed scroll
  controller on every keyboard show/hide for the life of the process.

Co-Authored-By: Claude Fable 5.1 <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