@@ -70,24 +70,31 @@ class InAppNotificationCenterBloc
7070 return ;
7171 }
7272
73- // Fetch both tabs' initial data in parallel.
74- await Future .wait ([
75- _fetchNotifications (
76- emit: emit,
77- userId: userId,
78- filter: _breakingNewsFilter,
79- isInitialFetch: true ,
80- ),
81- _fetchNotifications (
82- emit: emit,
83- userId: userId,
84- filter: _digestFilter,
85- isInitialFetch: true ,
86- ),
87- ]);
73+ try {
74+ // Fetch both tabs' initial data in parallel and wait for their results.
75+ final results = await Future .wait ([
76+ _fetchNotifications (userId: userId, filter: _breakingNewsFilter),
77+ _fetchNotifications (userId: userId, filter: _digestFilter),
78+ ]);
79+
80+ final breakingNewsResponse = results[0 ];
81+ final digestResponse = results[1 ];
8882
89- // After both fetches are complete, set the status to success.
90- emit (state.copyWith (status: InAppNotificationCenterStatus .success));
83+ // Perform a single, atomic state update with both results.
84+ emit (
85+ state.copyWith (
86+ status: InAppNotificationCenterStatus .success,
87+ breakingNewsNotifications: breakingNewsResponse.items,
88+ breakingNewsHasMore: breakingNewsResponse.hasMore,
89+ breakingNewsCursor: breakingNewsResponse.cursor,
90+ digestNotifications: digestResponse.items,
91+ digestHasMore: digestResponse.hasMore,
92+ digestCursor: digestResponse.cursor,
93+ ),
94+ );
95+ } catch (error, stackTrace) {
96+ _handleFetchError (emit, error, stackTrace);
97+ }
9198 }
9299
93100 /// Handles fetching the next page of notifications for the current tab.
@@ -120,15 +127,42 @@ class InAppNotificationCenterBloc
120127 ? state.breakingNewsCursor
121128 : state.digestCursor;
122129
123- await _fetchNotifications (
124- emit : emit,
125- userId: userId,
126- filter: filter,
127- cursor: cursor,
128- );
130+ try {
131+ final response = await _fetchNotifications (
132+ userId: userId,
133+ filter: filter,
134+ cursor: cursor,
135+ );
129136
130- // After fetch, set status back to success.
131- emit (state.copyWith (status: InAppNotificationCenterStatus .success));
137+ // Append the new items to the correct list.
138+ if (isBreakingNewsTab) {
139+ emit (
140+ state.copyWith (
141+ status: InAppNotificationCenterStatus .success,
142+ breakingNewsNotifications: [
143+ ...state.breakingNewsNotifications,
144+ ...response.items,
145+ ],
146+ breakingNewsHasMore: response.hasMore,
147+ breakingNewsCursor: response.cursor,
148+ ),
149+ );
150+ } else {
151+ emit (
152+ state.copyWith (
153+ status: InAppNotificationCenterStatus .success,
154+ digestNotifications: [
155+ ...state.digestNotifications,
156+ ...response.items,
157+ ],
158+ digestHasMore: response.hasMore,
159+ digestCursor: response.cursor,
160+ ),
161+ );
162+ }
163+ } catch (error, stackTrace) {
164+ _handleFetchError (emit, error, stackTrace);
165+ }
132166 }
133167
134168 /// Handles the event to change the active tab.
@@ -303,64 +337,22 @@ class InAppNotificationCenterBloc
303337 }
304338
305339 /// A generic method to fetch notifications based on a filter.
306- Future <void > _fetchNotifications ({
307- required Emitter <InAppNotificationCenterState > emit,
340+ Future <PaginatedResponse <InAppNotification >> _fetchNotifications ({
308341 required String userId,
309342 required Map <String , dynamic > filter,
310343 String ? cursor,
311- bool isInitialFetch = false ,
312- }) {
313- final isBreakingNewsFilter = filter == _breakingNewsFilter;
314-
315- return _inAppNotificationRepository
316- .readAll (
317- userId: userId,
318- filter: filter,
319- pagination: PaginationOptions (
320- limit: _notificationsFetchLimit,
321- cursor: cursor,
322- ),
323- sort: [const SortOption ('createdAt' , SortOrder .desc)],
324- )
325- .then ((response) {
326- final newNotifications = response.items;
327- final nextCursor = response.cursor;
328- final hasMore = response.hasMore;
329-
330- if (isBreakingNewsFilter) {
331- emit (
332- state.copyWith (
333- breakingNewsNotifications: isInitialFetch
334- ? newNotifications
335- : [...state.breakingNewsNotifications, ...newNotifications],
336- breakingNewsHasMore: hasMore,
337- breakingNewsCursor: nextCursor,
338- ),
339- );
340- } else {
341- emit (
342- state.copyWith (
343- digestNotifications: isInitialFetch
344- ? newNotifications
345- : [...state.digestNotifications, ...newNotifications],
346- digestHasMore: hasMore,
347- digestCursor: nextCursor,
348- ),
349- );
350- }
351- })
352- .catchError ((Object e, StackTrace s) {
353- _logger.severe ('Failed to fetch notifications.' , e, s);
354- final httpException = e is HttpException
355- ? e
356- : UnknownException (e.toString ());
357- emit (
358- state.copyWith (
359- status: InAppNotificationCenterStatus .failure,
360- error: httpException,
361- ),
362- );
363- });
344+ }) async {
345+ // This method now simply fetches and returns the data, or throws on error.
346+ // The responsibility of emitting state is moved to the event handlers.
347+ return _inAppNotificationRepository.readAll (
348+ userId: userId,
349+ filter: filter,
350+ pagination: PaginationOptions (
351+ limit: _notificationsFetchLimit,
352+ cursor: cursor,
353+ ),
354+ sort: [const SortOption ('createdAt' , SortOrder .desc)],
355+ );
364356 }
365357
366358 /// Filter for "Breaking News" notifications.
@@ -389,4 +381,22 @@ class InAppNotificationCenterBloc
389381 ],
390382 },
391383 };
384+
385+ /// Centralized error handler for fetch operations.
386+ void _handleFetchError (
387+ Emitter <InAppNotificationCenterState > emit,
388+ Object error,
389+ StackTrace stackTrace,
390+ ) {
391+ _logger.severe ('Failed to fetch notifications.' , error, stackTrace);
392+ final httpException = error is HttpException
393+ ? error
394+ : UnknownException (error.toString ());
395+ emit (
396+ state.copyWith (
397+ status: InAppNotificationCenterStatus .failure,
398+ error: httpException,
399+ ),
400+ );
401+ }
392402}
0 commit comments