Skip to content

Commit 8fa06bb

Browse files
committed
add firebase_analytics
1 parent 6bc7048 commit 8fa06bb

File tree

9 files changed

+238
-102
lines changed

9 files changed

+238
-102
lines changed

.gitignore

+7-1
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,10 @@ app.*.map.json
5050
*.config.dart
5151

5252
# environment variables
53-
/env/.env
53+
/env/.env
54+
55+
# firebase
56+
**/google-services.json
57+
**/GoogleService-Info.plist
58+
**/firebase_app_id_file.json
59+
**/firebase_options.dart

analysis_options.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ analyzer:
44
- "**.g.dart"
55
- "**.freezed.dart"
66
- "**.config.dart"
7+
- "/**firebase_options.dart"
78
linter:
89
rules:
910
file_names: false

ios/Runner.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
1515
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
1616
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
17+
E3D1E857B426C02057C7E6A4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0051BB325D22947D8DFFA017 /* GoogleService-Info.plist */; };
1718
/* End PBXBuildFile section */
1819

1920
/* Begin PBXCopyFilesBuildPhase section */
@@ -30,6 +31,7 @@
3031
/* End PBXCopyFilesBuildPhase section */
3132

3233
/* Begin PBXFileReference section */
34+
0051BB325D22947D8DFFA017 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
3335
0276AEBB815F3E1F871D58B9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
3436
04AB70C272D34F3EC829CB07 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3537
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
@@ -88,6 +90,7 @@
8890
97C146EF1CF9000F007C117D /* Products */,
8991
C726DF3E44E98AED28338CF8 /* Pods */,
9092
69CCFBE48BEFF6D1769DADE9 /* Frameworks */,
93+
0051BB325D22947D8DFFA017 /* GoogleService-Info.plist */,
9194
);
9295
sourceTree = "<group>";
9396
};
@@ -192,6 +195,7 @@
192195
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
193196
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
194197
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
198+
E3D1E857B426C02057C7E6A4 /* GoogleService-Info.plist in Resources */,
195199
);
196200
runOnlyForDeploymentPostprocessing = 0;
197201
};

lib/app/view/app.dart

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:flutter_localized_locales/flutter_localized_locales.dart';
4+
import 'package:gpt_detector/app/l10n/cubit/l10n_cubit.dart';
5+
import 'package:gpt_detector/app/l10n/extensions/app_l10n_extensions.dart';
6+
import 'package:gpt_detector/app/theme/cubit/theme_cubit.dart';
7+
import 'package:gpt_detector/app/theme/dark/dark_theme.dart';
8+
import 'package:gpt_detector/app/theme/light/light_theme.dart';
9+
import 'package:gpt_detector/core/extensions/context_extensions.dart';
10+
import 'package:gpt_detector/feature/splash/presentation/view/splash_view.dart';
11+
import 'package:gpt_detector/locator.dart';
12+
13+
class App extends StatelessWidget {
14+
const App({super.key});
15+
16+
@override
17+
Widget build(BuildContext context) {
18+
return MultiBlocProvider(
19+
providers: [
20+
BlocProvider(
21+
create: (context) => Locator.instance<L10nCubit>(),
22+
),
23+
BlocProvider(
24+
create: (context) => Locator.instance<ThemeCubit>(),
25+
),
26+
],
27+
child: BlocBuilder<ThemeCubit, ThemeState>(
28+
builder: (context, themeState) {
29+
return BlocBuilder<L10nCubit, L10nState>(
30+
builder: (context, l10nState) {
31+
return MaterialApp(
32+
debugShowCheckedModeBanner: false,
33+
34+
builder: (context, child) => MediaQuery(
35+
// Disables font scaling and bold text
36+
data: context.mediaQuery.copyWith(textScaler: TextScaler.noScaling, boldText: false),
37+
// Dismisses the keyboard globally
38+
child: GestureDetector(
39+
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
40+
child: child,
41+
),
42+
),
43+
44+
// Theme
45+
themeMode: themeState.themeMode,
46+
theme: Locator.instance<LightTheme>().theme,
47+
darkTheme: Locator.instance<DarkTheme>().theme,
48+
49+
// Localization
50+
locale: l10nState.locale,
51+
supportedLocales: AppLocalizations.supportedLocales,
52+
localizationsDelegates: const [
53+
...AppLocalizations.localizationsDelegates,
54+
LocaleNamesLocalizationsDelegate(),
55+
],
56+
57+
home: const SplashView(),
58+
);
59+
},
60+
);
61+
},
62+
),
63+
);
64+
}
65+
}

