this repo has no description

feat: implement token management and loading in ApiService and main app flow

+39 -1
+14 -1
lib/api.dart
··· 2 import 'dart:io'; 3 4 import 'package:at_uri/at_uri.dart'; 5 import 'package:grain/app_logger.dart'; 6 import 'package:grain/dpop_client.dart'; 7 import 'package:grain/main.dart'; ··· 17 import 'models/profile.dart'; 18 19 class ApiService { 20 String? _accessToken; 21 Profile? currentUser; 22 Profile? loadedProfile; ··· 24 25 String get _apiUrl => AppConfig.apiUrl; 26 27 - setToken(String? token) { 28 _accessToken = token; 29 } 30 31 Future<AtprotoSession?> fetchSession() async { 32 if (_accessToken == null) return null;
··· 2 import 'dart:io'; 3 4 import 'package:at_uri/at_uri.dart'; 5 + import 'package:flutter_secure_storage/flutter_secure_storage.dart'; 6 import 'package:grain/app_logger.dart'; 7 import 'package:grain/dpop_client.dart'; 8 import 'package:grain/main.dart'; ··· 18 import 'models/profile.dart'; 19 20 class ApiService { 21 + static const _storage = FlutterSecureStorage(); 22 String? _accessToken; 23 Profile? currentUser; 24 Profile? loadedProfile; ··· 26 27 String get _apiUrl => AppConfig.apiUrl; 28 29 + Future<void> loadToken() async { 30 + _accessToken = await _storage.read(key: 'access_token'); 31 + } 32 + 33 + Future<void> setToken(String? token) async { 34 _accessToken = token; 35 + if (token != null) { 36 + await _storage.write(key: 'access_token', value: token); 37 + } else { 38 + await _storage.delete(key: 'access_token'); 39 + } 40 } 41 + 42 + bool get hasToken => _accessToken != null && _accessToken!.isNotEmpty; 43 44 Future<AtprotoSession?> fetchSession() async { 45 if (_accessToken == null) return null;
+25
lib/main.dart
··· 23 24 Future<void> main() async { 25 await AppConfig.init(); 26 appLogger.i('🚀 App started'); 27 runApp(const ProviderScope(child: MyApp())); 28 } ··· 36 37 class _MyAppState extends State<MyApp> { 38 bool isSignedIn = false; 39 String? displayName; 40 41 void handleSignIn() async { 42 setState(() { 43 isSignedIn = true; ··· 55 56 @override 57 Widget build(BuildContext context) { 58 return MaterialApp( 59 title: 'Grain', 60 theme: AppTheme.lightTheme,
··· 23 24 Future<void> main() async { 25 await AppConfig.init(); 26 + await apiService.loadToken(); // Restore access token before app starts 27 appLogger.i('🚀 App started'); 28 runApp(const ProviderScope(child: MyApp())); 29 } ··· 37 38 class _MyAppState extends State<MyApp> { 39 bool isSignedIn = false; 40 + bool _loading = true; 41 String? displayName; 42 43 + @override 44 + void initState() { 45 + super.initState(); 46 + _checkToken(); 47 + } 48 + 49 + Future<void> _checkToken() async { 50 + await apiService.loadToken(); 51 + if (apiService.hasToken) { 52 + await apiService.fetchSession(); 53 + await apiService.fetchCurrentUser(); 54 + } 55 + setState(() { 56 + isSignedIn = apiService.hasToken; 57 + _loading = false; 58 + }); 59 + } 60 + 61 void handleSignIn() async { 62 setState(() { 63 isSignedIn = true; ··· 75 76 @override 77 Widget build(BuildContext context) { 78 + if (_loading) { 79 + return const MaterialApp( 80 + home: Scaffold(body: Center(child: CircularProgressIndicator())), 81 + ); 82 + } 83 return MaterialApp( 84 title: 'Grain', 85 theme: AppTheme.lightTheme,