@@ -6,6 +6,7 @@ import 'package:ht_auth_repository/ht_auth_repository.dart';
6
6
import 'package:ht_data_repository/ht_data_repository.dart' ;
7
7
import 'package:ht_main/app/config/config.dart' as local_config;
8
8
import 'package:ht_shared/ht_shared.dart' ;
9
+ import 'package:logging/logging.dart' ;
9
10
10
11
part 'account_event.dart' ;
11
12
part 'account_state.dart' ;
@@ -16,9 +17,11 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
16
17
required HtDataRepository <UserContentPreferences >
17
18
userContentPreferencesRepository,
18
19
required local_config.AppEnvironment environment,
20
+ Logger ? logger,
19
21
}) : _authenticationRepository = authenticationRepository,
20
22
_userContentPreferencesRepository = userContentPreferencesRepository,
21
23
_environment = environment,
24
+ _logger = logger ?? Logger ('AccountBloc' ),
22
25
super (const AccountState ()) {
23
26
// Listen to user changes from HtAuthRepository
24
27
_userSubscription = _authenticationRepository.authStateChanges.listen ((
@@ -31,16 +34,16 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
31
34
on < AccountUserChanged > (_onAccountUserChanged);
32
35
on < AccountLoadUserPreferences > (_onAccountLoadUserPreferences);
33
36
on < AccountSaveHeadlineToggled > (_onAccountSaveHeadlineToggled);
34
- on < AccountFollowCategoryToggled > (_onAccountFollowCategoryToggled );
37
+ on < AccountFollowTopicToggled > (_onAccountFollowTopicToggled );
35
38
on < AccountFollowSourceToggled > (_onAccountFollowSourceToggled);
36
- // AccountFollowCountryToggled handler removed
37
39
on < AccountClearUserPreferences > (_onAccountClearUserPreferences);
38
40
}
39
41
40
42
final HtAuthRepository _authenticationRepository;
41
43
final HtDataRepository <UserContentPreferences >
42
44
_userContentPreferencesRepository;
43
45
final local_config.AppEnvironment _environment;
46
+ final Logger _logger;
44
47
late StreamSubscription <User ?> _userSubscription;
45
48
46
49
Future <void > _onAccountUserChanged (
@@ -72,7 +75,7 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
72
75
state.copyWith (
73
76
status: AccountStatus .success,
74
77
preferences: preferences,
75
- clearErrorMessage : true ,
78
+ clearError : true ,
76
79
),
77
80
);
78
81
} on NotFoundException {
@@ -86,48 +89,54 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
86
89
if (_environment == local_config.AppEnvironment .demo) {
87
90
// ignore: inference_failure_on_instance_creation
88
91
await Future .delayed (const Duration (milliseconds: 50 ));
89
- // After delay, re-attempt to read the preferences.
90
- // This is crucial because migration might have completed during the delay.
92
+ // After delay, re-attempt to read the preferences. This is crucial
93
+ // because migration might have completed during the delay.
91
94
try {
92
95
final migratedPreferences = await _userContentPreferencesRepository
93
96
.read (id: event.userId, userId: event.userId);
94
97
emit (
95
98
state.copyWith (
96
99
status: AccountStatus .success,
97
100
preferences: migratedPreferences,
98
- clearErrorMessage : true ,
101
+ clearError : true ,
99
102
),
100
103
);
101
104
return ; // Exit if successfully read after migration
102
105
} on NotFoundException {
103
106
// Still not found after delay, proceed to create default.
104
- print (
107
+ _logger. info (
105
108
'[AccountBloc] UserContentPreferences still not found after '
106
109
'migration delay. Creating default preferences.' ,
107
110
);
108
111
}
109
112
}
110
- // If preferences not found (either initially or after re-attempt),
111
- // create a default one for the user.
112
- final defaultPreferences = UserContentPreferences (id: event.userId);
113
+ // If preferences not found (either initially or after re-attempt), create
114
+ // a default one for the user.
115
+ final defaultPreferences = UserContentPreferences (
116
+ id: event.userId,
117
+ followedCountries: const [],
118
+ followedSources: const [],
119
+ followedTopics: const [],
120
+ savedHeadlines: const [],
121
+ );
113
122
try {
114
123
await _userContentPreferencesRepository.create (
115
124
item: defaultPreferences,
116
125
userId: event.userId,
117
126
);
118
127
emit (
119
128
state.copyWith (
120
- status: AccountStatus .success,
121
129
preferences: defaultPreferences,
122
- clearErrorMessage: true ,
130
+ clearError: true ,
131
+ status: AccountStatus .success,
123
132
),
124
133
);
125
134
} on ConflictException {
126
135
// If a conflict occurs during creation (e.g., another process
127
- // created it concurrently), attempt to read it again to get the
128
- // existing one. This can happen if the migration service
129
- // created it right after the second NotFoundException.
130
- print (
136
+ // created it concurrently), attempt to read it again to get the existing
137
+ // one. This can happen if the migration service created it right after
138
+ // the second NotFoundException.
139
+ _logger. info (
131
140
'[AccountBloc] Conflict during creation of UserContentPreferences. '
132
141
'Attempting to re-read.' ,
133
142
);
@@ -137,26 +146,44 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
137
146
state.copyWith (
138
147
status: AccountStatus .success,
139
148
preferences: existingPreferences,
140
- clearErrorMessage : true ,
149
+ clearError : true ,
141
150
),
142
151
);
143
- } catch (e) {
152
+ } on HtHttpException catch (e) {
153
+ _logger.severe (
154
+ 'Failed to create default preferences with HtHttpException: $e ' ,
155
+ );
156
+ emit (state.copyWith (status: AccountStatus .failure, error: e));
157
+ } catch (e, st) {
158
+ _logger.severe (
159
+ 'Failed to create default preferences with unexpected error: $e ' ,
160
+ e,
161
+ st,
162
+ );
144
163
emit (
145
164
state.copyWith (
146
165
status: AccountStatus .failure,
147
- errorMessage: 'Failed to create default preferences: $e ' ,
166
+ error: OperationFailedException (
167
+ 'Failed to create default preferences: $e ' ,
168
+ ),
148
169
),
149
170
);
150
171
}
151
172
} on HtHttpException catch (e) {
152
- emit (
153
- state.copyWith (status: AccountStatus .failure, errorMessage: e.message),
173
+ _logger.severe (
174
+ 'AccountLoadUserPreferences failed with HtHttpException: $e ' ,
175
+ );
176
+ emit (state.copyWith (status: AccountStatus .failure, error: e));
177
+ } catch (e, st) {
178
+ _logger.severe (
179
+ 'AccountLoadUserPreferences failed with unexpected error: $e ' ,
180
+ e,
181
+ st,
154
182
);
155
- } catch (e) {
156
183
emit (
157
184
state.copyWith (
158
185
status: AccountStatus .failure,
159
- errorMessage : 'An unexpected error occurred.' ,
186
+ error : OperationFailedException ( 'An unexpected error occurred: $ e ' ) ,
160
187
),
161
188
);
162
189
}
@@ -197,46 +224,51 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
197
224
state.copyWith (
198
225
status: AccountStatus .success,
199
226
preferences: updatedPrefs,
200
- clearErrorMessage : true ,
227
+ clearError : true ,
201
228
),
202
229
);
203
230
} on HtHttpException catch (e) {
204
- emit (
205
- state.copyWith (status: AccountStatus .failure, errorMessage: e.message),
231
+ _logger.severe (
232
+ 'AccountSaveHeadlineToggled failed with HtHttpException: $e ' ,
233
+ );
234
+ emit (state.copyWith (status: AccountStatus .failure, error: e));
235
+ } catch (e, st) {
236
+ _logger.severe (
237
+ 'AccountSaveHeadlineToggled failed with unexpected error: $e ' ,
238
+ e,
239
+ st,
206
240
);
207
- } catch (e) {
208
241
emit (
209
242
state.copyWith (
210
243
status: AccountStatus .failure,
211
- errorMessage: 'Failed to update saved headlines.' ,
244
+ error: OperationFailedException (
245
+ 'Failed to update saved headlines: $e ' ,
246
+ ),
212
247
),
213
248
);
214
249
}
215
250
}
216
251
217
- Future <void > _onAccountFollowCategoryToggled (
218
- AccountFollowCategoryToggled event,
252
+ Future <void > _onAccountFollowTopicToggled (
253
+ AccountFollowTopicToggled event,
219
254
Emitter <AccountState > emit,
220
255
) async {
221
256
if (state.user == null || state.preferences == null ) return ;
222
257
emit (state.copyWith (status: AccountStatus .loading));
223
258
224
259
final currentPrefs = state.preferences! ;
225
- final isCurrentlyFollowed = currentPrefs.followedCategories .any (
226
- (c ) => c .id == event.category .id,
260
+ final isCurrentlyFollowed = currentPrefs.followedTopics .any (
261
+ (t ) => t .id == event.topic .id,
227
262
);
228
- final List <Category > updatedFollowedCategories ;
263
+ final List <Topic > updatedFollowedTopics ;
229
264
230
- if (isCurrentlyFollowed) {
231
- updatedFollowedCategories = List .from (currentPrefs.followedCategories)
232
- ..removeWhere ((c) => c.id == event.category.id);
233
- } else {
234
- updatedFollowedCategories = List .from (currentPrefs.followedCategories)
235
- ..add (event.category);
236
- }
265
+ updatedFollowedTopics = isCurrentlyFollowed
266
+ ? (List .from (currentPrefs.followedTopics)
267
+ ..removeWhere ((t) => t.id == event.topic.id))
268
+ : (List .from (currentPrefs.followedTopics)..add (event.topic));
237
269
238
270
final updatedPrefs = currentPrefs.copyWith (
239
- followedCategories : updatedFollowedCategories ,
271
+ followedTopics : updatedFollowedTopics ,
240
272
);
241
273
242
274
try {
@@ -249,18 +281,26 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
249
281
state.copyWith (
250
282
status: AccountStatus .success,
251
283
preferences: updatedPrefs,
252
- clearErrorMessage : true ,
284
+ clearError : true ,
253
285
),
254
286
);
255
287
} on HtHttpException catch (e) {
256
- emit (
257
- state.copyWith (status: AccountStatus .failure, errorMessage: e.message),
288
+ _logger.severe (
289
+ 'AccountFollowTopicToggled failed with HtHttpException: $e ' ,
290
+ );
291
+ emit (state.copyWith (status: AccountStatus .failure, error: e));
292
+ } catch (e, st) {
293
+ _logger.severe (
294
+ 'AccountFollowTopicToggled failed with unexpected error: $e ' ,
295
+ e,
296
+ st,
258
297
);
259
- } catch (e) {
260
298
emit (
261
299
state.copyWith (
262
300
status: AccountStatus .failure,
263
- errorMessage: 'Failed to update followed categories.' ,
301
+ error: OperationFailedException (
302
+ 'Failed to update followed topics: $e ' ,
303
+ ),
264
304
),
265
305
);
266
306
}
@@ -301,33 +341,45 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
301
341
state.copyWith (
302
342
status: AccountStatus .success,
303
343
preferences: updatedPrefs,
304
- clearErrorMessage : true ,
344
+ clearError : true ,
305
345
),
306
346
);
307
347
} on HtHttpException catch (e) {
308
- emit (
309
- state.copyWith (status: AccountStatus .failure, errorMessage: e.message),
348
+ _logger.severe (
349
+ 'AccountFollowSourceToggled failed with HtHttpException: $e ' ,
350
+ );
351
+ emit (state.copyWith (status: AccountStatus .failure, error: e));
352
+ } catch (e, st) {
353
+ _logger.severe (
354
+ 'AccountFollowSourceToggled failed with unexpected error: $e ' ,
355
+ e,
356
+ st,
310
357
);
311
- } catch (e) {
312
358
emit (
313
359
state.copyWith (
314
360
status: AccountStatus .failure,
315
- errorMessage: 'Failed to update followed sources.' ,
361
+ error: OperationFailedException (
362
+ 'Failed to update followed sources: $e ' ,
363
+ ),
316
364
),
317
365
);
318
366
}
319
367
}
320
368
321
- // _onAccountFollowCountryToggled method removed
322
-
323
369
Future <void > _onAccountClearUserPreferences (
324
370
AccountClearUserPreferences event,
325
371
Emitter <AccountState > emit,
326
372
) async {
327
373
emit (state.copyWith (status: AccountStatus .loading));
328
374
try {
329
375
// Create a new default preferences object to "clear" existing ones
330
- final defaultPreferences = UserContentPreferences (id: event.userId);
376
+ final defaultPreferences = UserContentPreferences (
377
+ id: event.userId,
378
+ followedCountries: const [],
379
+ followedSources: const [],
380
+ followedTopics: const [],
381
+ savedHeadlines: const [],
382
+ );
331
383
await _userContentPreferencesRepository.update (
332
384
id: event.userId,
333
385
item: defaultPreferences,
@@ -337,18 +389,26 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
337
389
state.copyWith (
338
390
status: AccountStatus .success,
339
391
preferences: defaultPreferences,
340
- clearErrorMessage : true ,
392
+ clearError : true ,
341
393
),
342
394
);
343
395
} on HtHttpException catch (e) {
344
- emit (
345
- state.copyWith (status: AccountStatus .failure, errorMessage: e.message),
396
+ _logger.severe (
397
+ 'AccountClearUserPreferences failed with HtHttpException: $e ' ,
398
+ );
399
+ emit (state.copyWith (status: AccountStatus .failure, error: e));
400
+ } catch (e, st) {
401
+ _logger.severe (
402
+ 'AccountClearUserPreferences failed with unexpected error: $e ' ,
403
+ e,
404
+ st,
346
405
);
347
- } catch (e) {
348
406
emit (
349
407
state.copyWith (
350
408
status: AccountStatus .failure,
351
- errorMessage: 'Failed to clear user preferences.' ,
409
+ error: OperationFailedException (
410
+ 'Failed to clear user preferences: $e ' ,
411
+ ),
352
412
),
353
413
);
354
414
}
0 commit comments