@@ -3,11 +3,13 @@ import 'dart:math' as math;
33import 'package:easy_refresh/easy_refresh.dart' ;
44import 'package:flutter/material.dart' ;
55import 'package:flutter_bloc/flutter_bloc.dart' ;
6+ import 'package:go_router/go_router.dart' ;
67import 'package:tsdm_client/constants/layout.dart' ;
78import 'package:tsdm_client/features/notification/bloc/auto_notification_cubit.dart' ;
89import 'package:tsdm_client/features/notification/bloc/notification_bloc.dart' ;
910import 'package:tsdm_client/features/notification/bloc/notification_state_cubit.dart' ;
1011import 'package:tsdm_client/i18n/strings.g.dart' ;
12+ import 'package:tsdm_client/routes/screen_paths.dart' ;
1113import 'package:tsdm_client/shared/models/notification_type.dart' ;
1214import 'package:tsdm_client/utils/logger.dart' ;
1315import 'package:tsdm_client/utils/retry_button.dart' ;
@@ -38,19 +40,29 @@ class _NotificationPageState extends State<NotificationPage> with SingleTickerPr
3840 return Align (
3941 child: LayoutBuilder (
4042 builder:
41- (context, constraints) => SingleChildScrollView (
43+ (context, constraints) =>
44+ SingleChildScrollView (
4245 physics: const AlwaysScrollableScrollPhysics (),
4346 child: ConstrainedBox (
4447 constraints: BoxConstraints (
45- minWidth: MediaQuery .sizeOf (context).width,
48+ minWidth: MediaQuery
49+ .sizeOf (context)
50+ .width,
4651 minHeight: constraints.maxHeight,
4752 ),
4853 child: Center (
4954 child: Text (
5055 context.t.general.noData,
51- style: Theme .of (
56+ style: Theme
57+ .of (
5258 context,
53- ).textTheme.titleMedium? .copyWith (color: Theme .of (context).colorScheme.outline),
59+ )
60+ .textTheme
61+ .titleMedium
62+ ? .copyWith (color: Theme
63+ .of (context)
64+ .colorScheme
65+ .outline),
5466 ),
5567 ),
5668 ),
@@ -85,9 +97,15 @@ class _NotificationPageState extends State<NotificationPage> with SingleTickerPr
8597 if (state.status == NotificationStatus .failure) {
8698 showFailedToLoadSnackBar (context);
8799 } else if (state.status == NotificationStatus .success) {
88- final n = state.noticeList.where ((e) => ! e.alreadyRead).length;
89- final pm = state.personalMessageList.where ((e) => ! e.alreadyRead).length;
90- final bm = state.broadcastMessageList.where ((e) => ! e.alreadyRead).length;
100+ final n = state.noticeList
101+ .where ((e) => ! e.alreadyRead)
102+ .length;
103+ final pm = state.personalMessageList
104+ .where ((e) => ! e.alreadyRead)
105+ .length;
106+ final bm = state.broadcastMessageList
107+ .where ((e) => ! e.alreadyRead)
108+ .length;
91109 context.read <NotificationStateCubit >().setAll (
92110 noticeCount: n,
93111 personalMessageCount: pm,
@@ -98,74 +116,77 @@ class _NotificationPageState extends State<NotificationPage> with SingleTickerPr
98116 child: BlocBuilder <NotificationBloc , NotificationState >(
99117 builder: (context, state) {
100118 final (n, pm, bm) = switch (onlyShowUnread) {
101- true => (
102- state.noticeList.where ((e) => ! e.alreadyRead),
103- state.personalMessageList.where ((e) => ! e.alreadyRead),
104- state.broadcastMessageList.where ((e) => ! e.alreadyRead),
119+ true =>
120+ (
121+ state.noticeList.where ((e) => ! e.alreadyRead),
122+ state.personalMessageList.where ((e) => ! e.alreadyRead),
123+ state.broadcastMessageList.where ((e) => ! e.alreadyRead),
105124 ),
106125 false => (state.noticeList, state.personalMessageList, state.broadcastMessageList),
107126 };
108127
109128 final body = switch (state.status) {
110129 NotificationStatus .initial ||
111130 NotificationStatus .loading => const Center (child: CircularProgressIndicator ()),
112- NotificationStatus .success => TabBarView (
113- controller: _tabController,
114- children: [
115- EasyRefresh .builder (
116- controller: _noticeRefreshController,
117- header: const MaterialHeader (),
118- onRefresh: () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
119- childBuilder:
120- (context, physics) =>
121- n.isEmpty
122- ? _buildEmptyBody (context)
123- : ListView .separated (
124- physics: physics,
125- padding: edgeInsetsL12T4R12B4,
126- itemCount: n.length,
127- itemBuilder: (_, idx) => NoticeCardV2 (n.elementAt (idx)),
128- separatorBuilder: (_, __) => sizedBoxW4H4,
129- ),
131+ NotificationStatus .success =>
132+ TabBarView (
133+ controller: _tabController,
134+ children: [
135+ EasyRefresh .builder (
136+ controller: _noticeRefreshController,
137+ header: const MaterialHeader (),
138+ onRefresh: () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
139+ childBuilder:
140+ (context, physics) =>
141+ n.isEmpty
142+ ? _buildEmptyBody (context)
143+ : ListView .separated (
144+ physics: physics,
145+ padding: edgeInsetsL12T4R12B4,
146+ itemCount: n.length,
147+ itemBuilder: (_, idx) => NoticeCardV2 (n.elementAt (idx)),
148+ separatorBuilder: (_, __) => sizedBoxW4H4,
149+ ),
150+ ),
151+ EasyRefresh .builder (
152+ controller: _personalMessageRefreshController,
153+ header: const MaterialHeader (),
154+ onRefresh: () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
155+ childBuilder:
156+ (context, physics) =>
157+ pm.isEmpty
158+ ? _buildEmptyBody (context)
159+ : ListView .separated (
160+ physics: physics,
161+ padding: edgeInsetsL12T4R12B4,
162+ itemCount: pm.length,
163+ itemBuilder: (_, idx) => PersonalMessageCardV2 (pm.elementAt (idx)),
164+ separatorBuilder: (_, __) => sizedBoxW4H4,
165+ ),
166+ ),
167+ EasyRefresh .builder (
168+ controller: _broadcastMessageRefreshController,
169+ header: const MaterialHeader (),
170+ onRefresh: () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
171+ childBuilder:
172+ (context, physics) =>
173+ bm.isEmpty
174+ ? _buildEmptyBody (context)
175+ : ListView .separated (
176+ physics: physics,
177+ padding: edgeInsetsL12T4R12B4,
178+ itemCount: bm.length,
179+ itemBuilder: (_, idx) => BroadcastMessageCardV2 (bm.elementAt (idx)),
180+ separatorBuilder: (_, __) => sizedBoxW4H4,
181+ ),
182+ ),
183+ ],
130184 ),
131- EasyRefresh .builder (
132- controller: _personalMessageRefreshController,
133- header: const MaterialHeader (),
134- onRefresh: () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
135- childBuilder:
136- (context, physics) =>
137- pm.isEmpty
138- ? _buildEmptyBody (context)
139- : ListView .separated (
140- physics: physics,
141- padding: edgeInsetsL12T4R12B4,
142- itemCount: pm.length,
143- itemBuilder: (_, idx) => PersonalMessageCardV2 (pm.elementAt (idx)),
144- separatorBuilder: (_, __) => sizedBoxW4H4,
145- ),
185+ NotificationStatus .failure =>
186+ buildRetryButton (
187+ context,
188+ () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
146189 ),
147- EasyRefresh .builder (
148- controller: _broadcastMessageRefreshController,
149- header: const MaterialHeader (),
150- onRefresh: () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
151- childBuilder:
152- (context, physics) =>
153- bm.isEmpty
154- ? _buildEmptyBody (context)
155- : ListView .separated (
156- physics: physics,
157- padding: edgeInsetsL12T4R12B4,
158- itemCount: bm.length,
159- itemBuilder: (_, idx) => BroadcastMessageCardV2 (bm.elementAt (idx)),
160- separatorBuilder: (_, __) => sizedBoxW4H4,
161- ),
162- ),
163- ],
164- ),
165- NotificationStatus .failure => buildRetryButton (
166- context,
167- () => context.read <NotificationBloc >().add (NotificationUpdateAllRequested ()),
168- ),
169190 };
170191 return Scaffold (
171192 appBar: AppBar (
@@ -179,40 +200,45 @@ class _NotificationPageState extends State<NotificationPage> with SingleTickerPr
179200 setState (() => onlyShowUnread = ! onlyShowUnread);
180201 },
181202 ),
203+ IconButton (
204+ icon: const Icon (Icons .saved_search_outlined),
205+ onPressed: () => context.pushNamed (ScreenPaths .noticeSearch),
206+ ),
182207 PopupMenuButton <_Actions >(
183208 itemBuilder:
184- (_) => [
185- PopupMenuItem (
186- value: _Actions .markAllNoticeAsRead,
187- child: Row (
188- children: [
189- const Icon (Icons .notifications_paused_outlined),
190- sizedBoxPopupMenuItemIconSpacing,
191- Text (tr.cardMenu.markAllNoticeAsRead),
192- ],
193- ),
194- ),
195- PopupMenuItem (
196- value: _Actions .markAllPersonalMessageAsRead,
197- child: Row (
198- children: [
199- const Icon (Icons .notifications_active_outlined),
200- sizedBoxPopupMenuItemIconSpacing,
201- Text (tr.cardMenu.markAllPersonalMessageAsRead),
202- ],
203- ),
204- ),
205- PopupMenuItem (
206- value: _Actions .markAllBroadcastMessageAsRead,
207- child: Row (
208- children: [
209- const Icon (Icons .notification_important_outlined),
210- sizedBoxPopupMenuItemIconSpacing,
211- Text (tr.cardMenu.markAllBroadcastMessageAsRead),
212- ],
213- ),
214- ),
215- ],
209+ (_) =>
210+ [
211+ PopupMenuItem (
212+ value: _Actions .markAllNoticeAsRead,
213+ child: Row (
214+ children: [
215+ const Icon (Icons .notifications_paused_outlined),
216+ sizedBoxPopupMenuItemIconSpacing,
217+ Text (tr.cardMenu.markAllNoticeAsRead),
218+ ],
219+ ),
220+ ),
221+ PopupMenuItem (
222+ value: _Actions .markAllPersonalMessageAsRead,
223+ child: Row (
224+ children: [
225+ const Icon (Icons .notifications_active_outlined),
226+ sizedBoxPopupMenuItemIconSpacing,
227+ Text (tr.cardMenu.markAllPersonalMessageAsRead),
228+ ],
229+ ),
230+ ),
231+ PopupMenuItem (
232+ value: _Actions .markAllBroadcastMessageAsRead,
233+ child: Row (
234+ children: [
235+ const Icon (Icons .notification_important_outlined),
236+ sizedBoxPopupMenuItemIconSpacing,
237+ Text (tr.cardMenu.markAllBroadcastMessageAsRead),
238+ ],
239+ ),
240+ ),
241+ ],
216242 onSelected: (value) async {
217243 final noticeType = switch (value) {
218244 _Actions .markAllNoticeAsRead => NotificationType .notice,
@@ -252,16 +278,21 @@ class _PreferredSizeComponentBottom extends StatelessWidget implements Preferred
252278 builder: (context, state) {
253279 return switch (state) {
254280 AutoNoticeStateStopped () => sizedBoxW2H2,
255- AutoNoticeStateTicking (: final total, : final remain) => LinearProgressIndicator (
256- value: math.max (1 - remain.inSeconds / total.inSeconds, 0 ),
257- minHeight: 2 ,
258- ),
281+ AutoNoticeStateTicking (: final total, : final remain) =>
282+ LinearProgressIndicator (
283+ value: math.max (1 - remain.inSeconds / total.inSeconds, 0 ),
284+ minHeight: 2 ,
285+ ),
259286 AutoNoticeStatePending () => const LinearProgressIndicator (minHeight: 2 ),
260- AutoNoticeStatePaused (: final total, : final remain) => LinearProgressIndicator (
261- value: math.max (1 - remain.inSeconds / total.inSeconds, 0 ),
262- minHeight: 2 ,
263- color: Theme .of (context).colorScheme.outline,
264- ),
287+ AutoNoticeStatePaused (: final total, : final remain) =>
288+ LinearProgressIndicator (
289+ value: math.max (1 - remain.inSeconds / total.inSeconds, 0 ),
290+ minHeight: 2 ,
291+ color: Theme
292+ .of (context)
293+ .colorScheme
294+ .outline,
295+ ),
265296 };
266297 },
267298 ),
0 commit comments