Skip to content

feat: Show torrent count for each filter state in drawer (#109)#196

Open
ananyaaa66 wants to merge 1 commit intoCCExtractor:mainfrom
ananyaaa66:fix/issue-109-filter-counts
Open

feat: Show torrent count for each filter state in drawer (#109)#196
ananyaaa66 wants to merge 1 commit intoCCExtractor:mainfrom
ananyaaa66:fix/issue-109-filter-counts

Conversation

@ananyaaa66
Copy link
Copy Markdown

@ananyaaa66 ananyaaa66 commented Mar 31, 2026

Closes #109

Summary

Shows the count of torrents for each filter state (All, Downloading, Completed, Active, Inactive, Error) as a badge next to each filter tile in the drawer, matching the ruTorrent web interface behavior.

Changes

  • torrent_service.dart: Added getFilterCount(Filter) method that reuses the existing _filterList() logic to return the count
    • drawer_viewmodel.dart: Exposed getFilterCount() via the DrawerViewModel
    • filter_tile_list_widgets.dart: Added a trailing count badge with themed styling to each FilterTile
      The count updates reactively as torrents change state (download, complete, error, etc.).

Summary by CodeRabbit

  • New Features
    • Filter tiles now display the count of matching torrents as a trailing badge. The badge styling adapts based on selection state to maintain visual clarity across different filter categories.

…#109)

- Add getFilterCount() to TorrentService reusing existing _filterList logic
- Expose filter count in DrawerViewModel
- Add trailing count badge to FilterTile widget with themed styling
- Count updates reactively as torrents change state

Closes CCExtractor#109
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 31, 2026

📝 Walkthrough

Walkthrough

This change adds filter count display functionality to the app's drawer. A new getFilterCount() method is introduced across the service and view model layers to compute matching torrents per filter, and the UI is updated to render these counts as styled trailing widgets in filter tiles.

Changes

Cohort / File(s) Summary
Service Layer
lib/services/state_services/torrent_service.dart
Added public getFilterCount(Filter filter) method that delegates to internal _filterList() and returns the count of matching torrents, defaulting to 0 when null.
ViewModel Layer
lib/ui/widgets/smart_widgets/drawer/drawer_viewmodel.dart
Added public getFilterCount(Filter filter) method as a null-safe wrapper that delegates to the torrent service.
UI Rendering
lib/ui/widgets/dumb_widgets/filter_tile_list_widgets.dart
Modified FilterTile.build() to compute and display filter counts as styled trailing widgets in ListTiles, with opacity and color adjustments based on selection state.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A counter's delight, so neat and divine,
Each filter now shows its torrent count line,
No more shall we guess what downloads await,
The drawer reveals them—how simply ornate!
From service to view, the logic flows free,

🚥 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 PR title clearly and concisely summarizes the main change: adding torrent count display for each filter state in the drawer, which directly matches the primary objective.
Linked Issues check ✅ Passed The PR implements all coding requirements from #109: getFilterCount() method in TorrentService, delegation through DrawerViewModel, and count display with styling in FilterTile.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implement filter count display: the new getFilterCount() method, its delegation through DrawerViewModel, and the trailing count badge UI in FilterTile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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)
lib/ui/widgets/dumb_widgets/filter_tile_list_widgets.dart (1)

40-47: Consider a minimum width for visual consistency (optional).

The badge width varies with digit count. For consistent alignment across filter tiles, you could add a minimum width constraint:

💡 Optional: Add minimum width
         trailing: Container(
           padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2),
+          constraints: BoxConstraints(minWidth: 28),
           decoration: BoxDecoration(
             color: isSelected
                 ? Colors.white.withOpacity(0.3)
                 : Theme.of(context).colorScheme.secondary.withOpacity(0.15),
             borderRadius: BorderRadius.circular(12),
           ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/ui/widgets/dumb_widgets/filter_tile_list_widgets.dart` around lines 40 -
47, The badge Container in the trailing of the filter tile (the Container with
padding, decoration and color used when isSelected) should get a minimum width
to keep badges visually consistent across digit counts; update that Container
(in filter_tile_list_widgets) to include constraints: BoxConstraints(minWidth:
<value>) and keep its existing padding, and ensure child alignment (e.g., Center
or alignment: Alignment.center) so single-digit badges remain centered — adjust
the minWidth value to match your design (e.g., ~28–36) for consistent alignment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/ui/widgets/smart_widgets/drawer/drawer_viewmodel.dart`:
- Around line 50-53: DrawerViewModel currently reads counts synchronously via
getFilterCount and never subscribes to TorrentService, so counts won’t update
while the drawer is open; fix by subscribing to TorrentService changes in
DrawerViewModel.init() (e.g., listen to TorrentService.torrentsList or its
change stream) and call notifyListeners() when the list or filter counts change,
and remove the listener in dispose(), or alternatively change the UI side by
wrapping FilterTile’s count display in a ValueListenableBuilder (or
StreamBuilder) bound to TorrentService.torrentsList so the count updates
reactively; reference methods/classes: DrawerViewModel.init(), getFilterCount(),
notifyListeners(), TorrentService.torrentsList, and FilterTile.

---

Nitpick comments:
In `@lib/ui/widgets/dumb_widgets/filter_tile_list_widgets.dart`:
- Around line 40-47: The badge Container in the trailing of the filter tile (the
Container with padding, decoration and color used when isSelected) should get a
minimum width to keep badges visually consistent across digit counts; update
that Container (in filter_tile_list_widgets) to include constraints:
BoxConstraints(minWidth: <value>) and keep its existing padding, and ensure
child alignment (e.g., Center or alignment: Alignment.center) so single-digit
badges remain centered — adjust the minWidth value to match your design (e.g.,
~28–36) for consistent alignment.
🪄 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: 9ade8dfa-ccdf-41ff-b702-f746fbb35f10

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa8364 and 608a0ca.

📒 Files selected for processing (3)
  • lib/services/state_services/torrent_service.dart
  • lib/ui/widgets/dumb_widgets/filter_tile_list_widgets.dart
  • lib/ui/widgets/smart_widgets/drawer/drawer_viewmodel.dart

Comment on lines +50 to +53
/// Returns the count of torrents matching a given [Filter]
int getFilterCount(Filter filter) {
return _torrentService?.getFilterCount(filter) ?? 0;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if DrawerViewModel subscribes to TorrentService changes anywhere
rg -n "addListener|listen" lib/ui/widgets/smart_widgets/drawer/

# Check how drawer is used and if it rebuilds on torrent changes
rg -n -A 5 "DrawerViewModel" lib/ui/widgets/smart_widgets/drawer/

Repository: CCExtractor/rutorrent-flutter

Length of output: 1795


🏁 Script executed:

# Check DrawerViewModel.init() and full implementation
head -80 lib/ui/widgets/smart_widgets/drawer/drawer_viewmodel.dart

Repository: CCExtractor/rutorrent-flutter

Length of output: 3231


🏁 Script executed:

# Check FilterTile implementation and how it uses getFilterCount
fd -t f "filter_tile" lib/ --exec cat -n {} \;

Repository: CCExtractor/rutorrent-flutter

Length of output: 3785


🏁 Script executed:

# Check if BaseViewModel or TorrentService have built-in change propagation
rg -n "class BaseViewModel|class TorrentService" lib/

Repository: CCExtractor/rutorrent-flutter

Length of output: 170


Counts will not update live while the drawer is open, contradicting the PR's claimed reactive behavior.

The getFilterCount method reads synchronously without subscribing to TorrentService changes. DrawerViewModel doesn't listen to TorrentService (neither in init() nor elsewhere), so it won't call notifyListeners() when torrents change. FilterTile is a StatelessWidget that reads the count once at build time without any reactive wrapper, so the displayed count will only refresh when the drawer is reopened, not while it remains open and torrent states change.

To match the PR's description of reactive updates, DrawerViewModel should:

  1. Listen to TorrentService changes in init() and call notifyListeners() when the torrent list or filter counts change, or
  2. Wrap the count display in FilterTile with ValueListenableBuilder on TorrentService.torrentsList
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/ui/widgets/smart_widgets/drawer/drawer_viewmodel.dart` around lines 50 -
53, DrawerViewModel currently reads counts synchronously via getFilterCount and
never subscribes to TorrentService, so counts won’t update while the drawer is
open; fix by subscribing to TorrentService changes in DrawerViewModel.init()
(e.g., listen to TorrentService.torrentsList or its change stream) and call
notifyListeners() when the list or filter counts change, and remove the listener
in dispose(), or alternatively change the UI side by wrapping FilterTile’s count
display in a ValueListenableBuilder (or StreamBuilder) bound to
TorrentService.torrentsList so the count updates reactively; reference
methods/classes: DrawerViewModel.init(), getFilterCount(), notifyListeners(),
TorrentService.torrentsList, and FilterTile.

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.

Count of States is not shown in the drawer filters

1 participant