lib/bootstrap.dart

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import 'dart:async';
2+
3+
import 'package:firebase_core/firebase_core.dart';
4+
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
5+
import 'package:flutter/foundation.dart';
6+
import 'package:flutter/material.dart';
7+
import 'package:flutter/services.dart';
8+
import 'package:flutter_native_splash/flutter_native_splash.dart';
9+
import 'package:gpt_detector/core/utils/logger/logger_utils.dart';
10+
import 'package:gpt_detector/core/utils/observer/bloc_observer.dart';
11+
import 'package:gpt_detector/firebase_options.dart';
12+
import 'package:gpt_detector/locator.dart';
13+
import 'package:hydrated_bloc/hydrated_bloc.dart';
14+
import 'package:path_provider/path_provider.dart';
15+
16+
Future<void> bootstrap({required FutureOr<Widget> Function() builder}) async {
17+
final widgetBinding = WidgetsFlutterBinding.ensureInitialized();
18+
// Initialize Flutter Native Splash
19+
FlutterNativeSplash.preserve(widgetsBinding: widgetBinding);
20+
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
21+
await FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(kReleaseMode);
22+
// Register error handlers. For more info, see:
23+
// https://docs.flutter.dev/testing/errors
24+
// Pass all uncaught Flutter framework exceptions to Crashlytics
25+
FlutterError.onError = (FlutterErrorDetails details) {
26+
FirebaseCrashlytics.instance.recordFlutterError(details);
27+
LoggerUtils.instance.logFatalError(details.exceptionAsString(), details.stack);
28+
};
29+
// Pass all uncaught asynchronous errors that aren't handled by the Flutter framework to Crashlytics
30+
PlatformDispatcher.instance.onError = (error, stack) {
31+
FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
32+
LoggerUtils.instance.logFatalError(error.toString(), stack);
33+
return true;
34+
};
35+
36+
// Initialize Hydrated Bloc
37+
HydratedBloc.storage = await HydratedStorage.build(
38+
storageDirectory: await getApplicationDocumentsDirectory(),
39+
);
40+
// Initialize Bloc Observer
41+
Bloc.observer = AppBlocObserver();
42+
// Initialize Locator
43+
await Locator.locateServices();
44+
// Set Screen Orientation
45+
await SystemChrome.setPreferredOrientations(
46+
[DeviceOrientation.portraitUp],
47+
);
48+
49+
runApp(await builder());
50+
}
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// ignore_for_file: prefer_constructors_over_static_methods
2+
3+
import 'package:logger/logger.dart';
4+
5+
class LoggerUtils {
6+
LoggerUtils._();
7+
8+
static LoggerUtils? _instance;
9+
10+
static LoggerUtils get instance {
11+
_instance ??= LoggerUtils._();
12+
return _instance!;
13+
}
14+
15+
final Logger _logger = Logger(printer: PrettyPrinter(stackTraceBeginIndex: 2));
16+
17+
void logInfo(String message) {
18+
_logger.i(message);
19+
}
20+
21+
void logWarning(String message) {
22+
_logger.w(message);
23+
}
24+
25+
void logError(String message) {
26+
_logger.e(message);
27+
}
28+
29+
void logFatalError(String message, StackTrace? stackTrace) {
30+
_logger.f(message, stackTrace: stackTrace);
31+
}
32+
}

lib/main.dart

