Skip to content

Commit

Permalink
perf(listing): prevent an infinite rendering loop
Browse files Browse the repository at this point in the history
ArticleListItem was stuck in a loop of self invalidation.
  • Loading branch information
casimir committed Nov 6, 2024
1 parent 092cd30 commit a69bfcd
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 52 deletions.
12 changes: 6 additions & 6 deletions lib/pages/articles/article_list_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class _ArticleListItemState extends ConsumerState<ArticleListItem> {
// TODO explore https://pub.dev/packages/flutter_slidable
// TODO GestureDetector on iOS

_listenToSelectionChange(ref);
_listenToSelectionChange();

return Ink(
color: widget.showSelection && _isSelected
Expand Down Expand Up @@ -155,12 +155,12 @@ class _ArticleListItemState extends ConsumerState<ArticleListItem> {
);
}

void _listenToSelectionChange(WidgetRef ref) async {
final currentArticleId =
await ref.watch(currentArticleProvider.selectAsync((it) => it?.id));
if (mounted) {
void _listenToSelectionChange() async {
final isSelected = await ref.watch(currentArticleProvider
.selectAsync((it) => (it?.id ?? -1) == widget.article.id));
if (mounted && _isSelected != isSelected) {
setState(() {
_isSelected = currentArticleId == widget.article.id;
_isSelected = isSelected;
});
}
}
Expand Down
84 changes: 42 additions & 42 deletions lib/pages/articles/listing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import 'search.dart';

final _log = Logger('frigoligo.listing');

enum MenuAction { synchronize, saveLink, settings }

class ListingPage extends ConsumerStatefulWidget {
const ListingPage({
super.key,
Expand Down Expand Up @@ -50,8 +52,8 @@ class _ListingPageState extends ConsumerState<ListingPage> {
headerSliverBuilder: (context, innerBoxIsScrolled) => [
PinnedHeaderSliver(
child: SearchBarWithFilters(
doRefresh: () => doRefresh(ref),
menu: _buildMenu(context, ref),
doRefresh: () => doRefresh(),
menu: _buildMenu(context),
backgroundColor: headerColor,
),
),
Expand All @@ -63,7 +65,7 @@ class _ListingPageState extends ConsumerState<ListingPage> {
child: Builder(builder: (context) {
return ArticleListView(
controller: _scrollKey.currentState!.innerController,
doRefresh: () => doRefresh(ref),
doRefresh: () => doRefresh(),
onItemSelect: widget.onItemSelect,
sideBySideMode: widget.sideBySideMode,
);
Expand All @@ -73,50 +75,48 @@ class _ListingPageState extends ConsumerState<ListingPage> {
),
floatingActionButton: RemoteSyncFAB(showIf: widget.withProgressIndicator),
backgroundColor: headerColor,
resizeToAvoidBottomInset: false,
restorationId: 'listing.scaffold',
);
}
}

Future<void> doRefresh(WidgetRef ref) async {
_log.info('triggered refresh');
await ref
.read(remoteSyncerProvider.notifier)
.synchronize(withFinalRefresh: true);
}

enum MenuAction { synchronize, saveLink, settings }
Future<void> doRefresh() async {
_log.info('triggered refresh');
await ref
.read(remoteSyncerProvider.notifier)
.synchronize(withFinalRefresh: true);
}

PopupMenuButton _buildMenu(BuildContext context, WidgetRef ref) =>
PopupMenuButton(
key: const Key(wkListingPopupMenu),
itemBuilder: (context) => [
PopupMenuItem(
value: MenuAction.saveLink,
child: ListTile(
leading: const Icon(Icons.add_link),
title: Text(context.L.g_saveLink),
PopupMenuButton _buildMenu(BuildContext context) => PopupMenuButton(
key: const Key(wkListingPopupMenu),
itemBuilder: (context) => [
PopupMenuItem(
value: MenuAction.saveLink,
child: ListTile(
leading: const Icon(Icons.add_link),
title: Text(context.L.g_saveLink),
),
),
),
PopupMenuItem(
value: MenuAction.synchronize,
child: ListTile(
leading: const Icon(Icons.sync),
title: Text(context.L.g_synchronize),
PopupMenuItem(
value: MenuAction.synchronize,
child: ListTile(
leading: const Icon(Icons.sync),
title: Text(context.L.g_synchronize),
),
),
),
PopupMenuItem(
value: MenuAction.settings,
child: ListTile(
key: const Key(wkListingSettings),
leading: const Icon(Icons.settings),
title: Text(context.L.g_settings),
PopupMenuItem(
value: MenuAction.settings,
child: ListTile(
key: const Key(wkListingSettings),
leading: const Icon(Icons.settings),
title: Text(context.L.g_settings),
),
),
),
],
onSelected: (action) => switch (action as MenuAction) {
MenuAction.saveLink => showSaveUrlDialog(context),
MenuAction.synchronize => doRefresh(ref),
MenuAction.settings => context.push('/settings'),
},
);
],
onSelected: (action) => switch (action as MenuAction) {
MenuAction.saveLink => showSaveUrlDialog(context),
MenuAction.synchronize => doRefresh(),
MenuAction.settings => context.push('/settings'),
},
);
}
2 changes: 1 addition & 1 deletion lib/providers/article.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'settings.dart';

part 'article.g.dart';

@riverpod
@Riverpod(keepAlive: true)
class CurrentArticle extends _$CurrentArticle {
int? _articleId;
StreamSubscription? _watcher;
Expand Down
6 changes: 3 additions & 3 deletions lib/providers/article.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a69bfcd

Please sign in to comment.