100 lines
3.6 KiB
Dart
100 lines
3.6 KiB
Dart
import 'package:dio/dio.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:injectable/injectable.dart';
|
|
import '../../../../core/utils/logger.dart';
|
|
import 'unified_feed_event.dart';
|
|
import 'unified_feed_state.dart';
|
|
import '../../domain/entities/feed_item.dart';
|
|
import '../../data/repositories/feed_repository.dart';
|
|
|
|
/// BLoC Centralisé pour le mur d'actualité (DRY).
|
|
/// Aucune logique graphique, juste la gestion d'états.
|
|
@injectable
|
|
class UnifiedFeedBloc extends Bloc<UnifiedFeedEvent, UnifiedFeedState> {
|
|
final FeedRepository _repository;
|
|
|
|
UnifiedFeedBloc(this._repository) : super(UnifiedFeedInitial()) {
|
|
on<LoadFeedRequested>(_onLoadFeedRequested);
|
|
on<FeedLoadMoreRequested>(_onLoadMoreRequested);
|
|
on<ClearLoadMoreError>(_onClearLoadMoreError);
|
|
on<FeedItemLiked>(_onFeedItemLiked);
|
|
}
|
|
|
|
void _onClearLoadMoreError(ClearLoadMoreError event, Emitter<UnifiedFeedState> emit) {
|
|
if (state is UnifiedFeedLoaded) {
|
|
emit((state as UnifiedFeedLoaded).copyWith(loadMoreErrorMessage: null));
|
|
}
|
|
}
|
|
|
|
Future<void> _onLoadFeedRequested(LoadFeedRequested event, Emitter<UnifiedFeedState> emit) async {
|
|
if (!event.isRefresh) {
|
|
emit(UnifiedFeedLoading());
|
|
}
|
|
|
|
try {
|
|
final items = await _repository.getFeed(page: 0, size: 10);
|
|
|
|
// On suppose qu'on n'a pas atteint la fin si on a reçu la taille max demandée (10)
|
|
final hasReachedMax = items.length < 10;
|
|
|
|
emit(UnifiedFeedLoaded(items: items, hasReachedMax: hasReachedMax));
|
|
} catch (e) {
|
|
if (e is DioException && e.type == DioExceptionType.cancel) return;
|
|
emit(UnifiedFeedError('Erreur de chargement du flux: $e'));
|
|
}
|
|
}
|
|
|
|
Future<void> _onLoadMoreRequested(FeedLoadMoreRequested event, Emitter<UnifiedFeedState> emit) async {
|
|
if (state is UnifiedFeedLoaded) {
|
|
final currentState = state as UnifiedFeedLoaded;
|
|
if (currentState.hasReachedMax || currentState.isFetchingMore) return;
|
|
|
|
emit(currentState.copyWith(isFetchingMore: true));
|
|
|
|
try {
|
|
final nextPage = (currentState.items.length / 10).floor();
|
|
final moreItems = await _repository.getFeed(page: nextPage, size: 10);
|
|
|
|
emit(currentState.copyWith(
|
|
items: List.of(currentState.items)..addAll(moreItems),
|
|
hasReachedMax: moreItems.isEmpty,
|
|
isFetchingMore: false,
|
|
));
|
|
} catch (e, st) {
|
|
if (e is DioException && e.type == DioExceptionType.cancel) return;
|
|
AppLogger.error('UnifiedFeedBloc: chargement supplémentaire échoué', error: e, stackTrace: st);
|
|
emit(currentState.copyWith(
|
|
isFetchingMore: false,
|
|
loadMoreErrorMessage: 'Impossible de charger plus',
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
void _onFeedItemLiked(FeedItemLiked event, Emitter<UnifiedFeedState> emit) {
|
|
if (state is UnifiedFeedLoaded) {
|
|
final currentState = state as UnifiedFeedLoaded;
|
|
final updatedItems = currentState.items.map((item) {
|
|
if (item.id == event.itemId) {
|
|
return FeedItem(
|
|
id: item.id,
|
|
type: item.type,
|
|
authorName: item.authorName,
|
|
authorAvatarUrl: item.authorAvatarUrl,
|
|
createdAt: item.createdAt,
|
|
content: item.content,
|
|
likesCount: item.isLikedByMe ? item.likesCount - 1 : item.likesCount + 1,
|
|
commentsCount: item.commentsCount,
|
|
isLikedByMe: !item.isLikedByMe,
|
|
customActionLabel: item.customActionLabel,
|
|
actionUrlTarget: item.actionUrlTarget,
|
|
);
|
|
}
|
|
return item;
|
|
}).toList();
|
|
|
|
emit(currentState.copyWith(items: updatedItems));
|
|
}
|
|
}
|
|
}
|