+3-86
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,6 @@
1-
import 'package:flutter/material.dart';
2-
import 'package:flutter/services.dart';
3-
import 'package:flutter_bloc/flutter_bloc.dart';
4-
import 'package:flutter_localized_locales/flutter_localized_locales.dart';
5-
import 'package:flutter_native_splash/flutter_native_splash.dart';
6-
import 'package:gpt_detector/app/l10n/cubit/l10n_cubit.dart';
7-
import 'package:gpt_detector/app/l10n/extensions/app_l10n_extensions.dart';
8-
import 'package:gpt_detector/app/theme/cubit/theme_cubit.dart';
9-
import 'package:gpt_detector/app/theme/dark/dark_theme.dart';
10-
import 'package:gpt_detector/app/theme/light/light_theme.dart';
11-
import 'package:gpt_detector/core/extensions/context_extensions.dart';
12-
import 'package:gpt_detector/core/utils/observer/bloc_observer.dart';
13-
import 'package:gpt_detector/feature/splash/presentation/view/splash_view.dart';
14-
import 'package:gpt_detector/locator.dart';
15-
import 'package:hydrated_bloc/hydrated_bloc.dart';
16-
import 'package:path_provider/path_provider.dart';
1+
import 'package:gpt_detector/app/view/app.dart';
2+
import 'package:gpt_detector/bootstrap.dart';
173

184
Future<void> main() async {
19-
final widgetBinding = WidgetsFlutterBinding.ensureInitialized();
20-
// Initialize Flutter Native Splash
21-
FlutterNativeSplash.preserve(widgetsBinding: widgetBinding);
22-
// Initialize Hydrated Bloc
23-
HydratedBloc.storage = await HydratedStorage.build(
24-
storageDirectory: await getApplicationDocumentsDirectory(),
25-
);
26-
// Initialize Bloc Observer
27-
Bloc.observer = AppBlocObserver();
28-
// Initialize Locator
29-
await Locator.locateServices();
30-
// Set Screen Orientation
31-
await SystemChrome.setPreferredOrientations(
32-
[DeviceOrientation.portraitUp],
33-
);
34-
runApp(const GPTDetector());
35-
}
36-
37-
class GPTDetector extends StatelessWidget {
38-
const GPTDetector({super.key});
39-
40-
@override
41-
Widget build(BuildContext context) {
42-
return MultiBlocProvider(
43-
providers: [
44-
BlocProvider(
45-
create: (context) => Locator.instance<L10nCubit>(),
46-
),
47-
BlocProvider(
48-
create: (context) => Locator.instance<ThemeCubit>(),
49-
),
50-
],
51-
child: BlocBuilder<ThemeCubit, ThemeState>(
52-
builder: (context, themeState) {
53-
return BlocBuilder<L10nCubit, L10nState>(
54-
builder: (context, l10nState) {
55-
return MaterialApp(
56-
debugShowCheckedModeBanner: false,
57-
58-
builder: (context, child) => MediaQuery(
59-
// Disables font scaling and bold text
60-
data: context.mediaQuery.copyWith(textScaler: TextScaler.noScaling, boldText: false),
61-
// Dismisses the keyboard globally
62-
child: GestureDetector(
63-
onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
64-
child: child,
65-
),
66-
),
67-
68-
// Theme
69-
themeMode: themeState.themeMode,
70-
theme: Locator.instance<LightTheme>().theme,
71-
darkTheme: Locator.instance<DarkTheme>().theme,
72-
73-
// Localization
74-
locale: l10nState.locale,
75-
supportedLocales: AppLocalizations.supportedLocales,
76-
localizationsDelegates: const [
77-
...AppLocalizations.localizationsDelegates,
78-
LocaleNamesLocalizationsDelegate(),
79-
],
80-
81-
home: const SplashView(),
82-
);
83-
},
84-
);
85-
},
86-
),
87-
);
88-
}
5+
await bootstrap(builder: App.new);
896
}

0 commit comments

Comments
 (0)