Files
firka/firka/lib/app/initialization_screen.dart

220 lines
7.7 KiB
Dart

import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:firka/app/app_state.dart';
import 'package:firka/app/initialization.dart';
import 'package:firka/core/bloc/home_refresh_cubit.dart';
import 'package:firka/core/settings.dart';
import 'package:firka/core/bloc/profile_picture_cubit.dart';
import 'package:firka/core/bloc/reauth_cubit.dart';
import 'package:firka/core/bloc/settings_cubit.dart';
import 'package:firka/core/bloc/theme_cubit.dart';
import 'package:firka/core/firka_bundle.dart';
import 'package:firka/routing/app_router.dart';
import 'package:firka/services/watch_sync_helper.dart';
import 'package:firka/ui/phone/pages/extras/main_wear_pair.dart';
import 'package:firka/l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';
class InitializationScreen extends StatefulWidget {
const InitializationScreen({super.key});
@override
State<InitializationScreen> createState() => _InitializationScreenState();
}
class _InitializationScreenState extends State<InitializationScreen> {
GoRouter? _router;
final Future<AppInitialization> _init = initializeApp().timeout(
const Duration(seconds: 20),
);
@override
Widget build(BuildContext context) {
return FutureBuilder<AppInitialization>(
future: _init,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
logger.shout(
"Error in InitializationScreen",
snapshot.error.toString(),
snapshot.stackTrace,
);
FlutterNativeSplash.remove();
return MaterialApp(
key: const ValueKey('errorPage'),
home: DefaultAssetBundle(
bundle: FirkaBundle(),
child: Scaffold(
body: Center(
child: Text(
'Error initializing app: ${snapshot.error}',
style: const TextStyle(color: Colors.red),
),
),
),
),
);
}
assert(snapshot.data != null);
initData = snapshot.data!;
initDone = true;
FlutterNativeSplash.remove();
WatchSyncHelper.initialize();
if (Platform.isAndroid) {
WatchSyncHelper.setWearSyncMethodCallHandler();
}
if (Platform.isIOS) {
unawaited(() async {
try {
await WatchSyncHelper.sendLanguageToWatch();
} catch (e) {
logger.warning(
'[Init] Failed to publish language to Watch after sync init: $e',
);
}
}());
}
if (!initData.hasWatchListener) {
initData.hasWatchListener = true;
WatchSyncHelper.onWatchMessage = (msg) {
logger.finest("WatchOS IPC [Watch -> Phone]: ${msg["id"]}");
switch (msg["id"]) {
case "ping":
if (initData.tokens.isNotEmpty) {
logger.finest("WatchOS IPC [Phone -> Watch]: pong");
unawaited(
WatchSyncHelper.sendMessageToWatch({'id': 'pong'}),
);
_router?.go('/home');
WidgetsBinding.instance.addPostFrameCallback((_) {
final ctx = navigatorKey.currentContext;
if (ctx != null && ctx.mounted) {
showWearBottomSheet(
ctx,
initData,
Platform.isAndroid ? 'Wear OS' : 'Apple Watch',
);
}
});
}
}
};
if (Platform.isAndroid) {
WatchSyncHelper.watchMessageStream.listen((msg) async {
WatchSyncHelper.onWatchMessage?.call(msg);
if (msg['id'] == 'request_sync' &&
initDone &&
isWearOsSupportEnabled()) {
await WatchSyncHelper.runWearSyncInForeground(
initData.client,
);
}
});
if (isWearOsSupportEnabled()) {
unawaited(() async {
try {
await WatchSyncHelper.startWearSyncServiceWithFreshCache(
initData.client,
initData.appDir.path,
);
} catch (e) {
logger.warning(
'[Init] Failed to start Wear sync service on launch: $e',
);
}
}());
}
}
}
if (_router == null) {
_router = createAppRouter();
appRouter = _router;
}
final themeCubit = initData.themeCubit!;
final settingsCubit = initData.settingsCubit!;
final profilePictureCubit = initData.profilePictureCubit!;
final reauthCubit = initData.reauthCubit!;
final homeRefreshCubit = initData.homeRefreshCubit!;
return MultiBlocProvider(
providers: [
BlocProvider<ThemeCubit>.value(value: themeCubit),
BlocProvider<SettingsCubit>.value(value: settingsCubit),
BlocProvider<ProfilePictureCubit>.value(
value: profilePictureCubit,
),
BlocProvider<ReauthCubit>.value(value: reauthCubit),
BlocProvider<HomeRefreshCubit>.value(value: homeRefreshCubit),
],
child: MaterialApp.router(
title: 'Firka',
key: const ValueKey('firkaApp'),
routerConfig: _router!,
theme: ThemeData(
primarySwatch: Colors.lightGreen,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
builder: (context, child) {
return BlocBuilder<ThemeCubit, ThemeState>(
builder: (context, themeState) {
final isLight = themeState.isLightMode;
final overlay = SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: isLight
? Brightness.dark
: Brightness.light,
statusBarBrightness: isLight
? Brightness.light
: Brightness.dark,
systemStatusBarContrastEnforced: false,
);
SystemChrome.setSystemUIOverlayStyle(overlay);
return AnnotatedRegion<SystemUiOverlayStyle>(
value: overlay,
child: child ?? const SizedBox.shrink(),
);
},
);
},
),
);
}
return MaterialApp(
home: DefaultAssetBundle(
bundle: FirkaBundle(),
child: Scaffold(
backgroundColor: const Color(0xFF7CA120),
body: Container(),
),
),
);
},
);
}
}