- NotImplementedFailure: ajout userFriendlyMessage et icon construction (blue) - ErrorDisplayWidget: support spécial pour NotImplementedFailure (bientôt disponible) - SnackbarHelper: classe centralisée pour messages cohérents (success, error, warning, info, notImplemented) - budgets_list_page: remplace generic snackbar par SnackbarHelper.showNotImplemented - conversations_page: remplace 2 TODOs par SnackbarHelper.showNotImplemented - export_members: met à jour TODO obsolète (endpoint PDF maintenant disponible) - cache_service: fix AppLogger.error calls (error: named param) - cached_datasource_decorator: fix AppLogger.error call Task #64 - Fix Snackbar Placeholders + NotImplementedFailure UX
214 lines
6.0 KiB
Dart
214 lines
6.0 KiB
Dart
/// Centralized helper for showing consistent Snackbar messages
|
|
library snackbar_helper;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import '../../core/error/failures.dart';
|
|
|
|
/// Helper class for showing consistent Snackbar messages throughout the app
|
|
class SnackbarHelper {
|
|
/// Show success message
|
|
static void showSuccess(
|
|
BuildContext context,
|
|
String message, {
|
|
Duration duration = const Duration(seconds: 3),
|
|
SnackBarAction? action,
|
|
}) {
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const Icon(Icons.check_circle, color: Colors.white),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(message)),
|
|
],
|
|
),
|
|
backgroundColor: Colors.green[700],
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: duration,
|
|
action: action,
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Show error message
|
|
static void showError(
|
|
BuildContext context,
|
|
String message, {
|
|
Duration duration = const Duration(seconds: 4),
|
|
VoidCallback? onRetry,
|
|
}) {
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const Icon(Icons.error_outline, color: Colors.white),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(message)),
|
|
],
|
|
),
|
|
backgroundColor: Colors.red[700],
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: duration,
|
|
action: onRetry != null
|
|
? SnackBarAction(
|
|
label: 'Réessayer',
|
|
textColor: Colors.white,
|
|
onPressed: onRetry,
|
|
)
|
|
: null,
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Show warning message
|
|
static void showWarning(
|
|
BuildContext context,
|
|
String message, {
|
|
Duration duration = const Duration(seconds: 4),
|
|
}) {
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const Icon(Icons.warning_amber, color: Colors.white),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(message)),
|
|
],
|
|
),
|
|
backgroundColor: Colors.orange[700],
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: duration,
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Show info message
|
|
static void showInfo(
|
|
BuildContext context,
|
|
String message, {
|
|
Duration duration = const Duration(seconds: 3),
|
|
}) {
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const Icon(Icons.info_outline, color: Colors.white),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(message)),
|
|
],
|
|
),
|
|
backgroundColor: Colors.blue[700],
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: duration,
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Show "not implemented" message with appropriate styling
|
|
static void showNotImplemented(
|
|
BuildContext context,
|
|
String? featureName,
|
|
) {
|
|
final message = featureName != null
|
|
? '$featureName sera bientôt disponible !'
|
|
: 'Cette fonctionnalité sera bientôt disponible !';
|
|
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const Icon(Icons.construction, color: Colors.white),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(message)),
|
|
],
|
|
),
|
|
backgroundColor: Colors.blue[700],
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: const Duration(seconds: 4),
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Show failure with appropriate styling based on failure type
|
|
static void showFailure(
|
|
BuildContext context,
|
|
Failure failure, {
|
|
VoidCallback? onRetry,
|
|
}) {
|
|
// Handle NotImplementedFailure specially
|
|
if (failure is NotImplementedFailure) {
|
|
showNotImplemented(context, null);
|
|
return;
|
|
}
|
|
|
|
Color backgroundColor;
|
|
IconData icon;
|
|
|
|
if (failure is NetworkFailure) {
|
|
backgroundColor = Colors.orange[700]!;
|
|
icon = Icons.wifi_off;
|
|
} else if (failure is UnauthorizedFailure) {
|
|
backgroundColor = Colors.red[700]!;
|
|
icon = Icons.lock_outline;
|
|
} else if (failure is ForbiddenFailure) {
|
|
backgroundColor = Colors.deepOrange[700]!;
|
|
icon = Icons.block;
|
|
} else if (failure is ValidationFailure) {
|
|
backgroundColor = Colors.amber[700]!;
|
|
icon = Icons.error_outline;
|
|
} else {
|
|
backgroundColor = Colors.red[700]!;
|
|
icon = Icons.error_outline;
|
|
}
|
|
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
Icon(icon, color: Colors.white),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(failure.getUserMessage())),
|
|
],
|
|
),
|
|
backgroundColor: backgroundColor,
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: Duration(seconds: failure.isRetryable ? 6 : 4),
|
|
action: failure.isRetryable && onRetry != null
|
|
? SnackBarAction(
|
|
label: 'Réessayer',
|
|
textColor: Colors.white,
|
|
onPressed: onRetry,
|
|
)
|
|
: null,
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Show loading message (use with caution - prefer progress indicators)
|
|
static void showLoading(
|
|
BuildContext context,
|
|
String message, {
|
|
Duration duration = const Duration(seconds: 2),
|
|
}) {
|
|
final snackBar = SnackBar(
|
|
content: Row(
|
|
children: [
|
|
const SizedBox(
|
|
width: 16,
|
|
height: 16,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
|
),
|
|
),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: Text(message)),
|
|
],
|
|
),
|
|
backgroundColor: Colors.grey[800],
|
|
behavior: SnackBarBehavior.floating,
|
|
duration: duration,
|
|
);
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
/// Dismiss current Snackbar
|
|
static void dismiss(BuildContext context) {
|
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
|
}
|
|
}
|