diff --git a/lib/main.dart b/lib/main.dart index 96fe7e4..d89b081 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,80 +1,42 @@ -import 'package:camera/camera.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -import 'package:share_location/constants/apis.dart'; import 'package:share_location/screens/calendar_screen.dart'; import 'package:share_location/screens/grant_permission_screen.dart'; import 'package:share_location/screens/login_screen.dart'; import 'package:share_location/screens/main_screen.dart'; +import 'package:share_location/screens/server_loading_screen.dart'; import 'package:share_location/screens/timeline_screen.dart'; import 'package:share_location/screens/welcome_screen.dart'; -import 'package:share_location/utils/auth_required.dart'; -import 'package:supabase_flutter/supabase_flutter.dart'; -import 'managers/global_values_manager.dart'; -import 'managers/startup_page_manager.dart'; import 'models/memories.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); - await Supabase.initialize( - url: SUPABASE_API_URL, - anonKey: SUPABASE_API_KEY, - debug: kDebugMode, - ); - SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.portraitDown, ]); - GlobalValuesManager.setCameras(await availableCameras()); - - final initialPage = await StartupPageManager.getPage(); - - runApp(MyApp(initialPage: initialPage)); + runApp(MyApp()); } class MyApp extends StatefulWidget { - final String initialPage; - const MyApp({ Key? key, - required this.initialPage, }) : super(key: key); @override State createState() => _MyAppState(); } -class _MyAppState extends AuthRequiredState { +class _MyAppState extends State { final memories = Memories(); - @override - void initState() { - super.initState(); - - memories.addListener(() { - setState(() { - - }); - }, ['isInitializing']); - } - - @override - void onAuthenticated(Session session) { - memories.initialize(); - } - @override Widget build(BuildContext context) { - if (memories.isInitializing) { - return SizedBox(); - } - return ChangeNotifierProvider.value( value: memories, child: MaterialApp( @@ -102,8 +64,9 @@ class _MyAppState extends AuthRequiredState { TimelineScreen.ID: (context) => const TimelineScreen(), GrantPermissionScreen.ID: (context) => const GrantPermissionScreen(), CalendarScreen.ID: (context) => const CalendarScreen(), + ServerLoadingScreen.ID: (context) => const ServerLoadingScreen(), }, - initialRoute: widget.initialPage, + initialRoute: ServerLoadingScreen.ID, ), ); } diff --git a/lib/screens/main_screen.dart b/lib/screens/main_screen.dart index bb44f49..50c357e 100644 --- a/lib/screens/main_screen.dart +++ b/lib/screens/main_screen.dart @@ -248,8 +248,16 @@ class _MainScreenState extends AuthRequiredState with Loadable { backgroundColor: Colors.black, bottomSheet: () { if (isLoading) { - return const Center( - child: CircularProgressIndicator(), + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: const [ + CircularProgressIndicator(), + SizedBox(height: MEDIUM_SPACE), + Text('Loading camera'), + ], + ), ); } diff --git a/lib/screens/server_loading_screen.dart b/lib/screens/server_loading_screen.dart new file mode 100644 index 0000000..33358d2 --- /dev/null +++ b/lib/screens/server_loading_screen.dart @@ -0,0 +1,95 @@ +import 'package:camera/camera.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; +import 'package:share_location/constants/apis.dart'; +import 'package:share_location/constants/spacing.dart'; +import 'package:share_location/managers/global_values_manager.dart'; +import 'package:share_location/models/memories.dart'; +import 'package:share_location/widgets/dot_animation.dart'; +import 'package:supabase_flutter/supabase_flutter.dart'; + +import 'main_screen.dart'; +import 'welcome_screen.dart'; + +class ServerLoadingScreen extends StatefulWidget { + static const ID = 'server_loading'; + + const ServerLoadingScreen({Key? key}) : super(key: key); + + @override + State createState() => _ServerLoadingScreenState(); +} + +class _ServerLoadingScreenState extends State { + @override + void initState() { + super.initState(); + + load(); + } + + Future load() async { + GlobalValuesManager.setCameras(await availableCameras()); + await Supabase.initialize( + url: SUPABASE_API_URL, + anonKey: SUPABASE_API_KEY, + debug: kDebugMode, + ); + + final memories = context.read(); + final session = Supabase.instance.client.auth.session(); + + if (session != null) { + memories.initialize().then((_) { + Navigator.pushReplacementNamed(context, MainScreen.ID); + }); + } else { + Navigator.pushReplacementNamed(context, WelcomeScreen.ID); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.black, + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: const [ + Icon(Icons.cloud, size: 60), + SizedBox(height: SMALL_SPACE), + DotAnimation( + initialFadeInDelay: Duration.zero, + fadeInDuration: Duration(seconds: 1), + fadeOutDuration: Duration(seconds: 1), + fadeInDelay: Duration(seconds: 6), + fadeOutDelay: Duration.zero, + ), + DotAnimation( + initialFadeInDelay: Duration(seconds: 2), + fadeInDuration: Duration(seconds: 1), + fadeOutDuration: Duration(seconds: 1), + fadeInDelay: Duration(seconds: 6), + fadeOutDelay: Duration.zero, + ), + DotAnimation( + initialFadeInDelay: Duration(seconds: 4), + fadeInDuration: Duration(seconds: 1), + fadeOutDuration: Duration(seconds: 1), + fadeInDelay: Duration(seconds: 6), + fadeOutDelay: Duration.zero, + ), + SizedBox(height: SMALL_SPACE), + Icon(Icons.smartphone, size: 60), + SizedBox(height: LARGE_SPACE), + Text( + 'We are loading your data', + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/dot_animation.dart b/lib/widgets/dot_animation.dart new file mode 100644 index 0000000..fbd0a4b --- /dev/null +++ b/lib/widgets/dot_animation.dart @@ -0,0 +1,95 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; + +class DotAnimation extends StatefulWidget { + final Duration fadeInDuration; + final Duration fadeOutDuration; + final Duration fadeInDelay; + final Duration fadeOutDelay; + final Duration? initialFadeInDelay; + final Curve curve; + + const DotAnimation({ + Key? key, + this.fadeInDuration = const Duration(seconds: 2), + this.fadeOutDuration = const Duration(seconds: 2), + this.curve = Curves.easeOut, + this.fadeInDelay = const Duration(seconds: 1), + this.fadeOutDelay = const Duration(seconds: 1), + this.initialFadeInDelay, + }) : super(key: key); + + @override + State createState() => _DotAnimationState(); +} + +class _DotAnimationState extends State { + Timer? _timer; + bool animateIn = false; + + Duration get initialFadeInDelay => + widget.initialFadeInDelay ?? widget.fadeInDelay; + + @override + void initState() { + super.initState(); + + _timer = Timer(initialFadeInDelay, () { + setState(() { + animateIn = true; + }); + }); + } + + @override + void dispose() { + _timer?.cancel(); + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return AnimatedScale( + duration: animateIn ? widget.fadeInDuration : widget.fadeOutDuration, + scale: animateIn ? 1 : .4, + curve: widget.curve, + onEnd: () { + if (animateIn) { + // Animate out + _timer = Timer(widget.fadeOutDelay, () { + if (mounted) { + return; + } + + setState(() { + animateIn = false; + }); + }); + } else { + // Animate in + _timer = Timer(widget.fadeInDelay, () { + if (mounted) { + return; + } + + setState(() { + animateIn = true; + }); + }); + } + }, + child: AnimatedOpacity( + opacity: animateIn ? 1 : .4, + duration: animateIn ? widget.fadeInDuration : widget.fadeOutDuration, + curve: widget.curve, + child: const Icon( + Icons.circle, + size: 30, + color: Colors.white, + ), + ), + ); + } +}