Skip to content

Give the loading screen an escape hatch on weak connections#206

Merged
phanan merged 2 commits into
masterfrom
fix/loading-screen-weak-connection
Jul 12, 2026
Merged

Give the loading screen an escape hatch on weak connections#206
phanan merged 2 commits into
masterfrom
fix/loading-screen-weak-connection

Conversation

@phanan

@phanan phanan commented Jul 12, 2026

Copy link
Copy Markdown
Member

Problem

DataLoadingScreen ran DataProvider.init() (a single GET data) with no timeout behind an indefinite spinner. On a weak/stalling connection it could hang for minutes with no feedback and no way out — the only exit was if the request eventually errored.

Changes

  • Timeout backstop: a 30s timer falls through to the existing retry / log-out box, so it can't hang forever.
  • Feedback: after 6s still loading, a "This is taking longer than usual…" line appears under the spinner.
  • Escape hatch: when the user has downloaded songs, a View Downloads button enters offline mode (AppMode.offline → downloaded library), reusing the same path NoConnectionScreen already uses. Shown only when downloads exist.

Both timers are owned by the state and cancelled in dispose()/on navigation (replacing the un-cancellable Future.timeout), and the meaningless await on pushReplacementNamed was dropped.

Tests

data_loading_test.dart:

  • no message while the load is still fresh;
  • the message appears after the delay, with no downloads button when there are no downloads;
  • "View Downloads" appears when downloads exist, and tapping it enters offline mode and navigates.

Summary by CodeRabbit

  • New Features

    • Added progressive “still loading” messaging after ~6 seconds.
    • Added a 30-second startup timeout with an error screen and Retry.
    • Added View Downloads (when available) to continue in offline mode.
  • Bug Fixes

    • Prevents outdated initialization results from overriding a later retry.
    • Cancels pending loading/timeout timers on success, retry, or when switching to downloads.
  • Tests

    • Expanded UI tests to cover delayed messaging, timeout/error UI, failure handling, retry behavior, and stale-init race prevention.

The data-loading screen showed an indefinite spinner while GET data ran
with no timeout, so a weak connection could hang it forever with no
feedback or way out.

Now: a 30s timeout falls through to the existing retry/log-out box; after
6s of loading a "This is taking longer than usual…" message appears; and
when the user has downloaded songs, a "View Downloads" button drops them
into the offline library instead of waiting.
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5eaad8a8-6dc3-436b-89e0-3749bd1acc39

📥 Commits

Reviewing files that changed from the base of the PR and between 4cc50ab and 6628a19.

📒 Files selected for processing (3)
  • lib/ui/screens/data_loading.dart
  • test/ui/screens/data_loading_test.dart
  • test/ui/screens/data_loading_test.mocks.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/ui/screens/data_loading.dart

📝 Walkthrough

Walkthrough

DataLoadingScreen now uses timed loading and timeout states, supports retry and offline downloads navigation, and includes widget tests with generated provider mocks covering delayed messaging, errors, retry races, and offline mode.

Changes

Data loading flow

Layer / File(s) Summary
Timed loading lifecycle
lib/ui/screens/data_loading.dart
Initialization starts in initState, tracks delayed and timeout states with timers, ignores stale attempts, cancels timers, and navigates after valid successful initialization.
Loading states and offline navigation
lib/ui/screens/data_loading.dart
The screen supports retry, displays delayed-loading messaging, shows timeout errors, and navigates to MainScreen in offline mode when downloads are available.
Widget validation and provider mocks
test/ui/screens/data_loading_test.dart, test/ui/screens/data_loading_test.mocks.dart
Widget tests cover fresh and delayed loading, timeout and initialization errors, retry race handling, offline navigation, and generated provider mocks.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DataLoadingScreen
  participant DataProvider
  participant DownloadProvider
  participant AppState
  participant MainScreen
  DataLoadingScreen->>DataLoadingScreen: start initialization and timers
  DataLoadingScreen->>DataProvider: init()
  DataProvider-->>DataLoadingScreen: return result
  DataLoadingScreen->>DownloadProvider: check available downloads
  DataLoadingScreen->>AppState: set offline mode
  DataLoadingScreen->>MainScreen: navigate to MainScreen
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding timeout, retry, and offline escape options for the loading screen on weak connections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/loading-screen-weak-connection

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
lib/ui/screens/data_loading.dart (1)

