11import 'package:flutter/material.dart' ;
22import 'package:flutter_bloc/flutter_bloc.dart' ;
3+ import 'package:core/core.dart' ;
34import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart' ;
45import 'package:flutter_news_app_mobile_client_full_source_code/headlines-feed/widgets/save_filter_dialog.dart' ;
56import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart' ;
67import 'package:ui_kit/ui_kit.dart' ;
78
89/// {@template manage_saved_filters_page}
9- /// A page for managing saved feed filters.
10+ /// A page for managing saved feed filters, allowing users to reorder,
11+ /// rename, or delete them.
1012///
11- /// Allows users to rename or delete their saved filters.
13+ /// Reordering is handled via a [ReorderableListView] , which dispatches a
14+ /// [SavedFiltersReordered] event to the [AppBloc] to persist the new order.
15+ /// Renaming and deletion are handled via a [PopupMenuButton] on each list item.
1216/// {@endtemplate}
1317class ManageSavedFiltersPage extends StatelessWidget {
1418 /// {@macro manage_saved_filters_page}
@@ -22,6 +26,7 @@ class ManageSavedFiltersPage extends StatelessWidget {
2226 return Scaffold (
2327 appBar: AppBar (
2428 title: Text (
29+ // Will be updated to a new localization key later.
2530 l10n.manageFiltersPageTitle,
2631 style: theme.textTheme.titleLarge,
2732 ),
@@ -32,27 +37,29 @@ class ManageSavedFiltersPage extends StatelessWidget {
3237
3338 if (savedFilters.isEmpty) {
3439 return InitialStateWidget (
40+ // Will be updated to new localization keys later.
3541 icon: Icons .filter_list_off_outlined,
3642 headline: l10n.manageFiltersEmptyHeadline,
3743 subheadline: l10n.manageFiltersEmptySubheadline,
3844 );
3945 }
4046
41- return ListView . separated (
47+ return ReorderableListView . builder (
4248 itemCount: savedFilters.length,
43- separatorBuilder: (context, index) =>
44- const Divider (height: 1 , indent: AppSpacing .md),
4549 itemBuilder: (context, index) {
4650 final filter = savedFilters[index];
4751 return ListTile (
52+ // A key is required for ReorderableListView to work correctly.
53+ key: ValueKey (filter.id),
54+ leading: ReorderableDragStartListener (
55+ index: index,
56+ child: const Icon (Icons .drag_handle),
57+ ),
4858 title: Text (filter.name),
49- trailing: Row (
50- mainAxisSize: MainAxisSize .min,
51- children: [
52- IconButton (
53- icon: const Icon (Icons .edit_outlined),
54- tooltip: l10n.manageFiltersRenameTooltip,
55- onPressed: () {
59+ trailing: PopupMenuButton <String >(
60+ onSelected: (value) {
61+ switch (value) {
62+ case 'rename' :
5663 showDialog <void >(
5764 context: context,
5865 builder: (_) => SaveFilterDialog (
@@ -67,24 +74,53 @@ class ManageSavedFiltersPage extends StatelessWidget {
6774 },
6875 ),
6976 );
70- },
71- ),
72- IconButton (
73- icon: Icon (
74- Icons .delete_outline,
75- color: theme.colorScheme.error,
76- ),
77- tooltip: l10n.manageFiltersDeleteTooltip,
78- onPressed: () {
77+ break ;
78+ case 'delete' :
7979 context.read <AppBloc >().add (
8080 SavedFilterDeleted (filterId: filter.id),
8181 );
82- },
83- ),
84- ],
82+ break ;
83+ }
84+ },
85+ itemBuilder: (BuildContext context) =>
86+ < PopupMenuEntry <String >> [
87+ PopupMenuItem <String >(
88+ value: 'rename' ,
89+ // Will be updated to new localization keys later.
90+ child: Text (l10n.manageFiltersRenameTooltip),
91+ ),
92+ PopupMenuItem <String >(
93+ value: 'delete' ,
94+ child: Text (
95+ // Will be updated to new localization keys later.
96+ l10n.manageFiltersDeleteTooltip,
97+ style: TextStyle (color: theme.colorScheme.error),
98+ ),
99+ ),
100+ ],
85101 ),
86102 );
87103 },
104+ onReorder: (oldIndex, newIndex) {
105+ // This adjustment is necessary when moving an item downwards
106+ // in the list.
107+ if (oldIndex < newIndex) {
108+ newIndex -= 1 ;
109+ }
110+
111+ // Create a mutable copy of the list.
112+ final reorderedList = List <SavedFilter >.from (savedFilters);
113+
114+ // Remove the item from its old position and insert it into the
115+ // new position.
116+ final movedFilter = reorderedList.removeAt (oldIndex);
117+ reorderedList.insert (newIndex, movedFilter);
118+
119+ // Dispatch the event to the AppBloc to persist the new order.
120+ context.read <AppBloc >().add (
121+ SavedFiltersReordered (reorderedFilters: reorderedList),
122+ );
123+ },
88124 );
89125 },
90126 ),
0 commit comments