Skip to content

Commit bbf5668

Browse files
authored
Merge pull request #59 from headlines-toolkit/fix_sync_models
Fix sync models
2 parents 0b2b6bf + ebee66b commit bbf5668

File tree

97 files changed

+3132
-3264
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+3132
-3264
lines changed

lib/account/bloc/account_bloc.dart

Lines changed: 119 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:ht_auth_repository/ht_auth_repository.dart';
66
import 'package:ht_data_repository/ht_data_repository.dart';
77
import 'package:ht_main/app/config/config.dart' as local_config;
88
import 'package:ht_shared/ht_shared.dart';
9+
import 'package:logging/logging.dart';
910

1011
part 'account_event.dart';
1112
part 'account_state.dart';
@@ -16,9 +17,11 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
1617
required HtDataRepository<UserContentPreferences>
1718
userContentPreferencesRepository,
1819
required local_config.AppEnvironment environment,
20+
Logger? logger,
1921
}) : _authenticationRepository = authenticationRepository,
2022
_userContentPreferencesRepository = userContentPreferencesRepository,
2123
_environment = environment,
24+
_logger = logger ?? Logger('AccountBloc'),
2225
super(const AccountState()) {
2326
// Listen to user changes from HtAuthRepository
2427
_userSubscription = _authenticationRepository.authStateChanges.listen((
@@ -31,16 +34,16 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
3134
on<AccountUserChanged>(_onAccountUserChanged);
3235
on<AccountLoadUserPreferences>(_onAccountLoadUserPreferences);
3336
on<AccountSaveHeadlineToggled>(_onAccountSaveHeadlineToggled);
34-
on<AccountFollowCategoryToggled>(_onAccountFollowCategoryToggled);
37+
on<AccountFollowTopicToggled>(_onAccountFollowTopicToggled);
3538
on<AccountFollowSourceToggled>(_onAccountFollowSourceToggled);
36-
// AccountFollowCountryToggled handler removed
3739
on<AccountClearUserPreferences>(_onAccountClearUserPreferences);
3840
}
3941

4042
final HtAuthRepository _authenticationRepository;
4143
final HtDataRepository<UserContentPreferences>
4244
_userContentPreferencesRepository;
4345
final local_config.AppEnvironment _environment;
46+
final Logger _logger;
4447
late StreamSubscription<User?> _userSubscription;
4548

4649
Future<void> _onAccountUserChanged(
@@ -72,7 +75,7 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
7275
state.copyWith(
7376
status: AccountStatus.success,
7477
preferences: preferences,
75-
clearErrorMessage: true,
78+
clearError: true,
7679
),
7780
);
7881
} on NotFoundException {
@@ -86,48 +89,54 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
8689
if (_environment == local_config.AppEnvironment.demo) {
8790
// ignore: inference_failure_on_instance_creation
8891
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.
9194
try {
9295
final migratedPreferences = await _userContentPreferencesRepository
9396
.read(id: event.userId, userId: event.userId);
9497
emit(
9598
state.copyWith(
9699
status: AccountStatus.success,
97100
preferences: migratedPreferences,
98-
clearErrorMessage: true,
101+
clearError: true,
99102
),
100103
);
101104
return; // Exit if successfully read after migration
102105
} on NotFoundException {
103106
// Still not found after delay, proceed to create default.
104-
print(
107+
_logger.info(
105108
'[AccountBloc] UserContentPreferences still not found after '
106109
'migration delay. Creating default preferences.',
107110
);
108111
}
109112
}
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+
);
113122
try {
114123
await _userContentPreferencesRepository.create(
115124
item: defaultPreferences,
116125
userId: event.userId,
117126
);
118127
emit(
119128
state.copyWith(
120-
status: AccountStatus.success,
121129
preferences: defaultPreferences,
122-
clearErrorMessage: true,
130+
clearError: true,
131+
status: AccountStatus.success,
123132
),
124133
);
125134
} on ConflictException {
126135
// 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(
131140
'[AccountBloc] Conflict during creation of UserContentPreferences. '
132141
'Attempting to re-read.',
133142
);
@@ -137,26 +146,44 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
137146
state.copyWith(
138147
status: AccountStatus.success,
139148
preferences: existingPreferences,
140-
clearErrorMessage: true,
149+
clearError: true,
141150
),
142151
);
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+
);
144163
emit(
145164
state.copyWith(
146165
status: AccountStatus.failure,
147-
errorMessage: 'Failed to create default preferences: $e',
166+
error: OperationFailedException(
167+
'Failed to create default preferences: $e',
168+
),
148169
),
149170
);
150171
}
151172
} 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,
154182
);
155-
} catch (e) {
156183
emit(
157184
state.copyWith(
158185
status: AccountStatus.failure,
159-
errorMessage: 'An unexpected error occurred.',
186+
error: OperationFailedException('An unexpected error occurred: $e'),
160187
),
161188
);
162189
}
@@ -197,46 +224,51 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
197224
state.copyWith(
198225
status: AccountStatus.success,
199226
preferences: updatedPrefs,
200-
clearErrorMessage: true,
227+
clearError: true,
201228
),
202229
);
203230
} 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,
206240
);
207-
} catch (e) {
208241
emit(
209242
state.copyWith(
210243
status: AccountStatus.failure,
211-
errorMessage: 'Failed to update saved headlines.',
244+
error: OperationFailedException(
245+
'Failed to update saved headlines: $e',
246+
),
212247
),
213248
);
214249
}
215250
}
216251

