Repository navigation
MacOS startup fix, iOS service recovery and file open/share on background - #464
Closed
panfilov-vladislav wants to merge 15 commits into
Closed
panfilov-vladislav wants to merge 15 commits into
panfilov-vladislav wants to merge 15 commits into
Conversation
added 15 commits
October 20, 2026 09:05
windowManager.close() simulates a click on the native close button (performClose), which is a no-op when the window is hidden (e.g. after "Hide" from the tray menu), silently preventing the app from exiting. Run the shutdown directly instead, independent of window visibility.
PowerControl only called bindNetwork() when the computed NetworkMode changed, which is driven by connectivity_plus's connectivity *type* (wifi/mobile/none) and local interface address. Backgrounding can kill the network stack (e.g. iOS tearing down sockets) without the type ever changing, so nothing ever re-triggered bindNetwork() on resume, and the ouisync-net layer's rebind-on-death logic never got a chance to run. Observe app lifecycle and call _setNetworkMode directly (bypassing the mode-unchanged guard) on resume, so a fresh bindNetwork is always sent.
Flutter's VM service discovery over the device's local network tunnel (used by `flutter attach`/`flutter run` on physical iOS devices) relies on mDNS and the Local Network permission, which the OS won't even prompt for without these Info.plist keys declared.
ErrorCubit only ever tracked a boolean "something went wrong" flag, with no way to see what actually happened short of digging through the log file. Record the message and stack trace for each unhandled exception (capped at the last 20), and let tapping the error row in Settings > Logs open a dialog listing them, with a button to copy the text to the clipboard.
_setNetworkMode deliberately rethrows on failure for callers reacting to a user-driven mode change, but didChangeAppLifecycleState called it unguarded. Right after resuming, the connection to the backend may still be mid-reconnect, so a failure here is expected and transient; swallow it instead of letting it surface as an unhandled exception.
Most of what trips ErrorCubit in practice is a symptom of the local Client connection being dead or wedged after the app resumes from the background (dropped sockets, subscriptions that silently stopped delivering). Rather than only reacting to errors the Client already knows how to self-heal from, proactively force a reset whenever an error is recorded, debounced so a burst of errors around one disconnect triggers a single reset instead of piling up overlapping ones.
Appends the native (Rust) logs to the same file the Dart side logs to, so they show up in the app's Save/Share logs - on iOS/macOS the native side's stdout isn't otherwise captured anywhere once the app is backgrounded. Also listens for Session.serviceUnresponsive and restarts the native service (stop/start + reset the client connection) when it fires: a refused connection after several attempts means the native process/thread died outright (observed after some iOS background/foreground cycles), not just that its socket was torn down, so nothing but restarting it will recover.
Every RepoCubit holds a Repository bound to a native handle from whatever service process opened it. After the service has been fully restarted (see previous commit) rather than just having its socket momentarily drop, that handle no longer refers to anything meaningful in the new process - at best this shows as stale/empty content (the new process happens to reuse the same handle number for something else), at worst an operation on it just hangs forever (nothing is listening on the other end to ever reply). Merely re-fetching through the same stale Repository object doesn't fix this; every repo needs to be closed and reopened against the new process, which is exactly what ReposCubit._reload() already does for the "store dirs changed" case - so reuse it on Session.reconnected too.
When app startup failed, the FutureBuilder in App only checked for data, so the loading spinner stayed on screen and the cause was hidden. Log the failure under the Startup logger and show the error and stack trace on a new StartupErrorScreen instead.
madadam
requested changes
Oct 26, 2026
| // threshold within the same tick, each firing their own event - guard against the resulting | ||
| // pile-up of concurrent restarts (harmless in practice, since `server.start()` just rejects the | ||
| // extra ones with `serviceAlreadyRunning`, but there's no reason to let them race). | ||
| bool _restartingUnresponsiveService = false; |
Collaborator
There was a problem hiding this comment.
I don't like this being global. There should be only one Session instance per app anyway so putting this into _AppComponents should be sufficient. Or remove it altogether and throttle or debounce the serviceUnresponsive stream instead (stream_transform might be useful for this).
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary