- Replace flutter_appauth with custom WebView implementation to resolve deep link issues - Add KeycloakWebViewAuthService with integrated WebView for seamless authentication - Configure Android manifest for HTTP cleartext traffic support - Add network security config for development environment (192.168.1.11) - Update Keycloak client to use HTTP callback endpoint (http://192.168.1.11:8080/auth/callback) - Remove obsolete keycloak_auth_service.dart and temporary scripts - Clean up dependencies and regenerate injection configuration - Tested successfully on multiple Android devices (Xiaomi 2201116TG, SM A725F) BREAKING CHANGE: Authentication flow now uses WebView instead of external browser - Users will see Keycloak login page within the app instead of browser redirect - Resolves ERR_CLEARTEXT_NOT_PERMITTED and deep link state management issues - Maintains full OIDC compliance with PKCE flow and secure token storage Technical improvements: - WebView with custom navigation delegate for callback handling - Automatic token extraction and user info parsing from JWT - Proper error handling and user feedback - Consistent authentication state management across app lifecycle
143 lines
3.3 KiB
Dart
143 lines
3.3 KiB
Dart
import 'package:equatable/equatable.dart';
|
|
import '../../../../core/models/evenement_model.dart';
|
|
|
|
/// États du BLoC Evenement
|
|
abstract class EvenementState extends Equatable {
|
|
const EvenementState();
|
|
|
|
@override
|
|
List<Object?> get props => [];
|
|
}
|
|
|
|
/// État initial
|
|
class EvenementInitial extends EvenementState {
|
|
const EvenementInitial();
|
|
}
|
|
|
|
/// État de chargement
|
|
class EvenementLoading extends EvenementState {
|
|
const EvenementLoading();
|
|
}
|
|
|
|
/// État de chargement avec données existantes (pour pagination)
|
|
class EvenementLoadingMore extends EvenementState {
|
|
final List<EvenementModel> evenements;
|
|
|
|
const EvenementLoadingMore(this.evenements);
|
|
|
|
@override
|
|
List<Object?> get props => [evenements];
|
|
}
|
|
|
|
/// État de succès avec liste d'événements
|
|
class EvenementLoaded extends EvenementState {
|
|
final List<EvenementModel> evenements;
|
|
final bool hasReachedMax;
|
|
final int currentPage;
|
|
final String? searchTerm;
|
|
final TypeEvenement? filterType;
|
|
|
|
const EvenementLoaded({
|
|
required this.evenements,
|
|
this.hasReachedMax = false,
|
|
this.currentPage = 0,
|
|
this.searchTerm,
|
|
this.filterType,
|
|
});
|
|
|
|
EvenementLoaded copyWith({
|
|
List<EvenementModel>? evenements,
|
|
bool? hasReachedMax,
|
|
int? currentPage,
|
|
String? searchTerm,
|
|
TypeEvenement? filterType,
|
|
}) {
|
|
return EvenementLoaded(
|
|
evenements: evenements ?? this.evenements,
|
|
hasReachedMax: hasReachedMax ?? this.hasReachedMax,
|
|
currentPage: currentPage ?? this.currentPage,
|
|
searchTerm: searchTerm ?? this.searchTerm,
|
|
filterType: filterType ?? this.filterType,
|
|
);
|
|
}
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
evenements,
|
|
hasReachedMax,
|
|
currentPage,
|
|
searchTerm,
|
|
filterType,
|
|
];
|
|
}
|
|
|
|
/// État de succès avec un événement spécifique
|
|
class EvenementDetailLoaded extends EvenementState {
|
|
final EvenementModel evenement;
|
|
|
|
const EvenementDetailLoaded(this.evenement);
|
|
|
|
@override
|
|
List<Object?> get props => [evenement];
|
|
}
|
|
|
|
/// État de succès avec statistiques
|
|
class EvenementStatistiquesLoaded extends EvenementState {
|
|
final Map<String, dynamic> statistiques;
|
|
|
|
const EvenementStatistiquesLoaded(this.statistiques);
|
|
|
|
@override
|
|
List<Object?> get props => [statistiques];
|
|
}
|
|
|
|
/// État de succès après création/modification
|
|
class EvenementOperationSuccess extends EvenementState {
|
|
final String message;
|
|
final EvenementModel? evenement;
|
|
|
|
const EvenementOperationSuccess({
|
|
required this.message,
|
|
this.evenement,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [message, evenement];
|
|
}
|
|
|
|
/// État d'erreur
|
|
class EvenementError extends EvenementState {
|
|
final String message;
|
|
final List<EvenementModel>? evenements; // Pour conserver les données en cas d'erreur de pagination
|
|
|
|
const EvenementError({
|
|
required this.message,
|
|
this.evenements,
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [message, evenements];
|
|
}
|
|
|
|
/// État de recherche vide
|
|
class EvenementSearchEmpty extends EvenementState {
|
|
final String searchTerm;
|
|
|
|
const EvenementSearchEmpty(this.searchTerm);
|
|
|
|
@override
|
|
List<Object?> get props => [searchTerm];
|
|
}
|
|
|
|
/// État de liste vide
|
|
class EvenementEmpty extends EvenementState {
|
|
final String message;
|
|
|
|
const EvenementEmpty({
|
|
this.message = 'Aucun événement trouvé',
|
|
});
|
|
|
|
@override
|
|
List<Object?> get props => [message];
|
|
}
|