59-59: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use catch (_) instead of catch (e).

The exception variable e is never used. As per coding guidelines, single-letter variable names are not permitted except for i, j, and h.

♻️ Proposed fix
-    } catch (e) {
+    } catch (_) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/ui/screens/data_loading.dart` at line 59, Update the catch clause in the
relevant error-handling flow to use an ignored exception binding, `catch (_)`,
since the caught value is not referenced. Leave the surrounding handling
unchanged.

Source: Coding guidelines

test/ui/screens/data_loading_test.dart (1)

58-99: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for timeout, retry, and error paths.

The three existing tests cover the fresh-loading window, delayed message, and View Downloads navigation. Missing scenarios:

  • 30-second timeout: pump past _loadTimeout, verify OopsBox appears with retry/log-out buttons.
  • Retry after error: complete initCompleter with an error, verify OopsBox, tap Retry, reset stub, complete new initCompleter, verify navigation to MainScreen.
  • init() throws: configure when(dataProvider.init()).thenThrow(...), verify OopsBox appears.

These cover the critical fallback paths introduced by this PR.

🧪 Example timeout test
testWidgets('shows OopsBox after the load timeout', (tester) async {
  await mount(tester, downloads: []);
  await tester.pump();
  await tester.pump(const Duration(seconds: 30));

  expect(find.text('Oops!'), findsOneWidget);
  expect(find.text('Retry'), findsOneWidget);
  expect(find.text('Log Out'), findsOneWidget);

  await settle(tester);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/ui/screens/data_loading_test.dart` around lines 58 - 99, Add widget
tests covering the missing fallback paths around the existing loading tests:
pump past _loadTimeout and verify OopsBox with Retry and Log Out; complete
initCompleter with an error, tap Retry, reset the stub, complete the new
initCompleter, and verify MainScreen navigation; configure dataProvider.init()
to throw and verify OopsBox appears. Use the existing mount, settle, and test
stubbing helpers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/ui/screens/data_loading.dart`:
- Around line 46-72: Update _loadData and _retry to track each loading attempt
with a generation/token, incrementing it when starting a retry and capturing the
current value for each init() future. Before handling success, failure, or
canceling timers, verify the captured generation is still current; ignore
results from superseded attempts while preserving the active attempt’s
navigation and error behavior.

---

Nitpick comments:
In `@lib/ui/screens/data_loading.dart`:
- Line 59: Update the catch clause in the relevant error-handling flow to use an
ignored exception binding, `catch (_)`, since the caught value is not
referenced. Leave the surrounding handling unchanged.

In `@test/ui/screens/data_loading_test.dart`:
- Around line 58-99: Add widget tests covering the missing fallback paths around
the existing loading tests: pump past _loadTimeout and verify OopsBox with Retry
and Log Out; complete initCompleter with an error, tap Retry, reset the stub,
complete the new initCompleter, and verify MainScreen navigation; configure
dataProvider.init() to throw and verify OopsBox appears. Use the existing mount,
settle, and test stubbing helpers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 427c2d98-3405-445b-a4b7-e3c70337918d

📥 Commits

Reviewing files that changed from the base of the PR and between 834d0b9 and 4cc50ab.

📒 Files selected for processing (3)
  • lib/ui/screens/data_loading.dart
  • test/ui/screens/data_loading_test.dart
  • test/ui/screens/data_loading_test.mocks.dart

Comment thread lib/ui/screens/data_loading.dart
Address review: a load attempt now carries a generation so a stale init()
future (e.g. one that resolves after the timeout fired and the user hit
Retry) can't navigate or re-error over a newer attempt. Also use
catch (_), and add tests for the timeout, failure, and retry paths
(including the stale-future case).
@phanan phanan merged commit 9defe28 into master Jul 12, 2026
2 checks passed
@phanan phanan deleted the fix/loading-screen-weak-connection branch July 12, 2026 19:35
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