Initial commit: unionflow-mobile-apps
Application Flutter complète (sans build artifacts). Signed-off-by: lions dev Team
This commit is contained in:
83
lib/features/explore/presentation/bloc/network_bloc.dart
Normal file
83
lib/features/explore/presentation/bloc/network_bloc.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../../core/utils/logger.dart';
|
||||
import '../../data/repositories/network_repository.dart';
|
||||
import 'network_event.dart';
|
||||
import 'network_state.dart';
|
||||
|
||||
@injectable
|
||||
class NetworkBloc extends Bloc<NetworkEvent, NetworkState> {
|
||||
final NetworkRepository _repository;
|
||||
|
||||
NetworkBloc(this._repository) : super(NetworkInitial()) {
|
||||
on<LoadNetworkRequested>(_onLoadNetworkRequested);
|
||||
on<SearchNetworkRequested>(_onSearchNetworkRequested);
|
||||
on<ToggleFollowRequested>(_onToggleFollowRequested);
|
||||
}
|
||||
|
||||
Future<void> _onToggleFollowRequested(ToggleFollowRequested event, Emitter<NetworkState> emit) async {
|
||||
if (state is! NetworkLoaded) return;
|
||||
final current = state as NetworkLoaded;
|
||||
NetworkItem? item;
|
||||
for (final i in current.items) {
|
||||
if (i.id == event.itemId) {
|
||||
item = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (item == null) return;
|
||||
// Seuls les membres (type Member) sont persistés côté backend ; Organisation reste local.
|
||||
if (item.type != 'Member') {
|
||||
final items = current.items.map((i) {
|
||||
if (i.id == event.itemId) return i.copyWith(isConnected: !i.isConnected);
|
||||
return i;
|
||||
}).toList();
|
||||
emit(NetworkLoaded(items: items, currentQuery: current.currentQuery));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final bool newFollowing = item.isConnected
|
||||
? await _repository.unfollow(event.itemId)
|
||||
: await _repository.follow(event.itemId);
|
||||
final items = current.items.map((i) {
|
||||
if (i.id == event.itemId) return i.copyWith(isConnected: newFollowing);
|
||||
return i;
|
||||
}).toList();
|
||||
emit(NetworkLoaded(items: items, currentQuery: current.currentQuery));
|
||||
} catch (e, st) {
|
||||
AppLogger.error('NetworkBloc: toggle follow échoué', error: e, stackTrace: st);
|
||||
emit(const NetworkError('Impossible de mettre à jour le suivi. Réessayez.'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLoadNetworkRequested(LoadNetworkRequested event, Emitter<NetworkState> emit) async {
|
||||
emit(NetworkLoading());
|
||||
try {
|
||||
final followedIds = await _repository.getFollowedIds();
|
||||
final items = await _repository.search('', followedIds: followedIds.toSet());
|
||||
emit(NetworkLoaded(items: items, currentQuery: ''));
|
||||
} catch (e, st) {
|
||||
AppLogger.error('NetworkBloc: chargement réseau échoué', error: e, stackTrace: st);
|
||||
emit(NetworkError('Erreur chargement réseau : $e'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onSearchNetworkRequested(SearchNetworkRequested event, Emitter<NetworkState> emit) async {
|
||||
emit(NetworkLoading());
|
||||
try {
|
||||
if (event.query.trim().isEmpty) {
|
||||
final followedIds = await _repository.getFollowedIds();
|
||||
final items = await _repository.search('', followedIds: followedIds.toSet());
|
||||
emit(NetworkLoaded(items: items, currentQuery: ''));
|
||||
return;
|
||||
}
|
||||
final followedIds = await _repository.getFollowedIds();
|
||||
final items = await _repository.search(event.query, followedIds: followedIds.toSet());
|
||||
emit(NetworkLoaded(items: items, currentQuery: event.query));
|
||||
} catch (e, st) {
|
||||
AppLogger.error('NetworkBloc: recherche réseau échouée', error: e, stackTrace: st);
|
||||
emit(NetworkError('Erreur de recherche : $e'));
|
||||
}
|
||||
}
|
||||
}
|
||||
29
lib/features/explore/presentation/bloc/network_event.dart
Normal file
29
lib/features/explore/presentation/bloc/network_event.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class NetworkEvent extends Equatable {
|
||||
const NetworkEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class LoadNetworkRequested extends NetworkEvent {}
|
||||
|
||||
class SearchNetworkRequested extends NetworkEvent {
|
||||
final String query;
|
||||
|
||||
const SearchNetworkRequested(this.query);
|
||||
|
||||
@override
|
||||
List<Object> get props => [query];
|
||||
}
|
||||
|
||||
/// Bascule Suivre / Ne plus suivre pour un item (membre ou organisation).
|
||||
class ToggleFollowRequested extends NetworkEvent {
|
||||
final String itemId;
|
||||
|
||||
const ToggleFollowRequested(this.itemId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [itemId];
|
||||
}
|
||||
38
lib/features/explore/presentation/bloc/network_state.dart
Normal file
38
lib/features/explore/presentation/bloc/network_state.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
import '../../domain/entities/network_item.dart';
|
||||
|
||||
export '../../domain/entities/network_item.dart';
|
||||
|
||||
abstract class NetworkState extends Equatable {
|
||||
const NetworkState();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class NetworkInitial extends NetworkState {}
|
||||
|
||||
class NetworkLoading extends NetworkState {}
|
||||
|
||||
class NetworkLoaded extends NetworkState {
|
||||
final List<NetworkItem> items;
|
||||
final String currentQuery;
|
||||
|
||||
const NetworkLoaded({
|
||||
required this.items,
|
||||
this.currentQuery = '',
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [items, currentQuery];
|
||||
}
|
||||
|
||||
class NetworkError extends NetworkState {
|
||||
final String message;
|
||||
|
||||
const NetworkError(this.message);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [message];
|
||||
}
|
||||
Reference in New Issue
Block a user