Skip to content

fix(mobile): perpetual spinner after launching without connectivity#1867

Draft
brow wants to merge 5 commits into
mainfrom
tomb/bot-1305-mobile-offline-state
Draft

fix(mobile): perpetual spinner after launching without connectivity#1867
brow wants to merge 5 commits into
mainfrom
tomb/bot-1305-mobile-offline-state

Conversation

@brow

@brow brow commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

What changed?

  • Fail relay handshakes after 10 seconds, close timed-out sockets, and keep live connections healthy with a 30-second ping interval.
  • Bound automatic reconnects at five attempts, preserve the terminal error, and reset the retry budget for explicit, resume, and connectivity-restored reconnects.
  • Show actionable network/authentication offline states and cached-content banners with working Retry actions instead of indefinite spinners.

Why?

A blackholed relay connection could leave mobile launch waiting forever, while authentication rejection could produce a blank screen. These changes make relay failures bounded, visible, and recoverable without relaunching the app.

Before / After

All images below are genuine captures from the same authenticated iOS Simulator with the relay made unreachable.

Before — current main

The app remains indefinitely in the reconnecting state with no recovery action.

Current main remains indefinitely in the reconnecting state

After — terminal offline state

After five bounded reconnect attempts, the app explains how to recover and provides Retry.

Terminal offline state with Retry

After — cached channel state

Cached content remains readable and a persistent Connection lost — Retry action is available.

Cached channel remains readable with Connection lost and Retry

How is it tested?

Flutter analysis and the full mobile suite (463 passed, 1 skipped).

Added tests:

Deep dual pre-review completed in three rounds with no remaining actionable findings.

npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e added 5 commits July 14, 2026 11:42
Fail fast when the relay handshake stalls, stop reconnecting after the bounded attempt budget, and provide actionable retry UI for terminal network and authentication failures.\n\nValidated with flutter analyze and the full mobile test suite.

Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Ensure interrupted authentication completes, fully reload channels after terminal recovery, avoid exposing raw connection errors, and distinguish auth rejection in cached banners.

Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Avoid duplicate disconnect callbacks during authentication and invalidate deliberate reconnect callbacks before replacing the socket.

Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Assert that a stream closure during NIP-42 authentication produces exactly one disconnect callback.

Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Cover both clean stream closure and stream errors during authentication, with bounded waits and socket-close assertions.

Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e <e18f3511303812c437d487ac4bf46ad897dc46946699b18ab2e60bf8ee0ea851@sprout-oss.stage.blox.sqprod.co>
@brow

brow commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@brow

brow commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

@builderbot review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@brow brow changed the title fix(mobile): bound relay reconnects and show offline state fix(mobile): perpetual spinner on connectivity error Jul 14, 2026
@brow brow changed the title fix(mobile): perpetual spinner on connectivity error fix(mobile): perpetual spinner after launching without connectivity Jul 14, 2026
brow pushed a commit that referenced this pull request Jul 15, 2026
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