diff --git a/lib/main.dart b/lib/main.dart index a7988e332..20f111378 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,8 @@ import 'dart:isolate'; +import 'dart:ui'; import 'package:aves/model/settings/settings.dart'; +import 'package:aves/utils/route_tracker.dart'; import 'package:aves/widgets/common/data_providers/settings_provider.dart'; import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/home_page.dart'; @@ -38,9 +40,30 @@ class AvesApp extends StatefulWidget { class _AvesAppState extends State { Future _appSetup; + final NavigatorObserver _routeTracker = CrashlyticsRouteTracker(); static const accentColor = Colors.indigoAccent; + static final darkTheme = ThemeData( + brightness: Brightness.dark, + accentColor: accentColor, + scaffoldBackgroundColor: Colors.grey[900], + buttonColor: accentColor, + toggleableActiveColor: accentColor, + tooltipTheme: TooltipThemeData( + verticalOffset: 32, + ), + appBarTheme: AppBarTheme( + textTheme: TextTheme( + headline6: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + fontFamily: 'Concourse Caps', + ), + ), + ), + ); + @override void initState() { super.initState(); @@ -50,6 +73,9 @@ class _AvesAppState extends State { Future _setup() async { await Firebase.initializeApp().then((app) { FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError; + FirebaseCrashlytics.instance.setCustomKey('locales', window.locales.join(', ')); + final now = DateTime.now(); + FirebaseCrashlytics.instance.setCustomKey('timezone', '${now.timeZoneName} (${now.timeZoneOffset})'); FirebaseCrashlytics.instance.setCustomKey( 'build_mode', kReleaseMode @@ -65,44 +91,45 @@ class _AvesAppState extends State { Widget build(BuildContext context) { // place the settings provider above `MaterialApp` // so it can be used during navigation transitions + final home = FutureBuilder( + future: _appSetup, + builder: (context, snapshot) { + if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) { + return settings.hasAcceptedTerms ? HomePage() : WelcomePage(); + } + return Scaffold( + body: snapshot.hasError + ? Container( + alignment: Alignment.center, + padding: EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(AIcons.error), + SizedBox(height: 16), + Text(snapshot.error.toString()), + ], + ), + ) + : SizedBox.shrink(), + ); + }, + ); return SettingsProvider( child: OverlaySupport( - child: MaterialApp( - title: 'Aves', - theme: ThemeData( - brightness: Brightness.dark, - accentColor: accentColor, - scaffoldBackgroundColor: Colors.grey[900], - buttonColor: accentColor, - toggleableActiveColor: accentColor, - tooltipTheme: TooltipThemeData( - verticalOffset: 32, - ), - appBarTheme: AppBarTheme( - textTheme: TextTheme( - headline6: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - fontFamily: 'Concourse Caps', - ), - ), - ), - ), - home: FutureBuilder( - future: _appSetup, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Column( - children: [ - Icon(AIcons.error), - Text(snapshot.error), - ], - ); - } - if (snapshot.connectionState != ConnectionState.done) return Scaffold(); - return settings.hasAcceptedTerms ? HomePage() : WelcomePage(); - }, - ), + child: FutureBuilder( + future: _appSetup, + builder: (context, snapshot) { + return MaterialApp( + home: home, + navigatorObservers: [ + if (!snapshot.hasError && snapshot.connectionState == ConnectionState.done) _routeTracker, + ], + title: 'Aves', + darkTheme: darkTheme, + themeMode: ThemeMode.dark, + ); + }, ), ), ); diff --git a/lib/utils/route_tracker.dart b/lib/utils/route_tracker.dart new file mode 100644 index 000000000..3be10ae63 --- /dev/null +++ b/lib/utils/route_tracker.dart @@ -0,0 +1,18 @@ +import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:flutter/material.dart'; + +class CrashlyticsRouteTracker extends NavigatorObserver { + @override + void didPush(Route route, Route previousRoute) => FirebaseCrashlytics.instance.log('Nav didPush to ${_name(route)}'); + + @override + void didPop(Route route, Route previousRoute) => FirebaseCrashlytics.instance.log('Nav didPop to ${_name(previousRoute)}'); + + @override + void didRemove(Route route, Route previousRoute) => FirebaseCrashlytics.instance.log('Nav didRemove to ${_name(previousRoute)}'); + + @override + void didReplace({Route newRoute, Route oldRoute}) => FirebaseCrashlytics.instance.log('Nav didReplace to ${_name(newRoute)}'); + + String _name(Route route) => route?.settings?.name ?? 'unnamed ${route?.runtimeType}'; +}