@@ -18,12 +18,16 @@ import 'screens/HomeScreen.dart';
1818import 'services/crawler_service.dart' ;
1919import 'services/preferences_service.dart' ;
2020import 'services/preferences_recovery_service.dart' ;
21+ import 'services/auth_service.dart' ;
22+ import 'services/encrypted_db_service.dart' ;
23+ import 'screens/LoginScreen.dart' ;
2124
2225// Firebase
2326import 'package:firebase_core/firebase_core.dart' ;
2427import 'firebase_options.dart' ;
2528import 'package:firebase_crashlytics/firebase_crashlytics.dart' ;
2629import 'package:firebase_analytics/firebase_analytics.dart' ;
30+ import 'package:supabase_flutter/supabase_flutter.dart' ;
2731
2832// Dart libs
2933import 'dart:ui' ;
@@ -63,6 +67,13 @@ Future<void> migratePreferences() async {
6367void main () async {
6468 WidgetsFlutterBinding .ensureInitialized ();
6569
70+ await Supabase .initialize (
71+ url: 'https://cajmqxovsmtcybsezibu.supabase.co' ,
72+ anonKey:
73+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNham1xeG92c210Y3lic2V6aWJ1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDYzMTYzMDIsImV4cCI6MjA2MTg5MjMwMn0.mt7uv4_MOAJzCHBGuGw_c_OB7HXTvqmNvKzHlZqPed0' ,
74+ debug: true ,
75+ );
76+
6677 await Firebase .initializeApp (options: DefaultFirebaseOptions .currentPlatform);
6778
6879 FlutterError .onError = (errorDetails) {
@@ -97,6 +108,8 @@ void main() async {
97108 final dnsService = DnsService ();
98109 final crawlerService = CrawlerService ();
99110 final preferencesService = PreferencesService ();
111+ final authService = AuthService ();
112+ final encryptedDbService = EncryptedDbService ();
100113
101114 await Future .wait ([
102115 preferencesService.initialize (),
@@ -109,6 +122,8 @@ void main() async {
109122 httpClient.initialize (),
110123 dnsService.initialize (),
111124 crawlerService.initialize (),
125+ authService.initialize (),
126+ encryptedDbService.initialize (),
112127 ]);
113128
114129 // Set initial system UI styling
@@ -139,12 +154,16 @@ void main() async {
139154 ),
140155 ChangeNotifierProvider <BookmarkService >.value (value: bookmarkService),
141156 ChangeNotifierProvider <HistoryService >.value (value: historyService),
157+ ChangeNotifierProvider <AuthService >.value (value: authService),
142158 ],
143159 child: const MainApp (),
144160 ),
145161 );
146162}
147163
164+ // It's handy to then extract the Supabase client in a variable for later uses
165+ final supabase = Supabase .instance.client;
166+
148167class MainApp extends StatelessWidget {
149168 const MainApp ({super .key});
150169
@@ -155,54 +174,81 @@ class MainApp extends StatelessWidget {
155174
156175 @override
157176 Widget build (BuildContext context) {
158- return Consumer2 <ThemeServices , LanguageService >(
159- builder: (context, themeService, languageService, child) {
160- return AnimatedSystemUIHandler (
161- child: MaterialApp (
162- debugShowCheckedModeBanner: false ,
163- themeMode: themeService.themeMode,
164- theme: themeService.getLightTheme (),
165- darkTheme: themeService.getDarkTheme (),
166- locale: languageService.currentLocale,
167- navigatorObservers: [observer],
168- localizationsDelegates: const [
169- GlobalMaterialLocalizations .delegate,
170- GlobalWidgetsLocalizations .delegate,
171- GlobalCupertinoLocalizations .delegate,
172- ],
173- supportedLocales: const [Locale ('en' , '' ), Locale ('vi' , '' )],
174- builder: (context, child) {
175- // Ensure proper MediaQuery inheritance
176- final mediaQuery = MediaQuery .of (context);
177- return MediaQuery (
178- // Prevent text scaling from affecting layout
179- data: mediaQuery.copyWith (
180- textScaler: themeService.textScaler,
181- // Ensure proper padding for system UI
182- padding: mediaQuery.padding,
183- viewPadding: mediaQuery.viewPadding,
184- viewInsets: mediaQuery.viewInsets,
185- ),
186- child: ScrollConfiguration (
187- // Enable scrolling everywhere
188- behavior: const MaterialScrollBehavior ().copyWith (
189- physics: const ClampingScrollPhysics (),
190- // Enable drag scrolling on all platforms
191- dragDevices: {
192- PointerDeviceKind .touch,
193- PointerDeviceKind .mouse,
194- PointerDeviceKind .stylus,
195- PointerDeviceKind .trackpad,
196- },
177+ final themeService = Provider .of <ThemeServices >(context);
178+ final languageService = Provider .of <LanguageService >(context);
179+ final authService = Provider .of <AuthService >(context);
180+
181+ return MaterialApp (
182+ debugShowCheckedModeBanner: false ,
183+ title: 'DocLN' ,
184+ theme: themeService.getLightTheme (),
185+ darkTheme: themeService.getDarkTheme (),
186+ themeMode: themeService.themeMode,
187+ navigatorObservers: [observer],
188+ locale: languageService.currentLocale,
189+ supportedLocales: const [Locale ('en' , '' ), Locale ('vi' , '' )],
190+ localizationsDelegates: const [
191+ GlobalMaterialLocalizations .delegate,
192+ GlobalWidgetsLocalizations .delegate,
193+ GlobalCupertinoLocalizations .delegate,
194+ ],
195+ home: FutureBuilder (
196+ // This future checks if the splash screen has been shown and if auth is initialized
197+ future: Future .delayed (const Duration (seconds: 5 ), () => true ),
198+ builder: (context, snapshot) {
199+ // While waiting, show splash screen
200+ if (! snapshot.hasData) {
201+ return const SplashScreen ();
202+ }
203+
204+ // After splash screen, decide whether to show login or home screen
205+ Widget nextScreen;
206+ if (authService.isAuthenticated) {
207+ nextScreen = HomeScreen ();
208+ } else {
209+ // Check if this is the first time or the user has explicitly logged out
210+ final hasLoggedOutBefore = Provider .of <PreferencesService >(
211+ context,
212+ listen: false ,
213+ ).getBool ('has_logged_out_before' , defaultValue: false );
214+
215+ if (hasLoggedOutBefore) {
216+ nextScreen = const LoginScreen ();
217+ } else {
218+ // For first time users, let them use the app before requiring login
219+ nextScreen = HomeScreen ();
220+ }
221+ }
222+
223+ // Create an animation controller manually for the transition
224+ return AnimatedSwitcher (
225+ duration: const Duration (milliseconds: 800 ),
226+ child: nextScreen,
227+ transitionBuilder: (Widget child, Animation <double > animation) {
228+ final curvedAnimation = CurvedAnimation (
229+ parent: animation,
230+ curve: Curves .easeOutBack,
231+ );
232+
233+ return FadeTransition (
234+ opacity: Tween <double >(begin: 0.0 , end: 1.0 ).animate (
235+ CurvedAnimation (
236+ parent: animation,
237+ curve: const Interval (0.3 , 1.0 , curve: Curves .easeOut),
197238 ),
198- child: child! ,
239+ ),
240+ child: ScaleTransition (
241+ scale: Tween <double >(
242+ begin: 0.7 ,
243+ end: 1.0 ,
244+ ).animate (curvedAnimation),
245+ child: child,
199246 ),
200247 );
201248 },
202- home: const SplashScreen (),
203- ),
204- );
205- },
249+ );
250+ },
251+ ),
206252 );
207253 }
208254}
0 commit comments