feat: add error_handler and email verification request
This commit is contained in:
parent
defecf958a
commit
cdc5e44bb3
8 changed files with 110 additions and 26 deletions
|
|
@ -383,5 +383,13 @@
|
|||
"lobbyStatusEntering": "Betrete das Schlachtfeld...",
|
||||
|
||||
"connectivityError": "Keine Internetverbindung verfügbar.",
|
||||
"connectivityMultiplayerError": "Für Multiplayer wird eine Internetverbindung benötigt."
|
||||
"connectivityMultiplayerError": "Für Multiplayer wird eine Internetverbindung benötigt.",
|
||||
|
||||
"errorNoInternet": "Keine Internetverbindung",
|
||||
"errorGeneric": "Etwas ist schiefgelaufen.",
|
||||
"errorUnauthorized": "Zugriff verweigert. Bitte neu einloggen.",
|
||||
"errorNotFound": "Daten konnten nicht gefunden werden.",
|
||||
"errorEntryNotUnique": "Dieser Eintrag ist bereits vergeben.",
|
||||
"errorAuthenticationFailed": "E-Mail oder Passwort falsch.",
|
||||
"errorIllegalRequest": "Ungültige Anfrage."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -397,5 +397,13 @@
|
|||
"lobbyStatusEntering": "Entering Battle...",
|
||||
|
||||
"connectivityError": "No internet connection available.",
|
||||
"connectivityMultiplayerError": "Active internet connection required for multiplayer."
|
||||
"connectivityMultiplayerError": "Active internet connection required for multiplayer.",
|
||||
|
||||
"errorNoInternet": "No internet connection",
|
||||
"errorGeneric": "Something went wrong",
|
||||
"errorUnauthorized": "Access denied. Please relogin.",
|
||||
"errorNotFound": "Data not found.",
|
||||
"errorEntryNotUnique": "Entry already exists.",
|
||||
"errorAuthenticationFailed": "E-Mail or Passwort wrong.",
|
||||
"errorIllegalRequest": "Illegal Request."
|
||||
}
|
||||
|
|
|
|||
56
lib/src/core/utils/error_handler.dart
Normal file
56
lib/src/core/utils/error_handler.dart
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:slrpg_app/l10n/app_localizations.dart';
|
||||
import 'package:slrpg_app/src/core/theme/app_theme.dart';
|
||||
|
||||
class ErrorHandler {
|
||||
static String getReadableError(BuildContext context, Object error) {
|
||||
final l10n = AppLocalizations.of(context);
|
||||
if (l10n == null) return error.toString();
|
||||
|
||||
final e = error.toString();
|
||||
|
||||
if (e.contains('SocketException') ||
|
||||
e.contains('Connection refused') ||
|
||||
e.contains('ClientException') ||
|
||||
e.contains('HandshakeException')) {
|
||||
return l10n.errorNoInternet;
|
||||
}
|
||||
|
||||
if (e.contains('401') || e.contains('403')) {
|
||||
return l10n.errorUnauthorized;
|
||||
}
|
||||
|
||||
if (e.contains('404')) {
|
||||
return l10n.errorNotFound;
|
||||
}
|
||||
|
||||
if (e.contains('400')) {
|
||||
if (e.contains('validation_not_unique')) {
|
||||
return l10n.errorEntryNotUnique;
|
||||
}
|
||||
if (e.contains('Failed to authenticate')) {
|
||||
return l10n.errorAuthenticationFailed;
|
||||
}
|
||||
return l10n.errorIllegalRequest;
|
||||
}
|
||||
|
||||
return l10n.errorGeneric;
|
||||
}
|
||||
|
||||
static void showErrorSnackBar(BuildContext context, Object error) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(getReadableError(context, error)),
|
||||
backgroundColor: AppTheme.errorColor,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
duration: const Duration(seconds: 4),
|
||||
action: SnackBarAction(
|
||||
label: 'OK',
|
||||
textColor: Colors.white,
|
||||
onPressed: () => ScaffoldMessenger.of(context).hideCurrentSnackBar(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:slrpg_app/l10n/app_localizations.dart';
|
||||
import 'package:slrpg_app/src/core/utils/error_handler.dart';
|
||||
|
||||
import '../../../../shared/data/repositories/user_repository.dart';
|
||||
import '../../../../core/theme/app_theme.dart';
|
||||
|
|
@ -60,6 +61,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen> {
|
|||
_isLoading = false;
|
||||
_errorMessage = _parseErrorMessage(e.toString());
|
||||
});
|
||||
ErrorHandler.showErrorSnackBar(context, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:slrpg_app/l10n/app_localizations.dart';
|
||||
import 'package:slrpg_app/src/core/utils/error_handler.dart';
|
||||
import 'package:slrpg_app/src/features/multiplayer/data/repositories/party_repository.dart';
|
||||
|
||||
import '../../../../core/constants/app_constants.dart';
|
||||
|
|
@ -159,9 +160,7 @@ class _HubScreenState extends ConsumerState<HubScreen> {
|
|||
} catch (e) {
|
||||
log('Failed to start workout: $e');
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Error: $e')),
|
||||
);
|
||||
if (mounted) ErrorHandler.showErrorSnackBar(context, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -276,8 +275,7 @@ class _HubScreenState extends ConsumerState<HubScreen> {
|
|||
if (mounted) context.go('/lobby/${party.id}');
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(content: Text('Error: $e')));
|
||||
if (mounted) ErrorHandler.showErrorSnackBar(context, e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -321,8 +319,7 @@ class _HubScreenState extends ConsumerState<HubScreen> {
|
|||
if (mounted) context.go('/lobby/${party.id}');
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context)
|
||||
.showSnackBar(SnackBar(content: Text('Error: $e')));
|
||||
if (mounted) ErrorHandler.showErrorSnackBar(context, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -497,21 +494,21 @@ class _HubScreenState extends ConsumerState<HubScreen> {
|
|||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
if (cycle != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_StatBox(
|
||||
label: l10n.hubCycleLabel,
|
||||
value: '#${cycle.cycleNumber}'),
|
||||
_StatBox(
|
||||
label: l10n.hubActiveLabel,
|
||||
value: l10n.hubActiveYes),
|
||||
],
|
||||
),
|
||||
),
|
||||
// if (cycle != null)
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
// children: [
|
||||
// _StatBox(
|
||||
// label: l10n.hubCycleLabel,
|
||||
// value: '#${cycle.cycleNumber}'),
|
||||
// _StatBox(
|
||||
// label: l10n.hubActiveLabel,
|
||||
// value: l10n.hubActiveYes),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
const Spacer(flex: 1),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ class _AvatarSetupScreenState extends ConsumerState<AvatarSetupScreen> {
|
|||
);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
user = await userRepo.getLocalUser();
|
||||
await ref.read(apiClientProvider).requestVerification(email);
|
||||
|
||||
if (user == null) {
|
||||
throw Exception(
|
||||
|
|
|
|||
|
|
@ -169,11 +169,10 @@ class _BattleScreenState extends ConsumerState<BattleScreen> {
|
|||
|
||||
if (!mounted) return;
|
||||
|
||||
_showCompletionDialog(result.xpEarned);
|
||||
if (result.hasLevelUp) {
|
||||
_showLevelUpDialog(result.oldLevel!, result.newLevel!);
|
||||
}
|
||||
|
||||
_showCompletionDialog(result.xpEarned);
|
||||
}
|
||||
|
||||
void _showLevelUpDialog(int oldLevel, int newLevel) {
|
||||
|
|
|
|||
|
|
@ -236,6 +236,19 @@ class ApiClient {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> requestVerification(String email) async {
|
||||
try {
|
||||
await _dio.post(
|
||||
'/api/collections/users/request-verification',
|
||||
data: {'email': email},
|
||||
);
|
||||
_logger.i('Verification email requested for $email');
|
||||
} catch (e) {
|
||||
_logger.e('Request verification failed', error: e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> logout() async {
|
||||
await _storage.delete(key: AppConstants.keyAuthToken);
|
||||
await _storage.delete(key: AppConstants.keyUserId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue