A modern Flutter RSS/Atom feed reader with Material 3 UI, FlexColorScheme theming, offline caching, foreground + Workmanager background sync, local notifications, home-screen widgets, and full internationalization (English, Turkish, Spanish).
- State Management:
providerpackage with 5 providers;FeedProviderwired viaChangeNotifierProxyProvider3 - Persistence: Hive CE (
hive_ce/hive_ce_flutter) with 3 boxes - Routing: GoRouter with declarative routes + onboarding redirect
- Background work:
workmanagerfor sync when app is closed;home_widgetfor home-screen widgets
| Provider | Purpose |
|---|---|
FeedProvider |
Feed fetching, filtering, pagination, caching, notifications. Uses ChangeNotifierProxyProvider3 to depend on Subscription/Settings/Bookmark providers |
SubscriptionProvider |
Feed subscriptions, categories, custom categories with icons |
BookmarkProvider |
Saved articles with full JSON and ID set persistence |
SettingsProvider |
Theme (flexScheme), locale, cache, sync, notifications, display settings |
ArticlePageProvider |
Per-article scroll state, full-text extraction, reading progress |
FeedItem— Article/entry with JSON serialization, copyWithFeedSubscription— Feed source with url, name, category, notifications, full-text, excluded keywords
'settings'— flexScheme, themeMode, locale, cache limit, sync interval, notification settings, ad block, webview mode,hasSeenOnboarding,_boxesMigratedflag'feeds'— subscriptions, custom categories, cached items, read IDs, category icons, category order,feedValidators(etag/lastModified),bgKnownItemIds(notification baseline)'bookmarks'— Bookmarked items (JSON + ID set)
FeedService— HTTP fetch with browser UA + keep-alive client, RSS/Atom parsing viadart_rss, HTTP 304 (etag/last-modified) support, isolate-basedparseFeedBodyFullTextExtractionService— Heuristic content extraction, runs in isolate, shared 20-entry FIFO cacheNotificationService— Singleton wrapper forflutter_local_notifications, quiet hours, digest modes, launch payload → article navigationOpmlService— OPML export/import viaxmlpackageBackgroundFetchService— Workmanager dispatcher with@pragma('vm:entry-point')callback;NetworkType.connected, 15-min minimum period; baseline-diffed notificationsWidgetUpdateService— home_widget data sync (widget_latestkey, category grouping), App Groupgroup.io.devopen.dondurma, deep-linkhomewidget://article?id=<id>ImageCacheService— Article and thumbnail cache managers
/onboarding→ OnboardingScreen (redirect target untilhasSeenOnboarding)/→ HomeScreen (bottom nav: Feeds/Folders/Bookmarks/Settings)/article→ ArticleScreen (PageView with swipe navigation; receivesitems+initialIndexviastate.extra)/debug→ DebugScreen (developer utilities, hidden behind long-press on app version)
provider, hive_ce, hive_ce_flutter, http, dart_rss, html,
flutter_html, flex_color_scheme, google_fonts (Outfit),
go_router, webview_flutter, adblocker_webview,
flutter_local_notifications, workmanager, home_widget,
cached_network_image_ce, skeletonizer, share_plus, url_launcher,
file_selector, package_info_plus, xml, intl, flutter_localizations
- Swipe Gestures: Right = read/unread, Left = bookmark
- Pagination: Date-based sections (Today/Yesterday/Older),
_pageSize = 50, resets on filter/category/search change - In-App Browser: WebView with ad blocking toggle (EasyList + AdGuard) and optional DarkReader injection
- Theme: 10 FlexColorScheme schemes × 3 brightness modes (System/Light/Dark); high contrast + reduced-motion options
- Offline Banner: Shows when viewing cached content
- Background Sync: Foreground timer (configurable interval) + Workmanager when app is closed
- Full-Text Extraction: Per-feed toggle, heuristic reader-mode scraper in isolate
- Keyword Filtering: Per-feed
excludedKeywords+ global excluded keywords, regex compiled once per filter pass - Search History: MRU list capped at 10, stored in settings
- Onboarding: Multi-step flow with suggested feeds, background blobs animation
FeedProvider._hasLoadedOncegates notification dispatch — first load never triggers notificationsFeedProvider.refreshAll()coalesces concurrent requests (_refreshQueued) and limits parallel HTTP to 5 (_fetchConcurrency, semaphore)FeedProvider.filterInputsChanged(pure static gate) invalidates the filter cache only when global/per-feed keywords or bookmark IDs actually change — unrelated upstream updates don't rebuild the feed list- Categories = subscriptions' category fields +
_customCategoriesset, merged inSubscriptionProvider.categoriesgetter NotificationService.isSupportedreturnsfalseon unsupported platforms- Per-feed
excludedKeywords/fullTextEnabledfields onFeedSubscription - Browser mode:
'builtin'|'external'|'system' - App root uses
context.selectonflexScheme/themeMode/localeso unrelated settings changes don't rebuild MaterialApp sessionOnboardingBypassed(router/onboarding_state.dart) short-circuits the onboarding redirect- Localization derived from
supportedAppLanguages(EN/TR/ES); add a language via ARB file + one entry there
- Always use fallback defaults in JSON deserialization for backward compatibility
_migrateHiveBoxes()inmain.dartis a one-time migration from the legacy single'settings'box; check it when adding new'feeds'/'bookmarks'keys_manageCacheTimer()recreates timer on proxy provider updates- Category icons stored separately in Hive, assigned on first load; legacy emoji icons mapped to Material icons
- Generated localization files in
lib/l10n/app_localizations*.dart— do not edit manually NotificationService.requestPermission()andAdBlockerWebviewController.initialize()run unawaited afterrunAppAssets/Logo.pngis launcher-icon source only and must NOT be bundled (asset list coversassets/logo.ico,assets/js/)