284299b946
Complete Flutter app (Android + iOS) mirroring the web frontend: - Core: Riverpod state, Dio networking with auth interceptor + auto-refresh, go_router navigation, flutter_secure_storage, light/dark theme with MedievalSharp/Crimson Pro fonts, German l10n - Market: search with text/GPS/radius/date/sort filters, list + map views (flutter_map + OSM), detail screen with opening hours, admission prices, single-marker map, pagination - Auth: login (password + magic link tabs), register, OAuth button placeholders, 2FA code prompt on 401, sealed auth state provider - User: profile view/edit/delete with confirm dialog, 2FA setup/disable on security screen - GPS: geolocator with IP-based fallback (geojs.io) matching web behavior - Platform: Android internet + location permissions, iOS NSLocation description - Tests: date/currency/distance formatter unit tests (13 passing) - Zero analysis issues, debug APK builds successfully
50 lines
1.4 KiB
Dart
50 lines
1.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../../core/network/api_exception.dart';
|
|
|
|
class ErrorDisplay extends StatelessWidget {
|
|
final Object error;
|
|
final VoidCallback? onRetry;
|
|
|
|
const ErrorDisplay({super.key, required this.error, this.onRetry});
|
|
|
|
String get _message {
|
|
if (error is ApiException) return (error as ApiException).message;
|
|
return error.toString();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
return Center(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Icon(Icons.error_outline, size: 48, color: theme.colorScheme.error),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
'Fehler',
|
|
style: theme.textTheme.titleMedium,
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
_message,
|
|
style: theme.textTheme.bodyMedium,
|
|
textAlign: TextAlign.center,
|
|
),
|
|
if (onRetry != null) ...[
|
|
const SizedBox(height: 16),
|
|
ElevatedButton.icon(
|
|
onPressed: onRetry,
|
|
icon: const Icon(Icons.refresh),
|
|
label: const Text('Erneut versuchen'),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|