diff --git a/packages/neon/neon_news/lib/dialogs/add_feed.dart b/packages/neon/neon_news/lib/dialogs/add_feed.dart index e5b1839f..d5569588 100644 --- a/packages/neon/neon_news/lib/dialogs/add_feed.dart +++ b/packages/neon/neon_news/lib/dialogs/add_feed.dart @@ -2,12 +2,10 @@ part of '../neon_news.dart'; class NewsAddFeedDialog extends StatefulWidget { const NewsAddFeedDialog({ - required this.bloc, this.folderID, super.key, }); - final NewsBloc bloc; final int? folderID; @override @@ -17,6 +15,7 @@ class NewsAddFeedDialog extends StatefulWidget { class _NewsAddFeedDialogState extends State { final formKey = GlobalKey(); final controller = TextEditingController(); + late NewsBloc bloc; NextcloudNewsFolder? folder; @@ -30,6 +29,7 @@ class _NewsAddFeedDialogState extends State { void initState() { super.initState(); + bloc = Provider.of(context, listen: false); unawaited( Clipboard.getData(Clipboard.kTextPlain).then((final clipboardContent) { if (clipboardContent != null && clipboardContent.text != null) { @@ -44,7 +44,7 @@ class _NewsAddFeedDialogState extends State { @override Widget build(final BuildContext context) => ResultBuilder>( - stream: widget.bloc.folders, + stream: bloc.folders, builder: (final context, final folders) => NeonDialog( title: Text(AppLocalizations.of(context).feedAdd), children: [ @@ -69,7 +69,7 @@ class _NewsAddFeedDialogState extends State { Center( child: NeonException( folders.error, - onRetry: widget.bloc.refresh, + onRetry: bloc.refresh, ), ), Center( diff --git a/packages/neon/neon_news/lib/pages/article.dart b/packages/neon/neon_news/lib/pages/article.dart index eaa2d232..d4136127 100644 --- a/packages/neon/neon_news/lib/pages/article.dart +++ b/packages/neon/neon_news/lib/pages/article.dart @@ -3,7 +3,6 @@ part of '../neon_news.dart'; class NewsArticlePage extends StatefulWidget { const NewsArticlePage({ required this.bloc, - required this.articlesBloc, required this.useWebView, this.bodyData, this.url, @@ -12,7 +11,6 @@ class NewsArticlePage extends StatefulWidget { assert(!useWebView || url != null, 'url has to be set when using a WebView'); final NewsArticleBloc bloc; - final NewsArticlesBloc articlesBloc; final bool useWebView; final String? bodyData; final String? url; @@ -22,6 +20,8 @@ class NewsArticlePage extends StatefulWidget { } class _NewsArticlePageState extends State { + late NewsArticlesBloc articlesBloc; + WebViewController? _webviewController; Timer? _markAsReadTimer; @@ -29,6 +29,8 @@ class _NewsArticlePageState extends State { void initState() { super.initState(); + articlesBloc = Provider.of(context, listen: false).mainArticlesBloc; + widget.bloc.errors.listen((final error) { NeonException.showSnackbar(context, error); }); @@ -67,7 +69,7 @@ class _NewsArticlePageState extends State { Future _startMarkAsReadTimer() async { if (await widget.bloc.unread.first) { - if (widget.articlesBloc.options.articleDisableMarkAsReadTimeoutOption.value) { + if (articlesBloc.options.articleDisableMarkAsReadTimeoutOption.value) { widget.bloc.markArticleAsRead(); } else { _markAsReadTimer = Timer(const Duration(seconds: 3), () async { diff --git a/packages/neon/neon_news/lib/pages/feed.dart b/packages/neon/neon_news/lib/pages/feed.dart index 60175a69..b8cb40c1 100644 --- a/packages/neon/neon_news/lib/pages/feed.dart +++ b/packages/neon/neon_news/lib/pages/feed.dart @@ -2,30 +2,31 @@ part of '../neon_news.dart'; class NewsFeedPage extends StatelessWidget { const NewsFeedPage({ - required this.bloc, required this.feed, super.key, }); - final NewsBloc bloc; final NextcloudNewsFeed feed; @override - Widget build(final BuildContext context) => Scaffold( - resizeToAvoidBottomInset: false, - appBar: AppBar( - title: Text(feed.title), - ), - body: NewsArticlesView( - bloc: NewsArticlesBloc( - bloc, - bloc.options, - bloc.requestManager, - bloc.client, - id: feed.id, - listType: ListType.feed, - ), - newsBloc: bloc, + Widget build(final BuildContext context) { + final bloc = Provider.of(context, listen: false); + + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar( + title: Text(feed.title), + ), + body: NewsArticlesView( + bloc: NewsArticlesBloc( + bloc, + bloc.options, + bloc.requestManager, + bloc.client, + id: feed.id, + listType: ListType.feed, ), - ); + ), + ); + } } diff --git a/packages/neon/neon_news/lib/pages/folder.dart b/packages/neon/neon_news/lib/pages/folder.dart index 0aa42ffc..e2c091be 100644 --- a/packages/neon/neon_news/lib/pages/folder.dart +++ b/packages/neon/neon_news/lib/pages/folder.dart @@ -2,12 +2,10 @@ part of '../neon_news.dart'; class NewsFolderPage extends StatelessWidget { const NewsFolderPage({ - required this.bloc, required this.folder, super.key, }); - final NewsBloc bloc; final NextcloudNewsFolder folder; @override @@ -17,11 +15,9 @@ class NewsFolderPage extends StatelessWidget { title: Text(folder.name), ), body: NewsFolderView( - bloc: bloc, folder: folder, ), floatingActionButton: NewsFeedFloatingActionButton( - bloc: bloc, folderID: folder.id, ), ); diff --git a/packages/neon/neon_news/lib/pages/main.dart b/packages/neon/neon_news/lib/pages/main.dart index a28abe62..ef3fd099 100644 --- a/packages/neon/neon_news/lib/pages/main.dart +++ b/packages/neon/neon_news/lib/pages/main.dart @@ -25,23 +25,16 @@ class _NewsMainPageState extends State { @override Widget build(final BuildContext context) { - final views = [ - NewsArticlesView( - bloc: bloc.mainArticlesBloc, - newsBloc: bloc, - ), - NewsFoldersView( - bloc: bloc, - ), - NewsFeedsView( - bloc: bloc, - ), + const views = [ + NewsArticlesView(), + NewsFoldersView(), + NewsFeedsView(), ]; - final floatingActionButtons = [ + const floatingActionButtons = [ null, - NewsFolderFloatingActionButton(bloc: bloc), - NewsFeedFloatingActionButton(bloc: bloc), + NewsFolderFloatingActionButton(), + NewsFeedFloatingActionButton(), ]; return Scaffold( diff --git a/packages/neon/neon_news/lib/widgets/articles_view.dart b/packages/neon/neon_news/lib/widgets/articles_view.dart index 2518caea..0947dcfb 100644 --- a/packages/neon/neon_news/lib/widgets/articles_view.dart +++ b/packages/neon/neon_news/lib/widgets/articles_view.dart @@ -2,37 +2,41 @@ part of '../neon_news.dart'; class NewsArticlesView extends StatefulWidget { const NewsArticlesView({ - required this.bloc, - required this.newsBloc, + this.bloc, super.key, }); - final NewsArticlesBloc bloc; - final NewsBloc newsBloc; + final NewsArticlesBloc? bloc; @override State createState() => _NewsArticlesViewState(); } class _NewsArticlesViewState extends State { + late NewsBloc newsBloc; + late NewsArticlesBloc bloc; + @override void initState() { super.initState(); - widget.bloc.errors.listen((final error) { + newsBloc = Provider.of(context, listen: false); + bloc = widget.bloc ?? newsBloc.mainArticlesBloc; + + bloc.errors.listen((final error) { NeonException.showSnackbar(context, error); }); } @override Widget build(final BuildContext context) => ResultBuilder>( - stream: widget.newsBloc.feeds, + stream: newsBloc.feeds, builder: (final context, final feeds) => ResultBuilder>( - stream: widget.bloc.articles, + stream: bloc.articles, builder: (final context, final articles) => SortBoxBuilder( sortBox: articlesSortBox, - sortPropertyOption: widget.newsBloc.options.articlesSortPropertyOption, - sortBoxOrderOption: widget.newsBloc.options.articlesSortBoxOrderOption, + sortPropertyOption: newsBloc.options.articlesSortPropertyOption, + sortBoxOrderOption: newsBloc.options.articlesSortBoxOrderOption, input: articles.data, builder: (final context, final sorted) => NeonListView( scrollKey: 'news-articles', @@ -41,8 +45,8 @@ class _NewsArticlesViewState extends State { error: articles.error ?? feeds.error, onRefresh: () async { await Future.wait([ - widget.bloc.refresh(), - widget.newsBloc.refresh(), + bloc.refresh(), + newsBloc.refresh(), ]); }, builder: (final context, final article) => _buildArticle( @@ -52,7 +56,7 @@ class _NewsArticlesViewState extends State { ), topFixedChildren: [ StreamBuilder( - stream: widget.bloc.filterType, + stream: bloc.filterType, builder: (final context, final selectedFilterTypeSnapshot) => Container( margin: const EdgeInsets.symmetric(horizontal: 15), child: DropdownButton( @@ -61,7 +65,7 @@ class _NewsArticlesViewState extends State { items: [ FilterType.all, FilterType.unread, - if (widget.bloc.listType == null) ...[ + if (bloc.listType == null) ...[ FilterType.starred, ], ].map>( @@ -87,7 +91,7 @@ class _NewsArticlesViewState extends State { }, ).toList(), onChanged: (final value) { - widget.bloc.setFilterType(value!); + bloc.setFilterType(value!); }, ), ), @@ -160,9 +164,9 @@ class _NewsArticlesViewState extends State { trailing: IconButton( onPressed: () { if (article.starred) { - widget.bloc.unstarArticle(article); + bloc.unstarArticle(article); } else { - widget.bloc.starArticle(article); + bloc.starArticle(article); } }, tooltip: @@ -174,13 +178,13 @@ class _NewsArticlesViewState extends State { ), onLongPress: () { if (article.unread) { - widget.bloc.markArticleAsRead(article); + bloc.markArticleAsRead(article); } else { - widget.bloc.markArticleAsUnread(article); + bloc.markArticleAsUnread(article); } }, onTap: () async { - final viewType = widget.newsBloc.options.articleViewTypeOption.value; + final viewType = newsBloc.options.articleViewTypeOption.value; String? bodyData; try { bodyData = _fixArticleBody(article.body); @@ -195,10 +199,9 @@ class _NewsArticlesViewState extends State { builder: (final context) => NewsArticlePage( bloc: NewsArticleBloc( Provider.of(context, listen: false).activeAccount.value!.client, - widget.bloc, + bloc, article, ), - articlesBloc: widget.bloc, useWebView: false, bodyData: bodyData, url: article.url, @@ -213,10 +216,9 @@ class _NewsArticlesViewState extends State { builder: (final context) => NewsArticlePage( bloc: NewsArticleBloc( Provider.of(context, listen: false).activeAccount.value!.client, - widget.bloc, + bloc, article, ), - articlesBloc: widget.bloc, useWebView: true, url: article.url, ), @@ -224,7 +226,7 @@ class _NewsArticlesViewState extends State { ); } else { if (article.unread) { - widget.bloc.markArticleAsRead(article); + bloc.markArticleAsRead(article); } if (article.url != null) { await launchUrlString( diff --git a/packages/neon/neon_news/lib/widgets/feed_floating_action_button.dart b/packages/neon/neon_news/lib/widgets/feed_floating_action_button.dart index edb43e99..c7dad3d1 100644 --- a/packages/neon/neon_news/lib/widgets/feed_floating_action_button.dart +++ b/packages/neon/neon_news/lib/widgets/feed_floating_action_button.dart @@ -2,29 +2,30 @@ part of '../neon_news.dart'; class NewsFeedFloatingActionButton extends StatelessWidget { const NewsFeedFloatingActionButton({ - required this.bloc, this.folderID, super.key, }); - final NewsBloc bloc; final int? folderID; @override - Widget build(final BuildContext context) => FloatingActionButton( - onPressed: () async { - final result = await showDialog( - context: context, - builder: (final context) => NewsAddFeedDialog( - bloc: bloc, - folderID: folderID, - ), - ); - if (result != null) { - bloc.addFeed(result[0] as String, result[1] as int?); - } - }, - tooltip: AppLocalizations.of(context).feedAdd, - child: const Icon(Icons.add), - ); + Widget build(final BuildContext context) { + final bloc = Provider.of(context, listen: false); + + return FloatingActionButton( + onPressed: () async { + final result = await showDialog( + context: context, + builder: (final context) => NewsAddFeedDialog( + folderID: folderID, + ), + ); + if (result != null) { + bloc.addFeed(result[0] as String, result[1] as int?); + } + }, + tooltip: AppLocalizations.of(context).feedAdd, + child: const Icon(Icons.add), + ); + } } diff --git a/packages/neon/neon_news/lib/widgets/feeds_view.dart b/packages/neon/neon_news/lib/widgets/feeds_view.dart index 7a6d942d..d7bb98ed 100644 --- a/packages/neon/neon_news/lib/widgets/feeds_view.dart +++ b/packages/neon/neon_news/lib/widgets/feeds_view.dart @@ -2,168 +2,172 @@ part of '../neon_news.dart'; class NewsFeedsView extends StatelessWidget { const NewsFeedsView({ - required this.bloc, this.folderID, super.key, }); - final NewsBloc bloc; final int? folderID; @override - Widget build(final BuildContext context) => ResultBuilder>( - stream: bloc.folders, - builder: (final context, final folders) => ResultBuilder>( - stream: bloc.feeds, - builder: (final context, final feeds) => SortBoxBuilder( - sortBox: feedsSortBox, - sortPropertyOption: bloc.options.feedsSortPropertyOption, - sortBoxOrderOption: bloc.options.feedsSortBoxOrderOption, - input: folders.data == null - ? null - : feeds.data?.where((final f) => folderID == null || f.folderId == folderID).toList(), - builder: (final context, final sorted) => NeonListView( - scrollKey: 'news-feeds', - withFloatingActionButton: true, - items: sorted, - isLoading: feeds.loading || folders.loading, - error: feeds.error ?? folders.error, - onRefresh: bloc.refresh, - builder: (final context, final feed) => _buildFeed( - context, - feed, - folders.data!, - ), + Widget build(final BuildContext context) { + final bloc = Provider.of(context, listen: false); + + return ResultBuilder>( + stream: bloc.folders, + builder: (final context, final folders) => ResultBuilder>( + stream: bloc.feeds, + builder: (final context, final feeds) => SortBoxBuilder( + sortBox: feedsSortBox, + sortPropertyOption: bloc.options.feedsSortPropertyOption, + sortBoxOrderOption: bloc.options.feedsSortBoxOrderOption, + input: folders.data == null + ? null + : feeds.data?.where((final f) => folderID == null || f.folderId == folderID).toList(), + builder: (final context, final sorted) => NeonListView( + scrollKey: 'news-feeds', + withFloatingActionButton: true, + items: sorted, + isLoading: feeds.loading || folders.loading, + error: feeds.error ?? folders.error, + onRefresh: bloc.refresh, + builder: (final context, final feed) => _buildFeed( + context, + feed, + folders.data!, ), ), ), - ); + ), + ); + } Widget _buildFeed( final BuildContext context, final NextcloudNewsFeed feed, final List folders, - ) => - ListTile( - title: Text( - feed.title, - style: feed.unreadCount! == 0 - ? Theme.of(context).textTheme.titleMedium!.copyWith(color: Theme.of(context).disabledColor) - : null, - ), - subtitle: - feed.unreadCount! > 0 ? Text(AppLocalizations.of(context).articlesUnread(feed.unreadCount!)) : Container(), - leading: NewsFeedIcon( - feed: feed, - borderRadius: const BorderRadius.all(Radius.circular(8)), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (feed.updateErrorCount > 0) ...[ - IconButton( - onPressed: () async { - await showDialog( - context: context, - builder: (final context) => NewsFeedUpdateErrorDialog( - feed: feed, - ), - ); - }, - tooltip: AppLocalizations.of(context).feedShowErrorMessage, - iconSize: 30, - icon: Text( - feed.updateErrorCount.toString(), - style: const TextStyle( - color: Colors.red, + ) { + final bloc = Provider.of(context, listen: false); + + return ListTile( + title: Text( + feed.title, + style: feed.unreadCount! == 0 + ? Theme.of(context).textTheme.titleMedium!.copyWith(color: Theme.of(context).disabledColor) + : null, + ), + subtitle: + feed.unreadCount! > 0 ? Text(AppLocalizations.of(context).articlesUnread(feed.unreadCount!)) : Container(), + leading: NewsFeedIcon( + feed: feed, + borderRadius: const BorderRadius.all(Radius.circular(8)), + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (feed.updateErrorCount > 0) ...[ + IconButton( + onPressed: () async { + await showDialog( + context: context, + builder: (final context) => NewsFeedUpdateErrorDialog( + feed: feed, ), + ); + }, + tooltip: AppLocalizations.of(context).feedShowErrorMessage, + iconSize: 30, + icon: Text( + feed.updateErrorCount.toString(), + style: const TextStyle( + color: Colors.red, ), ), - ], - PopupMenuButton( - itemBuilder: (final context) => [ - PopupMenuItem( - value: NewsFeedAction.showURL, - child: Text(AppLocalizations.of(context).feedShowURL), - ), - PopupMenuItem( - value: NewsFeedAction.delete, - child: Text(AppLocalizations.of(context).actionDelete), - ), + ), + ], + PopupMenuButton( + itemBuilder: (final context) => [ + PopupMenuItem( + value: NewsFeedAction.showURL, + child: Text(AppLocalizations.of(context).feedShowURL), + ), + PopupMenuItem( + value: NewsFeedAction.delete, + child: Text(AppLocalizations.of(context).actionDelete), + ), + PopupMenuItem( + value: NewsFeedAction.rename, + child: Text(AppLocalizations.of(context).actionRename), + ), + if (folders.isNotEmpty) ...[ PopupMenuItem( - value: NewsFeedAction.rename, - child: Text(AppLocalizations.of(context).actionRename), + value: NewsFeedAction.move, + child: Text(AppLocalizations.of(context).actionMove), ), - if (folders.isNotEmpty) ...[ - PopupMenuItem( - value: NewsFeedAction.move, - child: Text(AppLocalizations.of(context).actionMove), - ), - ], ], - onSelected: (final action) async { - switch (action) { - case NewsFeedAction.showURL: - await showDialog( - context: context, - builder: (final context) => NewsFeedShowURLDialog( - feed: feed, - ), - ); - break; - case NewsFeedAction.delete: + ], + onSelected: (final action) async { + switch (action) { + case NewsFeedAction.showURL: + await showDialog( + context: context, + builder: (final context) => NewsFeedShowURLDialog( + feed: feed, + ), + ); + break; + case NewsFeedAction.delete: + // ignore: use_build_context_synchronously + if (await showConfirmationDialog( + context, // ignore: use_build_context_synchronously - if (await showConfirmationDialog( - context, - // ignore: use_build_context_synchronously - AppLocalizations.of(context).feedRemoveConfirm(feed.title), - )) { - bloc.removeFeed(feed.id); - } - break; - case NewsFeedAction.rename: - final result = await showRenameDialog( - context: context, - title: AppLocalizations.of(context).feedRename, - value: feed.title, - ); - if (result != null) { - bloc.renameFeed(feed.id, result); - } - break; - case NewsFeedAction.move: - final result = await showDialog>( - context: context, - builder: (final context) => NewsMoveFeedDialog( - folders: folders, - feed: feed, - ), - ); - if (result != null) { - bloc.moveFeed(feed.id, result[0]); - } - break; - } - }, - ), - ], - ), - onLongPress: () { - if (feed.unreadCount! > 0) { - bloc.markFeedAsRead(feed.id); - } - }, - onTap: () async { - await Navigator.of(context).push( - MaterialPageRoute( - builder: (final context) => NewsFeedPage( - bloc: bloc, - feed: feed, - ), + AppLocalizations.of(context).feedRemoveConfirm(feed.title), + )) { + bloc.removeFeed(feed.id); + } + break; + case NewsFeedAction.rename: + final result = await showRenameDialog( + context: context, + title: AppLocalizations.of(context).feedRename, + value: feed.title, + ); + if (result != null) { + bloc.renameFeed(feed.id, result); + } + break; + case NewsFeedAction.move: + final result = await showDialog>( + context: context, + builder: (final context) => NewsMoveFeedDialog( + folders: folders, + feed: feed, + ), + ); + if (result != null) { + bloc.moveFeed(feed.id, result[0]); + } + break; + } + }, + ), + ], + ), + onLongPress: () { + if (feed.unreadCount! > 0) { + bloc.markFeedAsRead(feed.id); + } + }, + onTap: () async { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (final context) => NewsFeedPage( + feed: feed, ), - ); - }, - ); + ), + ); + }, + ); + } } enum NewsFeedAction { diff --git a/packages/neon/neon_news/lib/widgets/folder_floating_action_button.dart b/packages/neon/neon_news/lib/widgets/folder_floating_action_button.dart index 39c3f5d3..263b3014 100644 --- a/packages/neon/neon_news/lib/widgets/folder_floating_action_button.dart +++ b/packages/neon/neon_news/lib/widgets/folder_floating_action_button.dart @@ -2,24 +2,25 @@ part of '../neon_news.dart'; class NewsFolderFloatingActionButton extends StatelessWidget { const NewsFolderFloatingActionButton({ - required this.bloc, super.key, }); - final NewsBloc bloc; - @override - Widget build(final BuildContext context) => FloatingActionButton( - onPressed: () async { - final result = await showDialog( - context: context, - builder: (final context) => const NewsCreateFolderDialog(), - ); - if (result != null) { - bloc.createFolder(result); - } - }, - tooltip: AppLocalizations.of(context).folderCreate, - child: const Icon(Icons.add), - ); + Widget build(final BuildContext context) { + final bloc = Provider.of(context, listen: false); + + return FloatingActionButton( + onPressed: () async { + final result = await showDialog( + context: context, + builder: (final context) => const NewsCreateFolderDialog(), + ); + if (result != null) { + bloc.createFolder(result); + } + }, + tooltip: AppLocalizations.of(context).folderCreate, + child: const Icon(Icons.add), + ); + } } diff --git a/packages/neon/neon_news/lib/widgets/folder_view.dart b/packages/neon/neon_news/lib/widgets/folder_view.dart index bdfcd6b5..f45dcf74 100644 --- a/packages/neon/neon_news/lib/widgets/folder_view.dart +++ b/packages/neon/neon_news/lib/widgets/folder_view.dart @@ -2,12 +2,10 @@ part of '../neon_news.dart'; class NewsFolderView extends StatefulWidget { const NewsFolderView({ - required this.bloc, required this.folder, super.key, }); - final NewsBloc bloc; final NextcloudNewsFolder folder; @override @@ -15,9 +13,17 @@ class NewsFolderView extends StatefulWidget { } class _NewsFolderViewState extends State { - late final option = widget.bloc.options.defaultFolderViewTypeOption; + late NewsBloc bloc; + late final option = bloc.options.defaultFolderViewTypeOption; late DefaultFolderViewType _viewType = option.value; + @override + void initState() { + bloc = Provider.of(context, listen: false); + + super.initState(); + } + @override Widget build(final BuildContext context) => Column( children: [ @@ -45,17 +51,15 @@ class _NewsFolderViewState extends State { child: _viewType == DefaultFolderViewType.articles ? NewsArticlesView( bloc: NewsArticlesBloc( - widget.bloc, - widget.bloc.options, - widget.bloc.requestManager, - widget.bloc.client, + bloc, + bloc.options, + bloc.requestManager, + bloc.client, id: widget.folder.id, listType: ListType.folder, ), - newsBloc: widget.bloc, ) : NewsFeedsView( - bloc: widget.bloc, folderID: widget.folder.id, ), ), diff --git a/packages/neon/neon_news/lib/widgets/folders_view.dart b/packages/neon/neon_news/lib/widgets/folders_view.dart index df8e457d..49926dd1 100644 --- a/packages/neon/neon_news/lib/widgets/folders_view.dart +++ b/packages/neon/neon_news/lib/widgets/folders_view.dart @@ -2,49 +2,52 @@ part of '../neon_news.dart'; class NewsFoldersView extends StatelessWidget { const NewsFoldersView({ - required this.bloc, super.key, }); - final NewsBloc bloc; - @override - Widget build(final BuildContext context) => ResultBuilder>( - stream: bloc.folders, - builder: (final context, final folders) => ResultBuilder>( - stream: bloc.feeds, - builder: (final context, final feeds) => SortBoxBuilder( - sortBox: foldersSortBox, - sortPropertyOption: bloc.options.foldersSortPropertyOption, - sortBoxOrderOption: bloc.options.foldersSortBoxOrderOption, - input: feeds.data == null - ? null - : folders.data - ?.map( - (final folder) => FolderFeedsWrapper( - folder, - feeds.data!.where((final feed) => feed.folderId == folder.id).toList(), - ), - ) - .toList(), - builder: (final context, final sorted) => NeonListView( - scrollKey: 'news-folders', - withFloatingActionButton: true, - items: sorted, - isLoading: feeds.loading || folders.loading, - error: feeds.error ?? folders.error, - onRefresh: bloc.refresh, - builder: _buildFolder, - ), + Widget build(final BuildContext context) { + final bloc = Provider.of(context, listen: false); + + return ResultBuilder>( + stream: bloc.folders, + builder: (final context, final folders) => ResultBuilder>( + stream: bloc.feeds, + builder: (final context, final feeds) => SortBoxBuilder( + sortBox: foldersSortBox, + sortPropertyOption: bloc.options.foldersSortPropertyOption, + sortBoxOrderOption: bloc.options.foldersSortBoxOrderOption, + input: feeds.data == null + ? null + : folders.data + ?.map( + (final folder) => FolderFeedsWrapper( + folder, + feeds.data!.where((final feed) => feed.folderId == folder.id).toList(), + ), + ) + .toList(), + builder: (final context, final sorted) => NeonListView( + scrollKey: 'news-folders', + withFloatingActionButton: true, + items: sorted, + isLoading: feeds.loading || folders.loading, + error: feeds.error ?? folders.error, + onRefresh: bloc.refresh, + builder: _buildFolder, ), ), - ); + ), + ); + } Widget _buildFolder( final BuildContext context, final FolderFeedsWrapper folderFeedsWrapper, ) { + final bloc = Provider.of(context, listen: false); final unreadCount = feedsUnreadCountSum(folderFeedsWrapper.feeds); + return ListTile( title: Text( folderFeedsWrapper.folder.name, @@ -122,7 +125,6 @@ class NewsFoldersView extends StatelessWidget { await Navigator.of(context).push( MaterialPageRoute( builder: (final context) => NewsFolderPage( - bloc: bloc, folder: folderFeedsWrapper.folder, ), ),