@@ -52,140 +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- tooltip: l10n.notificationCenterMarkAllAsReadButton,
75- );
76- },
77- ),
78- BlocBuilder <
79- InAppNotificationCenterBloc ,
80- InAppNotificationCenterState
81- >(
82- builder: (context, state) {
83- return IconButton (
84- tooltip: l10n.deleteReadNotificationsButtonTooltip,
85- icon: const Icon (Icons .delete_sweep_outlined),
86- onPressed: state.hasReadItemsInCurrentTab
87- ? () async {
88- final confirmed = await showDialog <bool >(
89- context: context,
90- builder: (context) => AlertDialog (
91- title: Text (l10n.deleteConfirmationDialogTitle),
92- content: Text (
93- l10n.deleteReadNotificationsDialogContent,
94- ),
95- actions: [
96- TextButton (
97- onPressed: () => Navigator .pop (context, false ),
98- child: Text (l10n.cancelButtonLabel),
99- ),
100- TextButton (
101- onPressed: () => Navigator .pop (context, true ),
102- child: Text (l10n.deleteButtonLabel),
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,
83+ ),
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,
103146 ),
104- ],
105- ),
106- );
107- if (confirmed == true && context.mounted) {
108- context.read <InAppNotificationCenterBloc >().add (
109- const InAppNotificationCenterReadItemsDeleted (),
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,
110160 );
111161 }
112- }
113- : null ,
114- );
115- },
116- ),
117- ],
118- bottom: TabBar (
119- controller: _tabController,
120- tabs: [
121- Tab (text: l10n.notificationCenterTabBreakingNews),
122- Tab (text: l10n.notificationCenterTabDigests),
123- ],
124- ),
125- ),
126- body:
127- BlocConsumer <
128- InAppNotificationCenterBloc ,
129- InAppNotificationCenterState
130- >(
131- listener: (context, state) {
132- if (state.status == InAppNotificationCenterStatus .failure &&
133- state.error != null ) {
134- ScaffoldMessenger .of (context)
135- ..hideCurrentSnackBar ()
136- ..showSnackBar (
137- SnackBar (
138- content: Text (state.error! .message),
139- backgroundColor: Theme .of (context).colorScheme.error,
140- ),
141- );
142- }
143- },
144- builder: (context, state) {
145- if (state.status == InAppNotificationCenterStatus .loading &&
146- state.breakingNewsNotifications.isEmpty &&
147- state.digestNotifications.isEmpty) {
148- return LoadingStateWidget (
149- icon: Icons .notifications_none_outlined,
150- headline: l10n.notificationCenterLoadingHeadline,
151- subheadline: l10n.notificationCenterLoadingSubheadline,
152- );
153- }
154162
155- if (state.status == InAppNotificationCenterStatus .failure &&
156- state.breakingNewsNotifications.isEmpty &&
157- state.digestNotifications.isEmpty) {
158- return FailureStateWidget (
159- exception:
160- state.error ??
161- OperationFailedException (
162- l10n.notificationCenterFailureHeadline,
163- ),
164- onRetry: () {
165- context.read <InAppNotificationCenterBloc >().add (
166- const InAppNotificationCenterSubscriptionRequested (),
167- );
168- },
169- );
170- }
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+ }
171180
172- return TabBarView (
173- controller: _tabController,
174- children: [
175- _NotificationList (
176- status: state.status,
177- notifications: state.breakingNewsNotifications,
178- hasMore: state.breakingNewsHasMore,
179- ),
180- _NotificationList (
181- status: state.status,
182- notifications: state.digestNotifications,
183- hasMore: state.digestHasMore,
184- ),
185- ],
186- );
187- },
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+ Container (
201+ color: Colors .black.withOpacity (0.5 ),
202+ child: const Center (child: CircularProgressIndicator ()),
203+ ),
204+ ],
188205 ),
206+ );
207+ },
189208 );
190209 }
191210}
0 commit comments