Skip to content
Snippets Groups Projects
main.dart 7.67 KiB
Newer Older
tylersavery's avatar
tylersavery committed
import 'dart:io';
vjrj's avatar
vjrj committed
import 'package:connectivity_wrapper/connectivity_wrapper.dart';
vjrj's avatar
vjrj committed
import 'package:cron/cron.dart';
anfeichtinger's avatar
anfeichtinger committed
import 'package:easy_localization/easy_localization.dart';
vjrj's avatar
vjrj committed
import 'package:easy_logger/easy_logger.dart';
vjrj's avatar
vjrj committed
import 'package:flutter/foundation.dart';
anfeichtinger's avatar
anfeichtinger committed
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
anfeichtinger's avatar
anfeichtinger committed
import 'package:flutter_displaymode/flutter_displaymode.dart';
vjrj's avatar
vjrj committed
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:hive_flutter/hive_flutter.dart';
anfeichtinger's avatar
anfeichtinger committed
import 'package:hydrated_bloc/hydrated_bloc.dart';
vjrj's avatar
vjrj committed
import 'package:introduction_screen/introduction_screen.dart';
anfeichtinger's avatar
anfeichtinger committed
import 'package:path_provider/path_provider.dart';
vjrj's avatar
vjrj committed
import 'package:responsive_framework/responsive_wrapper.dart';
anfeichtinger's avatar
anfeichtinger committed

vjrj's avatar
vjrj committed
import 'app_bloc_observer.dart';
vjrj's avatar
vjrj committed
import 'data/models/app_cubit.dart';
import 'data/models/app_state.dart';
import 'data/models/node_list_cubit.dart';
import 'data/models/payment_cubit.dart';
vjrj's avatar
vjrj committed
import 'g1/api.dart';
vjrj's avatar
vjrj committed
import 'shared_prefs.dart';
import 'ui/screens/skeleton_screen.dart';
vjrj's avatar
vjrj committed

vjrj's avatar
vjrj committed
// logs
final EasyLogger logger = EasyLogger(
vjrj's avatar
vjrj committed
  name: 'ginkgo',
vjrj's avatar
vjrj committed
  defaultLevel: LevelMessages.debug,
  enableBuildModes: <BuildMode>[
    BuildMode.debug,
    BuildMode.profile,
    BuildMode.release
  ],
  enableLevels: <LevelMessages>[
    LevelMessages.debug,
    LevelMessages.info,
    LevelMessages.error,
    LevelMessages.warning
  ],
);
anfeichtinger's avatar
anfeichtinger committed