217-
Future<void> _onAccountFollowCategoryToggled(
218-
AccountFollowCategoryToggled event,
252+
Future<void> _onAccountFollowTopicToggled(
253+
AccountFollowTopicToggled event,
219254
Emitter<AccountState> emit,
220255
) async {
221256
if (state.user == null || state.preferences == null) return;
222257
emit(state.copyWith(status: AccountStatus.loading));
223258

224259
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,
227262
);
228-
final List<Category> updatedFollowedCategories;
263+
final List<Topic> updatedFollowedTopics;
229264

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));
237269

238270
final updatedPrefs = currentPrefs.copyWith(
239-
followedCategories: updatedFollowedCategories,
271+
followedTopics: updatedFollowedTopics,
240272
);
241273

242274
try {
@@ -249,18 +281,26 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
249281
state.copyWith(
250282
status: AccountStatus.success,
251283
preferences: updatedPrefs,
252-
clearErrorMessage: true,
284+
clearError: true,
253285
),
254286
);
255287
} 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,
258297
);
259-
} catch (e) {
260298
emit(
261299
state.copyWith(
262300
status: AccountStatus.failure,
263-
errorMessage: 'Failed to update followed categories.',
301+
error: OperationFailedException(
302+
'Failed to update followed topics: $e',
303+
),
264304
),
265305
);
266306
}
@@ -301,33 +341,45 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
301341
state.copyWith(
302342
status: AccountStatus.success,
303343
preferences: updatedPrefs,
304-
clearErrorMessage: true,
344+
clearError: true,
305345
),
306346
);
307347
} 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,
310357
);
311-
} catch (e) {
312358
emit(
313359
state.copyWith(
314360
status: AccountStatus.failure,
315-
errorMessage: 'Failed to update followed sources.',
361+
error: OperationFailedException(
362+
'Failed to update followed sources: $e',
363+
),
316364
),
317365
);
318366
}
319367
}
320368

321-
// _onAccountFollowCountryToggled method removed
322-
323369
Future<void> _onAccountClearUserPreferences(
324370
AccountClearUserPreferences event,
325371
Emitter<AccountState> emit,
326372
) async {
327373
emit(state.copyWith(status: AccountStatus.loading));
328374
try {
329375
// 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+
);
331383
await _userContentPreferencesRepository.update(
332384
id: event.userId,
333385
item: defaultPreferences,
@@ -337,18 +389,26 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
337389
state.copyWith(
338390
status: AccountStatus.success,
339391
preferences: defaultPreferences,
340-
clearErrorMessage: true,
392+
clearError: true,
341393
),
342394
);
343395
} 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,
346405
);
347-
} catch (e) {
348406
emit(
349407
state.copyWith(
350408
status: AccountStatus.failure,
351-
errorMessage: 'Failed to clear user preferences.',
409+
error: OperationFailedException(
410+
'Failed to clear user preferences: $e',
411+
),
352412
),
353413
);
354414
}

lib/account/bloc/account_event.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ class AccountSaveHeadlineToggled extends AccountEvent {
3333
List<Object> get props => [headline];
3434
}
3535

36-
class AccountFollowCategoryToggled extends AccountEvent {
37-
const AccountFollowCategoryToggled({required this.category});
38-
final Category category;
36+
class AccountFollowTopicToggled extends AccountEvent {
37+
const AccountFollowTopicToggled({required this.topic});
38+
final Topic topic;
3939

4040
@override
41-
List<Object> get props => [category];
41+
List<Object> get props => [topic];
4242
}
4343

4444
class AccountFollowSourceToggled extends AccountEvent {

0 commit comments

Comments
 (0)