@@ -52,100 +52,159 @@ class _InAppNotificationCenterPageState
5252 Widget build (BuildContext context) {
5353 final l10n = AppLocalizationsX (context).l10n;
5454
55- return Scaffold (
56- appBar: AppBar (
57- title: Text (l10n.notificationCenterPageTitle),
58- actions: [
59- BlocBuilder <
60- InAppNotificationCenterBloc ,
61- InAppNotificationCenterState
62- >(
63- builder: (context, state) {
64- final hasUnread = state.notifications.any ((n) => ! n.isRead);
65- return IconButton (
66- onPressed: hasUnread
67- ? () {
68- context.read <InAppNotificationCenterBloc >().add (
69- const InAppNotificationCenterMarkAllAsRead (),
70- );
71- }
72- : null ,
73- icon: const Icon (Icons .done_all),
74- );
75- },
76- ),
77- ],
78- bottom: TabBar (
79- controller: _tabController,
80- tabs: [
81- Tab (text: l10n.notificationCenterTabBreakingNews),
82- Tab (text: l10n.notificationCenterTabDigests),
83- ],
84- ),
85- ),
86- body:
87- BlocConsumer <
88- InAppNotificationCenterBloc ,
89- InAppNotificationCenterState
90- >(
91- listener: (context, state) {
92- if (state.status == InAppNotificationCenterStatus .failure &&
93- state.error != null ) {
94- ScaffoldMessenger .of (context)
95- ..hideCurrentSnackBar ()
96- ..showSnackBar (
97- SnackBar (
98- content: Text (state.error! .message),
99- backgroundColor: Theme .of (context).colorScheme.error,
55+ return BlocBuilder <
56+ InAppNotificationCenterBloc ,
57+ InAppNotificationCenterState
58+ >(
59+ builder: (context, state) {
60+ final isDeleting =
61+ state.status == InAppNotificationCenterStatus .deleting;
62+
63+ return WillPopScope (
64+ onWillPop: () async => ! isDeleting,
65+ child: Stack (
66+ children: [
67+ Scaffold (
68+ appBar: AppBar (
69+ title: Text (l10n.notificationCenterPageTitle),
70+ actions: [
71+ IconButton (
72+ onPressed:
73+ ! isDeleting &&
74+ state.notifications.any ((n) => ! n.isRead)
75+ ? () {
76+ context.read <InAppNotificationCenterBloc >().add (
77+ const InAppNotificationCenterMarkAllAsRead (),
78+ );
79+ }
80+ : null ,
81+ icon: const Icon (Icons .done_all),
82+ tooltip: l10n.notificationCenterMarkAllAsReadButton,
10083 ),
101- );
102- }
103- },
104- builder: (context, state) {
105- if (state.status == InAppNotificationCenterStatus .loading &&
106- state.breakingNewsNotifications.isEmpty &&
107- state.digestNotifications.isEmpty) {
108- return LoadingStateWidget (
109- icon: Icons .notifications_none_outlined,
110- headline: l10n.notificationCenterLoadingHeadline,
111- subheadline: l10n.notificationCenterLoadingSubheadline,
112- );
113- }
84+ IconButton (
85+ tooltip: l10n.deleteReadNotificationsButtonTooltip,
86+ icon: const Icon (Icons .delete_sweep_outlined),
87+ onPressed: ! isDeleting && state.hasReadItemsInCurrentTab
88+ ? () async {
89+ final confirmed = await showDialog <bool >(
90+ context: context,
91+ builder: (context) => AlertDialog (
92+ title: Text (
93+ l10n.deleteConfirmationDialogTitle,
94+ ),
95+ content: Text (
96+ l10n.deleteReadNotificationsDialogContent,
97+ ),
98+ actions: [
99+ TextButton (
100+ onPressed: () =>
101+ Navigator .pop (context, false ),
102+ child: Text (l10n.cancelButtonLabel),
103+ ),
104+ TextButton (
105+ onPressed: () =>
106+ Navigator .pop (context, true ),
107+ child: Text (l10n.deleteButtonLabel),
108+ ),
109+ ],
110+ ),
111+ );
112+ if (confirmed == true && context.mounted) {
113+ context.read <InAppNotificationCenterBloc >().add (
114+ const InAppNotificationCenterReadItemsDeleted (),
115+ );
116+ }
117+ }
118+ : null ,
119+ ),
120+ ],
121+ bottom: TabBar (
122+ controller: _tabController,
123+ tabs: [
124+ Tab (text: l10n.notificationCenterTabBreakingNews),
125+ Tab (text: l10n.notificationCenterTabDigests),
126+ ],
127+ ),
128+ ),
129+ body:
130+ BlocConsumer <
131+ InAppNotificationCenterBloc ,
132+ InAppNotificationCenterState
133+ >(
134+ listener: (context, state) {
135+ if (state.status ==
136+ InAppNotificationCenterStatus .failure &&
137+ state.error != null ) {
138+ ScaffoldMessenger .of (context)
139+ ..hideCurrentSnackBar ()
140+ ..showSnackBar (
141+ SnackBar (
142+ content: Text (state.error! .message),
143+ backgroundColor: Theme .of (
144+ context,
145+ ).colorScheme.error,
146+ ),
147+ );
148+ }
149+ },
150+ builder: (context, state) {
151+ if (state.status ==
152+ InAppNotificationCenterStatus .loading &&
153+ state.breakingNewsNotifications.isEmpty &&
154+ state.digestNotifications.isEmpty) {
155+ return LoadingStateWidget (
156+ icon: Icons .notifications_none_outlined,
157+ headline: l10n.notificationCenterLoadingHeadline,
158+ subheadline:
159+ l10n.notificationCenterLoadingSubheadline,
160+ );
161+ }
114162
115- if (state.status == InAppNotificationCenterStatus .failure &&
116- state.breakingNewsNotifications.isEmpty &&
117- state.digestNotifications.isEmpty) {
118- return FailureStateWidget (
119- exception:
120- state.error ??
121- OperationFailedException (
122- l10n.notificationCenterFailureHeadline,
123- ),
124- onRetry: () {
125- context.read <InAppNotificationCenterBloc >().add (
126- const InAppNotificationCenterSubscriptionRequested (),
127- );
128- },
129- );
130- }
163+ if (state.status ==
164+ InAppNotificationCenterStatus .failure &&
165+ state.breakingNewsNotifications.isEmpty &&
166+ state.digestNotifications.isEmpty) {
167+ return FailureStateWidget (
168+ exception:
169+ state.error ??
170+ OperationFailedException (
171+ l10n.notificationCenterFailureHeadline,
172+ ),
173+ onRetry: () {
174+ context.read <InAppNotificationCenterBloc >().add (
175+ const InAppNotificationCenterSubscriptionRequested (),
176+ );
177+ },
178+ );
179+ }
131180
132- return TabBarView (
133- controller: _tabController,
134- children: [
135- _NotificationList (
136- status: state.status,
137- notifications: state.breakingNewsNotifications,
138- hasMore: state.breakingNewsHasMore,
139- ),
140- _NotificationList (
141- status: state.status,
142- notifications: state.digestNotifications,
143- hasMore: state.digestHasMore,
144- ),
145- ],
146- );
147- },
181+ return TabBarView (
182+ controller: _tabController,
183+ children: [
184+ _NotificationList (
185+ status: state.status,
186+ notifications: state.breakingNewsNotifications,
187+ hasMore: state.breakingNewsHasMore,
188+ ),
189+ _NotificationList (
190+ status: state.status,
191+ notifications: state.digestNotifications,
192+ hasMore: state.digestHasMore,
193+ ),
194+ ],
195+ );
196+ },
197+ ),
198+ ),
199+ if (isDeleting)
200+ ColoredBox (
201+ color: Colors .black.withOpacity (0.5 ),
202+ child: const Center (child: CircularProgressIndicator ()),
203+ ),
204+ ],
148205 ),
206+ );
207+ },
149208 );
150209 }
151210}
0 commit comments