import 'package:d4rt_formulas/d4rt_formulas.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'ai/import_from_text_screen.dart'; import 'database/database_service.dart'; import 'service_locator.dart'; import 'ai/formula_list.dart'; import 'corpus.dart'; import 'defaults/default_corpus.dart'; import 'formula_models.dart' as models; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Setup service locator and initialize the database setupLocator(); var corpusFuture = loadCorpusFromDatabaseOrAssets(); runApp( MyApp(corpusFuture)); } final GlobalKey<_CorpusLoaderState> corpusLoaderKey = GlobalKey<_CorpusLoaderState>(); class MyApp extends StatelessWidget { final Future corpusFuture; MyApp(this.corpusFuture, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: CorpusLoader(corpusFuture), ); } } class CorpusLoader extends StatefulWidget { final Future corpusFuture; CorpusLoader(this.corpusFuture, {Key? key}) : super(key: corpusLoaderKey); @override State createState() => _CorpusLoaderState(); } class _CorpusLoaderState extends State { late Future _corpusFuture; @override void initState() { super.initState(); _corpusFuture = widget.corpusFuture; } void _handleImport() { _corpusFuture.then((corpus) { Navigator.push( context, MaterialPageRoute( builder: (context) => ImportFromTextScreen( corpus: corpus, ), ), ).then((result) { setState(() { // Refresh the list when returning from import }); }); }); } @override Widget build(BuildContext context) { return FutureBuilder( future: _corpusFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.hasError) { return Center(child: Text('Error loading corpus: ${snapshot.error}')); } var corpus = snapshot.data!; _registerCorpusInstance(corpus); return Scaffold( appBar: AppBar( title: const Text('Formulas'), actions: [ IconButton( icon: const Icon(Icons.library_add), tooltip: 'Import formulas', onPressed: _handleImport, ), ], ), body: FormulaList( corpus: snapshot.data!, onImport: _handleImport, ), ); } return const Center(child: CircularProgressIndicator()); }, ); } void _registerCorpusInstance(Corpus corpus) { var existingCorpus = GetIt.instance.isRegistered() ? GetIt.instance.get() : null; if (existingCorpus == null ) { print( "Registering corpus in GetIt for the first time." ); GetIt.instance.registerSingleton(corpus); } else if( existingCorpus == corpus ){ print( "The corpus was already registered and is the same instance, no need to re-register." ); } else if( existingCorpus != corpus ){ throw Exception( "The corpus was already registered but is a different instance. This should not happen." ); } } } /// Attempts to load corpus from database first, falls back to default corpus if database is empty Future loadCorpusFromDatabaseOrAssets() async { final database = getDatabase(); try { // Try to load from database first final dbElements = await database.loadCorpusElements(); if (dbElements.isEmpty) { // Database is empty, load default corpus and save to database final defaultCorpus = await createDefaultCorpus(); // Convert corpus to elements and save to database final elements = []; elements.addAll(defaultCorpus.allUnits().cast()); elements.addAll(defaultCorpus.getFormulas().cast()); await database.saveCorpusElements(elements); return defaultCorpus; } else { // Load corpus from database elements return await Corpus.fromDatabaseElements(dbElements); } } catch (e, st) { // If there's an error loading from database, fall back to default corpus errorHandler.notify(e,st); return await createDefaultCorpus(); } } /// Shows a dialog to ask user if they want to use the default corpus Future showUseDefaultCorpusDialog(BuildContext context) async { return await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: const Text('Empty Database'), content: const Text('The database is empty. Would you like to load the default corpus?'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), // Don't use default corpus child: const Text('No'), ), TextButton( onPressed: () => Navigator.of(context).pop(true), // Use default corpus child: const Text('Yes'), ), ], ); }, ) ?? false; // Default to false if dialog is dismissed }