void main() async {
  /// Initialize packages
  WidgetsFlutterBinding.ensureInitialized();
  await EasyLocalization.ensureInitialized();
vjrj's avatar
vjrj committed
  Bloc.observer = AppBlocObserver();
vjrj's avatar
vjrj committed

  if (!kIsWeb && Platform.isAndroid) {
tylersavery's avatar
tylersavery committed
    await FlutterDisplayMode.setHighRefreshRate();
vjrj's avatar
vjrj committed
  }

vjrj's avatar
vjrj committed
  final SharedPreferencesHelper shared = SharedPreferencesHelper();
  await shared.init();
  await shared.getWallet();
  assert(shared.getPubKey() != null);

vjrj's avatar
vjrj committed
  // .env
vjrj's avatar
vjrj committed
  await dotenv.load(
      fileName: kReleaseMode
          ? 'assets/env.production.txt'
          : 'assets/.env.development');
vjrj's avatar
vjrj committed

  if (kIsWeb) {
    await Hive.initFlutter();
    HydratedBloc.storage = await HydratedStorage.build(
        storageDirectory: HydratedStorage.webStorageDirectory);
  } else {
    final Directory tmpDir = await getTemporaryDirectory();
    Hive.init(tmpDir.toString());
vjrj's avatar
vjrj committed
    HydratedBloc.storage =
        await HydratedStorage.build(storageDirectory: tmpDir);
tylersavery's avatar
tylersavery committed
  }
vjrj's avatar
vjrj committed

vjrj's avatar
vjrj committed
  // Reset hive during developing
  if (!kReleaseMode) {
vjrj's avatar
vjrj committed
    // await HydratedBloc.storage.clear();
vjrj's avatar
vjrj committed
  }
vjrj's avatar
vjrj committed

  runApp(
    EasyLocalization(
      path: 'assets/translations',
      supportedLocales: const <Locale>[
        Locale('en'),
vjrj's avatar
vjrj committed
        Locale('es'),
vjrj's avatar
vjrj committed
        Locale('fr'),
      ],
      fallbackLocale: const Locale('en'),
      useFallbackTranslations: true,
vjrj's avatar
vjrj committed
      child: MultiBlocProvider(providers: <BlocProvider<dynamic>>[
        BlocProvider<AppCubit>(create: (BuildContext context) => AppCubit()),
        BlocProvider<PaymentCubit>(
            create: (BuildContext context) => PaymentCubit()),
        BlocProvider<NodeListCubit>(
            create: (BuildContext context) => NodeListCubit()),
        // Add other BlocProviders here if needed
      ], child: const MyApp()),
vjrj's avatar
vjrj committed
class AppIntro extends StatefulWidget {
  const AppIntro({super.key});

  @override
  State<AppIntro> createState() => _AppIntro();
}

class _AppIntro extends State<AppIntro> {
  final GlobalKey<IntroductionScreenState> introKey =
      GlobalKey<IntroductionScreenState>();

  void _onIntroEnd(BuildContext context) {
vjrj's avatar
vjrj committed
    BlocProvider.of<AppCubit>(context).introViewed();
vjrj's avatar
vjrj committed
    Navigator.of(context).pushReplacement(
vjrj's avatar
vjrj committed
      MaterialPageRoute<void>(
          builder: (BuildContext _) => const SkeletonScreen()),
vjrj's avatar
vjrj committed
    );
  }

  @override
  Widget build(BuildContext context) {
vjrj's avatar
vjrj committed
    return BlocBuilder<AppCubit, AppState>(
        builder: (BuildContext buildContext, AppState state) =>
            IntroductionScreen(
              key: introKey,
              pages: <PageViewModel>[
                for (int i = 1; i <= 5; i++)
                  createPageViewModel(
                      'intro_${i}_title',
                      'intro_${i}_description',
                      'assets/img/undraw_intro_$i.png'),
              ],
              onDone: () => _onIntroEnd(buildContext),
              showSkipButton: true,
              skipOrBackFlex: 0,
              onSkip: () => _onIntroEnd(buildContext),
              nextFlex: 0,
              skip: Text(tr('skip')),
              next: const Icon(Icons.arrow_forward),
              done: Text(tr('start'),
                  style: const TextStyle(fontWeight: FontWeight.w600)),
              dotsDecorator: const DotsDecorator(
                size: Size(10.0, 10.0),
                color: Color(0xFFBDBDBD),
                activeColor: Colors.blueAccent,
                activeSize: Size(22.0, 10.0),
                activeShape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(Radius.circular(25.0)),
                ),
              ),
            ));
vjrj's avatar
vjrj committed
  }
}

PageViewModel createPageViewModel(
    String title, String body, String imageAsset) {
  return PageViewModel(
    title: tr(title),
    body: tr(body),
    image: Image.asset(imageAsset),
    decoration: const PageDecoration(
      pageColor: Colors.white,
      bodyTextStyle: TextStyle(fontSize: 18),
      titleTextStyle: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
    ),
  );
}

vjrj's avatar
vjrj committed
class MyApp extends StatefulWidget {
vjrj's avatar
vjrj committed
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
anfeichtinger's avatar
anfeichtinger committed
  @override
  Widget build(BuildContext context) {
vjrj's avatar
vjrj committed
    return ConnectivityAppWrapper(
        app: MaterialApp(
      /// Localization is not available for the title.
      title: 'Ğ1nkgo',
      theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
      darkTheme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme),

      /// Theme stuff

      /// Localization stuff
      localizationsDelegates: context.localizationDelegates,
      supportedLocales: context.supportedLocales,
      locale: context.locale,
      debugShowCheckedModeBanner: false,
      home: MediaQuery(
        data: const MediaQueryData(),
        child: BlocProvider.of<AppCubit>(context).isIntroViewed
            ? const SkeletonScreen()
            : const AppIntro(),
      ),
      builder: (BuildContext buildContext, Widget? widget) {
        final NodeListCubit nodeListCubit =
            BlocProvider.of<NodeListCubit>(buildContext);
        final int nDuniterNodes = nodeListCubit.duniterNodes.length;
        final int nCesiumPlusNodes = nodeListCubit.cesiumPlusNodes.length;

        // Load nodes from /network/peers
        fetchDuniterNodes(nodeListCubit);

        logger(
            'Starting with $nDuniterNodes duniter nodes and $nCesiumPlusNodes c+ nodes');

        final Cron cron = Cron();
        cron.schedule(Schedule.parse('*/45 * * * *'), () async {
          // Every 45m check for faster node (maybe it something costly in terms of
          // bandwidth
          fetchDuniterNodes(nodeListCubit);
        });
        cron.schedule(Schedule.parse('*/90 * * * *'), () async {
          nodeListCubit.cleanDuniterErrorStats();
        });

        return ResponsiveWrapper.builder(
          ConnectivityWidgetWrapper(
            message: tr('offline'),
            height: 20,
            child: widget!,
vjrj's avatar
vjrj committed
          ),
vjrj's avatar
vjrj committed
          maxWidth: 480,
          minWidth: 480,
          // defaultScale: true,
          breakpoints: <ResponsiveBreakpoint>[
            // const ResponsiveBreakpoint.resize(200, name: MOBILE),
            const ResponsiveBreakpoint.resize(480, name: TABLET),
            const ResponsiveBreakpoint.resize(480, name: DESKTOP),
          ],
          background: Container(color: const Color(0xFFF5F5F5)),
        );
      },
    ));
anfeichtinger's avatar
anfeichtinger committed
  }
}