moshaf_boilerplate 3.0.0
moshaf_boilerplate: ^3.0.0 copied to clipboard
A CLI tool for generating Flutter boilerplate structures based on Clean Architecture, BLoC, dependencies, and more.
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:provider/provider.dart';
import 'package:example/app.dart';
import 'package:example/core/analytics/analytic.dart';
import 'package:example/core/config/app_config.dart';
import 'package:example/core/config/di_module/init_config.dart';
import 'package:example/core/config/firebase_support.dart';
import 'package:example/core/config/startup_error_app.dart';
import 'package:example/core/developer_tools/api_logs/api_log_store.dart';
import 'package:example/core/developer_tools/developer_mode_notifier.dart';
import 'package:example/core/env/env.dart';
import 'package:example/core/env/secure_storage_key.dart';
import 'package:example/core/feature_flags/feature_flag_notifier.dart';
import 'package:example/core/utils/bloc_providers.dart';
import 'package:example/core/utils/error_reporter.dart';
import 'package:example/core/utils/storage_data.dart';
Future<void> mainCommon({required Flavor flavor}) async {
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
String? locale;
try {
await AppConfig.initialize(flavor: flavor);
await initConfig();
// Only true when Firebase (and specifically Crashlytics) actually got
// initialized above — otherwise Crashlytics itself would throw inside
// the error handler.
ErrorReporter.crashlyticsReady = Env.enableFirebase &&
isFirebaseSupported &&
isFirebaseCrashlyticsSupported;
// setup analytic
final analytic = getIt<Analytic>();
await analytic.init();
// fetch remote feature flags before first frame; falls back to all-off
// internally on any failure, so this never throws.
await getIt<FeatureFlagNotifier>().initialize();
// Dev: developer tools are always on, no gesture needed. Staging/prod
// stay off until unlocked from About (see developer_unlock_service.dart).
if (AppConfig.isDev) {
getIt<DeveloperModeNotifier>().enable();
}
locale = await storage.read(key: localeLangId);
} catch (e, s) {
// Startup must always end in a runApp call. Without this, a throw here
// left the Flutter view unattached — a blank window with the reason
// logged nowhere the user could reach.
debugPrint('Startup failed: $e\n$s');
ErrorReporter.recordZoneError(e, s);
runApp(
StartupErrorApp(
error: e,
onRetry: () async {
// initConfig registers singletons, so a plain retry would throw
// "already registered".
await getIt.reset();
await mainCommon(flavor: flavor);
},
),
);
return;
}
runApp(
ScreenUtilInit(
builder: (_, __) => getBlocWrapper(
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: getIt<FeatureFlagNotifier>()),
ChangeNotifierProvider.value(value: getIt<DeveloperModeNotifier>()),
ChangeNotifierProvider.value(value: getIt<ApiLogStore>()),
],
child: EasyLocalization(
supportedLocales: const [Locale('en'), Locale('id')],
path: 'assets/translations',
fallbackLocale: const Locale('en'),
startLocale: Locale(locale ?? 'en'),
// Default is a bare ErrorWidget — the grey box again. A failed
// translation load must not take the whole app down with it.
errorWidget: (message) => StartupErrorApp(
error: message ?? 'Translations failed to load',
onRetry: () async {
await getIt.reset();
await mainCommon(flavor: flavor);
},
),
child: const App(),
),
),
),
),
);
}
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
debugPrint("Handling a background message: ${message.messageId}");
}