fix: fix errors while refreshing token on app start
This commit is contained in:
parent
b58b7ca57a
commit
361c43f3c1
9 changed files with 280 additions and 90 deletions
|
|
@ -1,24 +1,88 @@
|
||||||
import 'dart:developer';
|
// import 'dart:developer';
|
||||||
|
|
||||||
|
// import 'package:flutter/material.dart';
|
||||||
|
// import 'package:flutter/services.dart';
|
||||||
|
// import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
// import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
// import 'package:slrpg_app/src/shared/data/remote/secure_auth_store.dart';
|
||||||
|
// import 'src/app.dart';
|
||||||
|
// import 'src/shared/data/local/app_database.dart';
|
||||||
|
// import 'src/shared/data/remote/api_client.dart';
|
||||||
|
// import 'src/shared/data/remote/pb_auth_store.dart';
|
||||||
|
// import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
|
// void main() async {
|
||||||
|
// WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// await dotenv.load(fileName: '.env');
|
||||||
|
// log('Environment loaded: ${dotenv.env['ENVIRONMENT']}');
|
||||||
|
// log('API URL: ${dotenv.env['API_BASE_URL']}');
|
||||||
|
// } catch (e) {
|
||||||
|
// log('Could not load .env file: $e');
|
||||||
|
// log('Using default production values');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await SystemChrome.setPreferredOrientations([
|
||||||
|
// DeviceOrientation.portraitUp,
|
||||||
|
// DeviceOrientation.portraitDown,
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
// final database = AppDatabase();
|
||||||
|
|
||||||
|
// const secureStorage = FlutterSecureStorage(
|
||||||
|
// aOptions: AndroidOptions(encryptedSharedPreferences: true));
|
||||||
|
// final authStore = PbAuthStore();
|
||||||
|
// // final authStore = SecureAuthStore(storage: secureStorage);
|
||||||
|
// await authStore.loadFromStorage();
|
||||||
|
|
||||||
|
// runApp(
|
||||||
|
// ProviderScope(
|
||||||
|
// overrides: [
|
||||||
|
// // Datenbank Override (wie gehabt)
|
||||||
|
// appDatabaseProvider.overrideWithValue(database),
|
||||||
|
|
||||||
|
// // ApiClient Override: Wir geben den BEREITS GELADENEN Store rein
|
||||||
|
// apiClientProvider.overrideWith((ref) => ApiClient(
|
||||||
|
// authStore: authStore, // Hier injizieren!
|
||||||
|
// storage: secureStorage)),
|
||||||
|
// ],
|
||||||
|
// child: const SLRPGApp(), // Dein Root Widget (Name prüfen, falls anders)
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// // }
|
||||||
|
// // runApp(
|
||||||
|
// // ProviderScope(
|
||||||
|
// // overrides: [
|
||||||
|
// // appDatabaseProvider.overrideWithValue(database),
|
||||||
|
// // apiClientProvider
|
||||||
|
// // .overrideWith((ref) => ApiClient(authStore: authStore)),
|
||||||
|
// // ],
|
||||||
|
// // child: const SLRPGApp(),
|
||||||
|
// // ),
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// final appDatabaseProvider =
|
||||||
|
// Provider<AppDatabase>((ref) => throw UnimplementedError());
|
||||||
|
import 'dart:developer';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'src/app.dart';
|
|
||||||
import 'src/shared/data/local/app_database.dart';
|
|
||||||
import 'src/shared/data/remote/api_client.dart';
|
|
||||||
import 'src/shared/data/remote/pb_auth_store.dart';
|
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
import 'package:slrpg_app/src/app.dart';
|
||||||
|
import 'package:slrpg_app/src/shared/data/local/app_database.dart';
|
||||||
|
import 'package:slrpg_app/src/shared/data/remote/api_client.dart';
|
||||||
|
import 'package:slrpg_app/src/shared/data/remote/pb_auth_store.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
// 1. Env laden
|
||||||
try {
|
try {
|
||||||
await dotenv.load(fileName: '.env');
|
await dotenv.load(fileName: '.env');
|
||||||
log('Environment loaded: ${dotenv.env['ENVIRONMENT']}');
|
|
||||||
log('API URL: ${dotenv.env['API_BASE_URL']}');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Could not load .env file: $e');
|
log('Could not load .env file: $e');
|
||||||
log('Using default production values');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await SystemChrome.setPreferredOrientations([
|
await SystemChrome.setPreferredOrientations([
|
||||||
|
|
@ -28,18 +92,13 @@ void main() async {
|
||||||
|
|
||||||
final database = AppDatabase();
|
final database = AppDatabase();
|
||||||
|
|
||||||
|
// 2. Auth Store erstellen UND laden (Warten!)
|
||||||
final authStore = PbAuthStore();
|
final authStore = PbAuthStore();
|
||||||
await authStore.loadFromStorage();
|
await authStore.loadFromStorage(); // Das ist der entscheidende 'await'
|
||||||
|
|
||||||
if (authStore.isValid && authStore.record == null) {
|
log("Auth loaded. Valid? ${authStore.isValid}"); // Debug Log
|
||||||
final tempClient = ApiClient(authStore: authStore);
|
|
||||||
try {
|
|
||||||
await tempClient.refreshAuth();
|
|
||||||
} catch (e) {
|
|
||||||
log('Initial auth refresh failed: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 3. App starten mit injiziertem Store
|
||||||
runApp(
|
runApp(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
overrides: [
|
overrides: [
|
||||||
|
|
@ -52,5 +111,6 @@ void main() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provider Definition für DB (falls noch nicht vorhanden)
|
||||||
final appDatabaseProvider =
|
final appDatabaseProvider =
|
||||||
Provider<AppDatabase>((ref) => throw UnimplementedError());
|
Provider<AppDatabase>((ref) => throw UnimplementedError());
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:slrpg_app/src/features/authentication/data/repositories/auth_rep
|
||||||
import 'package:slrpg_app/src/features/multiplayer/presentation/screens/leaderboard_screen.dart';
|
import 'package:slrpg_app/src/features/multiplayer/presentation/screens/leaderboard_screen.dart';
|
||||||
import 'package:slrpg_app/src/features/multiplayer/presentation/screens/lobby_screen.dart';
|
import 'package:slrpg_app/src/features/multiplayer/presentation/screens/lobby_screen.dart';
|
||||||
import 'package:slrpg_app/src/features/settings/presentation/screens/privacy_policy_screen.dart';
|
import 'package:slrpg_app/src/features/settings/presentation/screens/privacy_policy_screen.dart';
|
||||||
|
import 'package:slrpg_app/src/shared/data/remote/api_client.dart';
|
||||||
|
|
||||||
import '../../features/authentication/presentation/screens/login_screen.dart';
|
import '../../features/authentication/presentation/screens/login_screen.dart';
|
||||||
import '../../features/authentication/presentation/screens/profile_screen.dart';
|
import '../../features/authentication/presentation/screens/profile_screen.dart';
|
||||||
|
|
@ -205,7 +206,20 @@ class _SplashScreenState extends ConsumerState<SplashScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _checkInitialRoute() async {
|
Future<void> _checkInitialRoute() async {
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
final apiClient = ref.read(apiClientProvider);
|
||||||
|
final authStore = apiClient.pb.authStore;
|
||||||
|
|
||||||
|
if (authStore.isValid && authStore.record == null) {
|
||||||
|
try {
|
||||||
|
await apiClient.refreshAuth();
|
||||||
|
} catch (e) {
|
||||||
|
// If refresh fails, user will be redirected to login by the router logic (authStore cleared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ final authRepositoryProvider = Provider<AuthRepository>((ref) {
|
||||||
|
|
||||||
apiClient.authStateChanges.listen((event) {
|
apiClient.authStateChanges.listen((event) {
|
||||||
if (event.token.isEmpty) {
|
if (event.token.isEmpty) {
|
||||||
repo.logout();
|
repo.clearLocalData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -115,10 +115,11 @@ class AuthRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
if (apiClient.getToken() != null) {
|
|
||||||
await apiClient.logout();
|
await apiClient.logout();
|
||||||
|
await clearLocalData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> clearLocalData() async {
|
||||||
await _storage.delete(key: AppConstants.keyLastSync);
|
await _storage.delete(key: AppConstants.keyLastSync);
|
||||||
|
|
||||||
await db.transaction(() async {
|
await db.transaction(() async {
|
||||||
|
|
|
||||||
|
|
@ -465,7 +465,7 @@ class _HubScreenState extends ConsumerState<HubScreen> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const QuestBoardWidget(),
|
// const QuestBoardWidget(),
|
||||||
const Spacer(flex: 2),
|
const Spacer(flex: 2),
|
||||||
if (cycle != null)
|
if (cycle != null)
|
||||||
Padding(
|
Padding(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:pocketbase/pocketbase.dart';
|
||||||
import 'package:slrpg_app/src/features/multiplayer/domain/entities/party.dart';
|
import 'package:slrpg_app/src/features/multiplayer/domain/entities/party.dart';
|
||||||
import 'package:slrpg_app/src/features/multiplayer/domain/entities/party_member.dart';
|
import 'package:slrpg_app/src/features/multiplayer/domain/entities/party_member.dart';
|
||||||
import 'package:slrpg_app/src/shared/data/repositories/user_repository.dart';
|
|
||||||
import '../../../../shared/data/remote/api_client.dart';
|
import '../../../../shared/data/remote/api_client.dart';
|
||||||
|
|
||||||
final partyRepositoryProvider = Provider((ref) {
|
final partyRepositoryProvider = Provider((ref) {
|
||||||
|
|
@ -63,21 +62,39 @@ class PartyRepository {
|
||||||
await _api.pb.collection('parties').update(partyId, body: body);
|
await _api.pb.collection('parties').update(partyId, body: body);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<Party> subscribeToParty(String partyId) async* {
|
Stream<Party> subscribeToParty(String partyId) {
|
||||||
yield await getPartyDetails(partyId);
|
late StreamController<Party> controller;
|
||||||
|
UnsubscribeFunc? unsubscribe;
|
||||||
|
|
||||||
final controller = StreamController<Party>();
|
controller = StreamController<Party>(
|
||||||
|
onListen: () async {
|
||||||
|
try {
|
||||||
|
final initial = await getPartyDetails(partyId);
|
||||||
|
controller.add(initial);
|
||||||
|
} catch (e) {
|
||||||
|
controller.addError(e);
|
||||||
|
}
|
||||||
|
|
||||||
_api.pb.collection('parties').subscribe(partyId, (e) {
|
unsubscribe =
|
||||||
|
await _api.pb.collection('parties').subscribe(partyId, (e) {
|
||||||
if (e.action == 'update' && e.record != null) {
|
if (e.action == 'update' && e.record != null) {
|
||||||
controller.add(Party.fromJson(e.record!.toJson()));
|
controller.add(Party.fromJson(e.record!.toJson()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
onCancel: () async {
|
||||||
|
await unsubscribe?.call();
|
||||||
|
log('🔌 Unsubscribed from party $partyId');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
yield* controller.stream;
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream<List<PartyMember>> subscribeToMembers(String partyId) async* {
|
Stream<List<PartyMember>> subscribeToMembers(String partyId) {
|
||||||
|
late StreamController<List<PartyMember>> controller;
|
||||||
|
UnsubscribeFunc? unsubscribe;
|
||||||
|
|
||||||
Future<List<PartyMember>> fetchMembers() async {
|
Future<List<PartyMember>> fetchMembers() async {
|
||||||
final records = await _api.pb.collection('party_members').getFullList(
|
final records = await _api.pb.collection('party_members').getFullList(
|
||||||
filter: 'party_id="$partyId"',
|
filter: 'party_id="$partyId"',
|
||||||
|
|
@ -86,17 +103,29 @@ class PartyRepository {
|
||||||
return records.map((r) => PartyMember.fromRecord(r.toJson())).toList();
|
return records.map((r) => PartyMember.fromRecord(r.toJson())).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
yield await fetchMembers();
|
controller = StreamController<List<PartyMember>>(
|
||||||
|
onListen: () async {
|
||||||
|
try {
|
||||||
|
controller.add(await fetchMembers());
|
||||||
|
} catch (e) {
|
||||||
|
controller.addError(e);
|
||||||
|
}
|
||||||
|
|
||||||
final controller = StreamController<List<PartyMember>>();
|
unsubscribe =
|
||||||
|
await _api.pb.collection('party_members').subscribe('*', (e) async {
|
||||||
_api.pb.collection('party_members').subscribe('*', (e) async {
|
if (e.record != null &&
|
||||||
if (e.record != null && e.record!.getStringValue('party_id') == partyId) {
|
e.record!.getStringValue('party_id') == partyId) {
|
||||||
controller.add(await fetchMembers());
|
controller.add(await fetchMembers());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
onCancel: () async {
|
||||||
|
await unsubscribe?.call();
|
||||||
|
log('🔌 Unsubscribed from party members $partyId');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
yield* controller.stream;
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> dealDamage(String partyId, int damage) async {
|
Future<void> dealDamage(String partyId, int damage) async {
|
||||||
|
|
|
||||||
|
|
@ -179,10 +179,8 @@ class _LeaderboardScreenState extends ConsumerState<LeaderboardScreen> {
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final currentUserId = snapshot.data?.serverId ?? '';
|
final currentUserId = snapshot.data?.serverId ?? '';
|
||||||
|
|
||||||
// NEU: RefreshIndicator für Pull-to-Refresh
|
|
||||||
return RefreshIndicator(
|
return RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
// Erzwingt ein Neuladen der Daten
|
|
||||||
return ref.refresh(leaderboardProvider.future);
|
return ref.refresh(leaderboardProvider.future);
|
||||||
},
|
},
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
|
@ -276,8 +274,6 @@ class _LeaderboardScreenState extends ConsumerState<LeaderboardScreen> {
|
||||||
Widget _buildAvatarPreview(LeaderboardEntry entry) {
|
Widget _buildAvatarPreview(LeaderboardEntry entry) {
|
||||||
if (entry.avatar != null && entry.avatar!.isNotEmpty) {
|
if (entry.avatar != null && entry.avatar!.isNotEmpty) {
|
||||||
try {
|
try {
|
||||||
// Hier prüfen, ob es ein JSON String oder eine Map ist, falls nötig.
|
|
||||||
// Da wir im Repository .toJson() aufrufen, ist es hier sicher eine Map.
|
|
||||||
final config = AvatarConfig.fromJson(entry.avatar!);
|
final config = AvatarConfig.fromJson(entry.avatar!);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
|
@ -300,8 +296,6 @@ class _LeaderboardScreenState extends ConsumerState<LeaderboardScreen> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WICHTIG: .autoDispose sorgt dafür, dass die Daten neu geladen werden,
|
|
||||||
// wenn der Screen verlassen und wieder betreten wird.
|
|
||||||
final leaderboardProvider = FutureProvider.autoDispose((ref) async {
|
final leaderboardProvider = FutureProvider.autoDispose((ref) async {
|
||||||
return ref.read(leaderboardRepositoryProvider).getGlobalLeaderboard();
|
return ref.read(leaderboardRepositoryProvider).getGlobalLeaderboard();
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ import 'package:pocketbase/pocketbase.dart';
|
||||||
import '../../../core/constants/app_constants.dart';
|
import '../../../core/constants/app_constants.dart';
|
||||||
import 'pb_auth_store.dart';
|
import 'pb_auth_store.dart';
|
||||||
|
|
||||||
final apiClientProvider = Provider<ApiClient>((ref) => ApiClient());
|
// final apiClientProvider = Provider<ApiClient>((ref) => ApiClient());
|
||||||
|
final apiClientProvider =
|
||||||
|
Provider<ApiClient>((ref) => throw UnimplementedError());
|
||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
late final PocketBase _pb;
|
late final PocketBase _pb;
|
||||||
final PbAuthStore _authStore;
|
// final PbAuthStore _authStore;
|
||||||
final Logger _logger;
|
final Logger _logger;
|
||||||
|
|
||||||
PocketBase get pb => _pb;
|
PocketBase get pb => _pb;
|
||||||
|
|
@ -18,19 +20,28 @@ class ApiClient {
|
||||||
Stream<AuthStoreEvent> get authStateChanges => _pb.authStore.onChange;
|
Stream<AuthStoreEvent> get authStateChanges => _pb.authStore.onChange;
|
||||||
|
|
||||||
ApiClient({
|
ApiClient({
|
||||||
PbAuthStore? authStore,
|
required AuthStore authStore,
|
||||||
FlutterSecureStorage? storage,
|
|
||||||
Logger? logger,
|
Logger? logger,
|
||||||
}) : _logger = logger ?? Logger(),
|
}) : _logger = logger ?? Logger() {
|
||||||
_authStore = authStore ?? PbAuthStore(storage: storage) {
|
|
||||||
_pb = PocketBase(
|
_pb = PocketBase(
|
||||||
AppConstants.apiBaseUrl,
|
AppConstants.apiBaseUrl,
|
||||||
authStore: _authStore,
|
authStore: authStore, // Hier kommt der geladene Store rein
|
||||||
);
|
);
|
||||||
if (authStore == null) {
|
|
||||||
_authStore.loadFromStorage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// ApiClient({
|
||||||
|
// PbAuthStore? authStore,
|
||||||
|
// FlutterSecureStorage? storage,
|
||||||
|
// Logger? logger,
|
||||||
|
// }) : _logger = logger ?? Logger(),
|
||||||
|
// _authStore = authStore ?? PbAuthStore(storage: storage) {
|
||||||
|
// _pb = PocketBase(
|
||||||
|
// AppConstants.apiBaseUrl,
|
||||||
|
// authStore: _authStore,
|
||||||
|
// );
|
||||||
|
// if (authStore == null) {
|
||||||
|
// _authStore.loadFromStorage();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
Future<T> _handleRequest<T>(Future<T> Function() request) async {
|
Future<T> _handleRequest<T>(Future<T> Function() request) async {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
20
lib/src/shared/data/remote/custom_http_client.dart
Normal file
20
lib/src/shared/data/remote/custom_http_client.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
class CustomHttpClient {
|
||||||
|
static HttpClient createWithTimeout({
|
||||||
|
Duration connectionTimeout = const Duration(seconds: 10),
|
||||||
|
Duration receiveTimeout = const Duration(seconds: 30),
|
||||||
|
}) {
|
||||||
|
final client = HttpClient();
|
||||||
|
|
||||||
|
client.connectionTimeout = connectionTimeout;
|
||||||
|
|
||||||
|
client.idleTimeout = const Duration(seconds: 15);
|
||||||
|
|
||||||
|
client.badCertificateCallback = (cert, host, port) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,57 +1,118 @@
|
||||||
|
// import 'dart:convert';
|
||||||
|
// import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
// import 'package:pocketbase/pocketbase.dart';
|
||||||
|
|
||||||
|
// class PbAuthStore extends AuthStore {
|
||||||
|
// final FlutterSecureStorage _storage;
|
||||||
|
// final String _storageKey;
|
||||||
|
|
||||||
|
// PbAuthStore({
|
||||||
|
// FlutterSecureStorage? storage,
|
||||||
|
// String key = 'pb_auth',
|
||||||
|
// }) : _storage = storage ?? const FlutterSecureStorage(),
|
||||||
|
// _storageKey = key,
|
||||||
|
// super();
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// Future<void> save(String newToken, dynamic newRecord) async {
|
||||||
|
// super.save(newToken, newRecord);
|
||||||
|
|
||||||
|
// final encoded = jsonEncode(<String, dynamic>{
|
||||||
|
// 'token': newToken,
|
||||||
|
// 'model': newRecord,
|
||||||
|
// });
|
||||||
|
|
||||||
|
// await _storage.write(key: _storageKey, value: encoded);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// void clear() {
|
||||||
|
// super.clear();
|
||||||
|
// _storage.delete(key: _storageKey);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Future<void> loadFromStorage() async {
|
||||||
|
// final raw = await _storage.read(key: _storageKey);
|
||||||
|
// if (raw != null && raw.isNotEmpty) {
|
||||||
|
// try {
|
||||||
|
// final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
||||||
|
// final token = decoded['token'] as String?;
|
||||||
|
// final model = decoded['model'];
|
||||||
|
|
||||||
|
// if (token != null && token.isNotEmpty) {
|
||||||
|
// super.save(token, model);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// } catch (_) {
|
||||||
|
// clear();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const legacyKey = 'auth_token';
|
||||||
|
// final legacyToken = await _storage.read(key: legacyKey);
|
||||||
|
// if (legacyToken != null && legacyToken.isNotEmpty) {
|
||||||
|
// super.save(legacyToken, null);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:pocketbase/pocketbase.dart';
|
import 'package:pocketbase/pocketbase.dart';
|
||||||
|
|
||||||
class PbAuthStore extends AuthStore {
|
class PbAuthStore extends AuthStore {
|
||||||
final FlutterSecureStorage _storage;
|
final FlutterSecureStorage _storage;
|
||||||
final String _storageKey;
|
final String _saveKey = 'pb_auth';
|
||||||
|
|
||||||
PbAuthStore({
|
PbAuthStore({FlutterSecureStorage? storage})
|
||||||
FlutterSecureStorage? storage,
|
: _storage = storage ??
|
||||||
String key = 'pb_auth',
|
const FlutterSecureStorage(
|
||||||
}) : _storage = storage ?? const FlutterSecureStorage(),
|
aOptions: AndroidOptions(encryptedSharedPreferences: true),
|
||||||
_storageKey = key,
|
);
|
||||||
super();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> save(String newToken, dynamic newRecord) async {
|
Future<void> save(String token, dynamic model) async {
|
||||||
super.save(newToken, newRecord);
|
super.save(token, model);
|
||||||
|
|
||||||
final encoded = jsonEncode(<String, dynamic>{
|
final encoded = jsonEncode(<String, dynamic>{
|
||||||
'token': newToken,
|
'token': token,
|
||||||
'model': newRecord,
|
'model': model,
|
||||||
});
|
});
|
||||||
|
|
||||||
await _storage.write(key: _storageKey, value: encoded);
|
await _storage.write(key: _saveKey, value: encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void clear() {
|
Future<void> clear() async {
|
||||||
super.clear();
|
super.clear();
|
||||||
_storage.delete(key: _storageKey);
|
await _storage.delete(key: _saveKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diese Methode rufen wir VOR App-Start auf!
|
||||||
Future<void> loadFromStorage() async {
|
Future<void> loadFromStorage() async {
|
||||||
final raw = await _storage.read(key: _storageKey);
|
final raw = await _storage.read(key: _saveKey);
|
||||||
if (raw != null && raw.isNotEmpty) {
|
if (raw != null && raw.isNotEmpty) {
|
||||||
try {
|
try {
|
||||||
final decoded = jsonDecode(raw) as Map<String, dynamic>;
|
final decoded = jsonDecode(raw);
|
||||||
final token = decoded['token'] as String?;
|
final token = decoded['token'] as String? ?? '';
|
||||||
final model = decoded['model'];
|
final modelData = decoded['model'];
|
||||||
|
|
||||||
if (token != null && token.isNotEmpty) {
|
dynamic model;
|
||||||
|
if (modelData is Map<String, dynamic>) {
|
||||||
|
if (modelData.containsKey('collectionId')) {
|
||||||
|
model = RecordModel.fromJson(modelData);
|
||||||
|
} else {
|
||||||
|
model = RecordModel.fromJson(modelData);
|
||||||
|
// model = AdminModel.fromJson(modelData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// super.save schreibt nur in den Speicher (RAM) des AuthStores,
|
||||||
|
// löst aber kein erneutes 'save' (und damit write) aus.
|
||||||
super.save(token, model);
|
super.save(token, model);
|
||||||
return;
|
} catch (e) {
|
||||||
|
// Daten korrupt? Löschen.
|
||||||
|
await clear();
|
||||||
}
|
}
|
||||||
} catch (_) {
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const legacyKey = 'auth_token';
|
|
||||||
final legacyToken = await _storage.read(key: legacyKey);
|
|
||||||
if (legacyToken != null && legacyToken.isNotEmpty) {
|
|
||||||
super.save(legacyToken, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue