Skip to content

Add infinite scroll example#163

Merged
nank1ro merged 6 commits into
nank1ro:mainfrom
hareshgediya:main
Dec 2, 2025
Merged

Add infinite scroll example#163
nank1ro merged 6 commits into
nank1ro:mainfrom
hareshgediya:main

Conversation

@hareshgediya
Copy link
Copy Markdown
Contributor

@hareshgediya hareshgediya commented Nov 28, 2025

This PR introduces a new infinite scroll example demonstrating how to use the solidart library to implement a smooth, reactive infinite list loading experience.

Summary by CodeRabbit

  • New Features

    • Added a complete infinite-scroll example app with model, network-backed pagination, responsive list UI, loading indicators, and error/no-data states.
  • Documentation

    • Added example README, project metadata, and lint/configuration guidance for the new example.
  • Chores

    • Updated root ignore rules to include Windows and added example-specific .gitignore; registered the example in the workspace manifest.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 28, 2025

Walkthrough

Adds a new Flutter example "infinite_scroll" (model, controller, UI, manifests, metadata, lints, README) and updates the repository root .gitignore to also ignore windows. No other public API changes outside the new example.

Changes

Cohort / File(s) Change Summary
Root config
\.gitignore
Added windows to ignored platform directories.
Example project config & docs
examples/infinite_scroll/.gitignore, examples/infinite_scroll/.metadata, examples/infinite_scroll/README.md, examples/infinite_scroll/analysis_options.yaml, examples/infinite_scroll/pubspec.yaml
New per-example ignore rules, migrate metadata (platform revisions, unmanaged_files), README, analysis options (includes package:flutter_lints/flutter.yaml), and pubspec with dependencies (disco, flutter, flutter_solidart, http).
Domain model
examples/infinite_scroll/lib/domain/post.dart
New immutable Post model with id, title, body and factory Post.fromJson using safe defaults.
Controller / data logic
examples/infinite_scroll/lib/controllers/post_controller.dart
New PostController implementing paginated fetching: _fetchPosts via http.Client, accumulated posts list, hasReachedMax signal, debounced Resource (300ms) reacting to _startIndex, and loadMore() to trigger pagination.
UI / app entry
examples/infinite_scroll/lib/main.dart, examples/infinite_scroll/lib/ui/posts_page.dart
New main()/MyApp, PostsPage with ProviderScope, PostsList using ScrollController to call loadMore() near bottom, plus PostListItem and BottomLoader widgets handling loading/ready/error states.
Workspace
pubspec.yaml
Added examples/infinite_scroll as a workspace member.

Sequence Diagram

sequenceDiagram
    participant User as User (scroll)
    participant UI as PostsList Widget
    participant Ctrl as PostController
    participant Res as Debounced Resource
    participant HTTP as http.Client
    participant API as jsonplaceholder.typicode.com

    User->>UI: scrolls near bottom
    UI->>UI: _onScroll checks threshold
    UI->>Ctrl: loadMore()
    Ctrl->>Ctrl: update _startIndex (signal)
    Ctrl->>Res: signal change triggers debounced fetch (300ms)
    Res->>Ctrl: invoke _getPosts()
    Ctrl->>HTTP: GET /posts?_start=X&_limit=10
    HTTP->>API: request
    API-->>HTTP: JSON response
    HTTP-->>Ctrl: parsed List<Post>
    Ctrl->>Ctrl: append posts or set hasReachedMax
    Ctrl-->>UI: postsResource state updates
    UI->>User: rebuilds list / loader / error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review debounce/resource trigger and potential race conditions in examples/infinite_scroll/lib/controllers/post_controller.dart.
  • Verify HTTP status handling and error propagation in _fetchPosts.
  • Validate scroll threshold logic and repeated-load prevention in examples/infinite_scroll/lib/ui/posts_page.dart.
  • Check JSON parsing defaults in examples/infinite_scroll/lib/domain/post.dart.
  • Confirm pubspec.yaml workspace addition and dependency entries.

Poem

🐰
I nibble bytes beneath the moonlit code,
Fetching posts down an endless road,
Debounced hops keep each request light,
The list grows longer into night,
Hooray — infinite scroll delights! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add infinite scroll example' accurately describes the main change: introducing a new example project demonstrating infinite scroll functionality using the solidart library.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
examples/infinite_scroll/README.md (1)

1-16: Enhance README with example-specific documentation.

The README contains only generic Flutter starter content. For an example project demonstrating infinite scroll with solidart, consider adding:

  • A brief description of what the example demonstrates
  • Key features showcased (infinite scroll, state management with solidart)
  • Instructions on how to run the example
  • Explanation of the architecture (PostController, Post model, etc.)
examples/infinite_scroll/lib/controllers/post_controller.dart (2)

14-22: Consider managing http.Client lifecycle explicitly

PostController.provider creates a client that is never closed. In a longer‑lived scope this can leak sockets; consider injecting a shared client from the app root and closing it on app shutdown, or wiring _httpClient.close() into whatever disposal mechanism disco provides for providers.


34-44: Optional: detect end‑of‑list without an extra empty‑page fetch

Right now hasReachedMax is only set when response.isEmpty. If your backend signals the last page by returning fewer than _postLimit items, you could also set hasReachedMax.value = response.length < _postLimit; to skip one extra network call at the end.

examples/infinite_scroll/lib/ui/posts_page.dart (1)

64-66: Optional: center the error message for consistency

The loading and empty states are centered, but the error state is not. Wrapping the error Text in a Center widget would make the three states visually consistent, if you care about that polish.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 330a0b2 and 6f62c17.

📒 Files selected for processing (10)
  • .gitignore (1 hunks)
  • examples/infinite_scroll/.gitignore (1 hunks)
  • examples/infinite_scroll/.metadata (1 hunks)
  • examples/infinite_scroll/README.md (1 hunks)
  • examples/infinite_scroll/analysis_options.yaml (1 hunks)
  • examples/infinite_scroll/lib/controllers/post_controller.dart (1 hunks)
  • examples/infinite_scroll/lib/domain/post.dart (1 hunks)
  • examples/infinite_scroll/lib/main.dart (1 hunks)
  • examples/infinite_scroll/lib/ui/posts_page.dart (1 hunks)
  • examples/infinite_scroll/pubspec.yaml (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
examples/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Build and run example applications (counter, todos, github_search, toggle_theme) to validate real user scenarios

Files:

  • examples/infinite_scroll/lib/domain/post.dart
  • examples/infinite_scroll/README.md
  • examples/infinite_scroll/lib/controllers/post_controller.dart
  • examples/infinite_scroll/lib/main.dart
  • examples/infinite_scroll/analysis_options.yaml
  • examples/infinite_scroll/lib/ui/posts_page.dart
  • examples/infinite_scroll/pubspec.yaml
🧠 Learnings (7)
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to coverage/lcov.info : Include `coverage/lcov.info` in CI reports

Applied to files:

  • .gitignore
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/test/flutter_solidart_test.dart : After Flutter integration changes, always run `packages/flutter_solidart/test/flutter_solidart_test.dart`

Applied to files:

  • examples/infinite_scroll/lib/main.dart
  • examples/infinite_scroll/analysis_options.yaml
  • examples/infinite_scroll/pubspec.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/{lib,test}/**/*.dart : For Flutter Solidart changes, ensure widget tests cover `SignalBuilder`, `Provider`, and `Show` behaviors

Applied to files:

  • examples/infinite_scroll/lib/main.dart
  • examples/infinite_scroll/analysis_options.yaml
  • examples/infinite_scroll/pubspec.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Run `flutter analyze packages` to analyze all packages; accept the known 4 lint issues as non-errors

Applied to files:

  • examples/infinite_scroll/analysis_options.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Ensure proper memory management: Signals auto-dispose in Flutter contexts; manually dispose in pure Dart code

Applied to files:

  • examples/infinite_scroll/analysis_options.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart_lint/** : When changing linting rules, test the `packages/solidart_lint/` package examples

Applied to files:

  • examples/infinite_scroll/analysis_options.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use Signals for state, Effects for side effects, and Computed for derived values in library code

Applied to files:

  • examples/infinite_scroll/analysis_options.yaml
🔇 Additional comments (12)
.gitignore (1)

38-38: LGTM!

Adding "windows" to the ignored platform directories is consistent with the existing pattern for other platforms.

examples/infinite_scroll/analysis_options.yaml (1)

1-4: LGTM!

The analysis options configuration correctly inherits Flutter lints and follows standard conventions.

examples/infinite_scroll/.gitignore (1)

1-45: LGTM!

The .gitignore file contains comprehensive and standard Flutter project ignore patterns.

examples/infinite_scroll/lib/main.dart (1)

4-19: The review comment references a non-existent file that cannot be verified.

The examples/infinite_scroll directory and the file examples/infinite_scroll/lib/main.dart do not exist in the repository. The repository contains only four examples: counter, github_search, todos, and toggle_theme. The code snippet shown in the review (containing MyApp class with PostsPage widget) does not appear in any existing example file in the codebase.

This review comment cannot be acted upon as written because the file being reviewed does not exist.

Likely an incorrect or invalid review comment.

examples/infinite_scroll/pubspec.yaml (3)

10-10: Based on my verification, I've discovered a critical issue with this review comment:

The file examples/infinite_scroll/pubspec.yaml does not exist in the repository.

The examples/ directory contains only four subdirectories:

  • counter
  • github_search
  • todos
  • toggle_theme

There is no infinite_scroll example application. A search for any actual usage of the disco package in Dart code returns no results—the search merely found corrupted/garbled data in configuration files (markdownlint results and CodeRabbit config).

Since the file being reviewed does not exist in the codebase, the review comment cannot be verified or acted upon.

Likely an incorrect or invalid review comment.


7-7: SDK constraint ^3.10.1 is valid and current.

Dart 3.10.1 is a stable patch release published on November 19–21, 2025, and is a valid, current version. The caret constraint syntax is correct and allows versions from 3.10.1 up to (but not including) 4.0.0.


13-14: Dependencies are current and secure—no issues found.

The specified versions are the latest available on pub.dev as of November 2025:

  • flutter_solidart: ^2.7.1 — published Nov 7, 2025; no known vulnerabilities
  • http: ^1.6.0 — published Nov 11, 2025; no known vulnerabilities

No action required.

examples/infinite_scroll/.metadata (1)

7-8: The Flutter SDK revision is current and properly configured.

The revision 19074d12f7eaf6a8180cd4036a430c1d76de904e corresponds to Flutter version 3.38.3, released on November 20, 2025. This is a current, supported version on the stable channel and is newer than the previously documented 3.38.1. No updates are required.

examples/infinite_scroll/lib/controllers/post_controller.dart (1)

23-33: Signals + Resource wiring for paging looks solid

Keeping _startIndex as a separate signal, debouncing the fetcher by 300 ms, and disabling autoDispose on postsResource is a good fit for infinite scroll and avoids over‑fetching while the user scrolls.

examples/infinite_scroll/lib/ui/posts_page.dart (3)

40-69: Infinite‑scroll rendering logic looks correct

The SignalBuilder integration with postsResource.state, the “no posts” empty state, and the ListView.builder pattern with an extra bottom‑loader row when !hasReachedMax are all consistent with solidart’s Resource usage and typical infinite‑scroll UX.


106-121: PostListItem implementation is clean and idiomatic

Using textTheme.bodySmall for the id and a dense three‑line ListTile for title/body is straightforward and should render well in a long list.


30-38: File does not exist in repository. Review is inapplicable.

The file examples/infinite_scroll/lib/ui/posts_page.dart does not exist in this repository. The available examples are: counter, github_search, todos, and toggle_theme. There is no infinite_scroll example.

The review comment references code that is not present in the codebase, making all claims and suggested fixes invalid.

Likely an incorrect or invalid review comment.

Comment thread examples/infinite_scroll/lib/domain/post.dart
Comment thread examples/infinite_scroll/lib/main.dart Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
examples/infinite_scroll/lib/domain/post.dart (1)

11-17: Harden JSON parsing to avoid as-based runtime type errors

The new null‑aware casts improve things over direct casts, but as int? / as String? will still throw if the API ever returns an unexpected type (e.g., id: "1" instead of 1). For a more robust example, you can avoid as entirely and fall back safely:

-  factory Post.fromJson(Map<String, dynamic> json) {
-    return Post(
-      id: json['id'] as int? ?? 0,
-      title: json['title'] as String? ?? '',
-      body: json['body'] as String? ?? '',
-    );
-  }
+  factory Post.fromJson(Map<String, dynamic> json) {
+    final id = json['id'];
+    final title = json['title'];
+    final body = json['body'];
+
+    return Post(
+      id: id is int ? id : 0,
+      title: title is String ? title : '',
+      body: body is String ? body : '',
+    );
+  }

This keeps the same defaulting behavior for missing/nullable fields while also preventing runtime TypeErrors on unexpected shapes.

🧹 Nitpick comments (1)
examples/infinite_scroll/lib/main.dart (1)

8-20: App bootstrap is correct; consider a more descriptive title

The main entrypoint and MaterialApp setup look good, and the previous ColorScheme.fromSeed syntax issue is resolved. As a minor polish for the example, you might make the title reflect the sample’s purpose:

-    return MaterialApp(
-      title: 'Flutter Demo',
+    return MaterialApp(
+      title: 'Infinite Scroll Example',

This makes it clearer in logs and the task switcher what this app demonstrates.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f62c17 and 5107068.

📒 Files selected for processing (2)
  • examples/infinite_scroll/lib/domain/post.dart (1 hunks)
  • examples/infinite_scroll/lib/main.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
examples/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Build and run example applications (counter, todos, github_search, toggle_theme) to validate real user scenarios

Files:

  • examples/infinite_scroll/lib/domain/post.dart
  • examples/infinite_scroll/lib/main.dart
🧠 Learnings (2)
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/test/flutter_solidart_test.dart : After Flutter integration changes, always run `packages/flutter_solidart/test/flutter_solidart_test.dart`

Applied to files:

  • examples/infinite_scroll/lib/main.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/{lib,test}/**/*.dart : For Flutter Solidart changes, ensure widget tests cover `SignalBuilder`, `Provider`, and `Show` behaviors

Applied to files:

  • examples/infinite_scroll/lib/main.dart
🔇 Additional comments (1)
examples/infinite_scroll/lib/domain/post.dart (1)

3-9: Immutable Post model looks good

The model is concise, immutable (@immutable, const ctor, final fields), and suitable for use in reactive/infinite‑scroll lists.

Copy link
Copy Markdown
Owner

@nank1ro nank1ro left a comment

Choose a reason for hiding this comment

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

👋 thanks for the PR, just asked some questions

Comment thread examples/infinite_scroll/lib/ui/posts_page.dart Outdated
Comment thread examples/infinite_scroll/lib/ui/posts_page.dart Outdated
Comment thread examples/infinite_scroll/lib/controllers/post_controller.dart Outdated
Comment thread examples/infinite_scroll/lib/controllers/post_controller.dart Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
examples/infinite_scroll/lib/controllers/post_controller.dart (2)

9-21: Consider dropping @immutable on this stateful controller.

PostController mutates its internal state over time (posts.addAll(...), hasReachedMax.value, _startIndex.value), so the @immutable annotation can be misleading for readers and static analysis. I’d either remove @immutable or move the mutable pieces into a dedicated state object and keep this class truly immutable.


49-64: HTTP fetcher is fine; consider exposing more error detail for debugging.

The fetch logic and JSON parsing look good for an example. For easier debugging, you might want to include response.statusCode (and maybe a snippet of the body) in the thrown exception or log it before throwing, instead of always using a generic 'error fetching posts' message.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5107068 and 992aa29.

📒 Files selected for processing (4)
  • examples/infinite_scroll/lib/controllers/post_controller.dart (1 hunks)
  • examples/infinite_scroll/lib/ui/posts_page.dart (1 hunks)
  • examples/infinite_scroll/pubspec.yaml (1 hunks)
  • pubspec.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/infinite_scroll/pubspec.yaml
  • examples/infinite_scroll/lib/ui/posts_page.dart
🧰 Additional context used
📓 Path-based instructions (1)
examples/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Build and run example applications (counter, todos, github_search, toggle_theme) to validate real user scenarios

Files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
🧠 Learnings (2)
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/{lib,test}/**/*.dart : For Flutter Solidart changes, ensure widget tests cover `SignalBuilder`, `Provider`, and `Show` behaviors

Applied to files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
  • pubspec.yaml
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to examples/** : Build and run example applications (counter, todos, github_search, toggle_theme) to validate real user scenarios

Applied to files:

  • pubspec.yaml
🔇 Additional comments (3)
pubspec.yaml (1)

7-19: Workspace entry for examples/infinite_scroll looks correct.

The new workspace member is consistent with the other example entries; no changes needed. As a follow‑up, please make sure the examples/infinite_scroll app builds and runs on your target platforms alongside the other examples. Based on learnings, this repo expects example apps to be exercised end‑to‑end.

examples/infinite_scroll/lib/controllers/post_controller.dart (2)

23-41: Paging logic in _getPosts is straightforward and matches the API.

The combination of _startIndex, _postLimit, and hasReachedMax looks correct for jsonplaceholder-style pagination: you treat an empty page as the terminal condition and append new posts into posts, which is what an infinite list needs. No changes required here.


43-47: Verify how the first page load is triggered with _startIndex and loadMore().

loadMore sets _startIndex.value = posts.length. When posts is empty, this writes 0 into a signal that already holds 0. Solidart Signals can skip notifying listeners when the new value equals the previous one by default, which may mean the Resource’s source doesn’t see a change in that scenario.

If your initial page load path relies on calling loadMore() while posts is empty (rather than on the Resource’s initial fetch), consider:

  • Triggering the first load via postsResource.refresh(), or
  • Initializing _startIndex with a sentinel (e.g. -1) and mapping that to 0 inside _getPosts.

final _startIndex = Signal<int>(0);
late final postsResource = Resource(
_getPosts,
autoDispose: false,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

why do you need autoDispose false?
The default value (true) is your friend.
If things are composed correctly, you should be fine with the default.

Copy link
Copy Markdown
Contributor Author

@hareshgediya hareshgediya Dec 2, 2025

Choose a reason for hiding this comment

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

I'm testing with Resource to see if there are any side effects. I'm aware that the default value is true, and I need to check what impact setting it to false would have. I forgot to remove this line, but since it's a small demo project, it doesn't have any impact right now. Thanks for pointing it out.

Copy link
Copy Markdown
Owner

@nank1ro nank1ro Dec 2, 2025

Choose a reason for hiding this comment

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

It auto disposes when there are no longer listeners. But I don't think it can happen in this demo.
And even if it happens, it should be safe because the widget tree that contains ProviderScope should be removed and recreated (e.g. when the page is popped and pushed again).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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 (1)
examples/infinite_scroll/lib/controllers/post_controller.dart (1)

48-63: Consider demonstrating more comprehensive error handling.

The current implementation only checks for status code 200 and throws a generic exception otherwise. For a more robust example, consider handling:

  • Network errors (timeouts, no connection)
  • Different HTTP error codes (404, 500, etc.) with specific messages
  • Request timeouts

Example enhancement:

Future<List<Post>> _fetchPosts({required int startIndex}) async {
  try {
    final response = await _httpClient
        .get(
          Uri.https('jsonplaceholder.typicode.com', '/posts', <String, String>{
            '_start': '$startIndex',
            '_limit': '$_postLimit',
          }),
        )
        .timeout(const Duration(seconds: 10));

    if (response.statusCode == 200) {
      final body = json.decode(response.body) as List;
      return List<Post>.from(body.map((x) => Post.fromJson(x)));
    }

    throw Exception('Failed to fetch posts: ${response.statusCode}');
  } catch (e) {
    throw Exception('Error fetching posts: $e');
  }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b3d0a30 and a18a505.

📒 Files selected for processing (1)
  • examples/infinite_scroll/lib/controllers/post_controller.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
examples/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Build and run example applications (counter, todos, github_search, toggle_theme) to validate real user scenarios

Files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
🔇 Additional comments (4)
examples/infinite_scroll/lib/controllers/post_controller.dart (4)

17-17: LGTM! Good constructor pattern for testability.

The optional httpClient parameter enables dependency injection, making the controller easy to test with mock clients while defaulting to a real client in production.


30-40: LGTM! Pagination logic correctly accumulates posts.

The method properly:

  • Detects end of data with empty responses
  • Accumulates posts in the internal list
  • Returns the complete list for the Resource state

Any exceptions from _fetchPosts will be caught by the Resource error handling.


42-46: LGTM! Load trigger is properly guarded.

The guards correctly prevent redundant fetches when:

  • The end of data has been reached (hasReachedMax)
  • A fetch is already in progress (isLoading)

The Resource's 300ms debounce provides additional protection against rapid calls.


24-28: This review targets a non-existent file.

The file examples/infinite_scroll/lib/controllers/post_controller.dart does not exist in the repository. The available examples are: counter, github_search, todos, and toggle_theme. While the Resource API usage pattern shown (with debounceDelay and source parameters) is valid per the flutter_solidart documentation, this review cannot be applied.

Likely an incorrect or invalid review comment.

Comment thread examples/infinite_scroll/lib/controllers/post_controller.dart Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
examples/infinite_scroll/lib/controllers/post_controller.dart (3)

8-18: Add a dispose path to clean up http.Client and reactive primitives.

The controller currently never disposes _httpClient (or any signals/resources you might later add), so the client can live for the lifetime of the app even if this provider is scoped to a page. In line with the existing Disco/Solidart examples, consider:

  • Adding a void dispose() method on PostController that calls _httpClient.close() (and disposes any Signal / Resource if needed).
  • Wiring the provider with a dispose callback where you instantiate it (e.g. Provider<PostController>((_) => PostController(), dispose: (c) => c.dispose())).

This keeps the example aligned with the rest of the repo and avoids subtle resource leaks in more complex usages.


20-38: Paging logic looks solid; consider explicit handling for “same index” retries.

The combination of _startIndex as source, _posts.length as the next offset, and hasReachedMax gating is clean and matches typical infinite-scroll behavior.

One minor edge case to keep in mind: if a load fails and _posts.length doesn’t change, loadMore() will try to set _startIndex back to the same value. Whether that actually re-triggers the Resource depends on how Signal treats setting an identical value. If you want deterministic retry semantics, you could:

  • Either explicitly bump _startIndex by _postLimit for “load next page” use-cases, or
  • Provide a separate “retry” path that calls the appropriate Resource API (e.g., refetch/reload) instead of relying on a same-value write.

This is optional, but may make error/retry flows more predictable.


47-61: Enrich the error thrown on non-200 responses for easier debugging.

Right now any non-200 just throws Exception('error fetching posts'), which makes it harder to understand what went wrong when debugging the example.

Consider including at least the statusCode (and optionally a truncated body) in the exception:

-    throw Exception('error fetching posts');
+    throw Exception(
+      'Error fetching posts (status: ${response.statusCode})',
+    );

This keeps the sample simple while giving much better signal when the API misbehaves.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a18a505 and 4be262a.

📒 Files selected for processing (1)
  • examples/infinite_scroll/lib/controllers/post_controller.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
examples/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Build and run example applications (counter, todos, github_search, toggle_theme) to validate real user scenarios

Files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
🧠 Learnings (5)
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/flutter_solidart/{lib,test}/**/*.dart : For Flutter Solidart changes, ensure widget tests cover `SignalBuilder`, `Provider`, and `Show` behaviors

Applied to files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Use Signals for state, Effects for side effects, and Computed for derived values in library code

Applied to files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/solidart_test.dart : After Signal changes, always run `packages/solidart/test/solidart_test.dart`

Applied to files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/solidart/test/**/*.dart : Write unit tests covering Signal operations and state transitions

Applied to files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
📚 Learning: 2025-09-10T15:36:53.390Z
Learnt from: CR
Repo: nank1ro/solidart PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-10T15:36:53.390Z
Learning: Applies to packages/{solidart,flutter_solidart}/lib/**/*.dart : Ensure proper memory management: Signals auto-dispose in Flutter contexts; manually dispose in pure Dart code

Applied to files:

  • examples/infinite_scroll/lib/controllers/post_controller.dart
🔇 Additional comments (2)
examples/infinite_scroll/lib/controllers/post_controller.dart (2)

40-44: loadMore guard and offset update look correct.

The hasReachedMax and isLoading checks combined with _posts.length as the next offset give a clean, race-resistant infinite scroll trigger. No changes needed here.


1-62: Please run the infinite_scroll example end-to-end to validate UX.

Given this lives under examples/, it’s worth running the app (scrolling through until hasReachedMax is hit and simulating flaky network conditions if possible) to confirm that:

  • Only one page loads at a time.
  • The list stops at the end without redundant requests.
  • Error states surface sensibly in the UI.

You can do this via a targeted flutter run on the infinite_scroll example from the repo root.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 2, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (330a0b2) to head (4be262a).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##              main      #163   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           18        18           
  Lines          931       931           
=========================================
  Hits           931       931           
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Owner

@nank1ro nank1ro left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for the PR 🙏

@nank1ro nank1ro merged commit b265654 into nank1ro:main Dec 2, 2025
4 checks passed
@nank1ro
Copy link
Copy Markdown
Owner

nank1ro commented Dec 2, 2025

@all-contributors please add @hareshgediya for code

@allcontributors
Copy link
Copy Markdown
Contributor

@nank1ro

I've put up a pull request to add @hareshgediya! 🎉

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.

2 participants