diff --git a/docker/Dockerfile b/docker/Dockerfile index 534fd40..836c8a5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,7 +1,20 @@ FROM ghcr.io/cirruslabs/flutter:stable -# Install cmake, ninja, clang, pkg-config for flutter linux -RUN apt-get update && apt-get install -y cmake ninja-build clang pkg-config libgtk-3-dev liblzma-dev +# Install cmake, ninja, clang, pkg-config, and other tools for flutter linux +RUN apt-get update && apt-get install -y \ + cmake \ + ninja-build \ + clang \ + pkg-config \ + libgtk-3-dev \ + liblzma-dev \ + binutils-dev \ + build-essential \ + lld \ + binutils + +# Create symlinks for the linker to ensure it's accessible +RUN ln -sf /usr/bin/ld.lld /usr/bin/ld WORKDIR /app diff --git a/lib/database/database_service.dart b/lib/database/database_service.dart new file mode 100644 index 0000000..3a0dba0 --- /dev/null +++ b/lib/database/database_service.dart @@ -0,0 +1,15 @@ +import 'package:get_it/get_it.dart'; + +// Conditionally import the correct database file based on platform +import 'formulas_database.dart' + if (dart.library.html) 'formulas_database_web.dart'; + +GetIt locator = GetIt.instance; + +void setupLocator() { + locator.registerSingleton(FormulasDatabase()); +} + +FormulasDatabase getDatabase() { + return locator(); +} \ No newline at end of file diff --git a/lib/database/formulas_database.dart b/lib/database/formulas_database.dart new file mode 100644 index 0000000..69d1000 --- /dev/null +++ b/lib/database/formulas_database.dart @@ -0,0 +1,56 @@ +import 'package:drift/drift.dart'; +import 'package:drift/native.dart'; +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; +import 'dart:io'; + +part 'formulas_database.g.dart'; + +// Define the formulas table with a single text column for formula descriptions +class Formulas extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get formula => text()(); +} + +@DriftDatabase(tables: [Formulas]) +class FormulasDatabase extends _$FormulasDatabase { + FormulasDatabase() : super(_openConnection()); + + @override + int get schemaVersion => 1; + + // Method to insert a new formula + Future insertFormula(String formulaText) { + return into(formulas).insert(FormulasCompanion.insert(formula: formulaText)); + } + + // Method to get all formulas + Future> getAllFormulas() { + return select(formulas).get(); + } + + // Method to get a formula by ID + Future getFormulaById(int id) { + return (select(formulas)..where((tbl) => tbl.id.equals(id))).getSingleOrNull(); + } + + // Method to update a formula + Future updateFormula(int id, String newFormula) { + return (update(formulas)..where((tbl) => tbl.id.equals(id))) + .write(FormulasCompanion.insert(formula: newFormula)); + } + + // Method to delete a formula + Future deleteFormula(int id) { + return (delete(formulas)..where((tbl) => tbl.id.equals(id))).go(); + } +} + +LazyDatabase _openConnection() { + return LazyDatabase(() async { + // For native platforms (Linux, Windows, macOS, Android, iOS) + final dbFolder = await getApplicationDocumentsDirectory(); + final file = File(p.join(dbFolder.path, 'formulas.sqlite')); + return NativeDatabase.createInBackground(file); + }); +} \ No newline at end of file diff --git a/lib/database/formulas_database.g.dart b/lib/database/formulas_database.g.dart new file mode 100644 index 0000000..785a205 --- /dev/null +++ b/lib/database/formulas_database.g.dart @@ -0,0 +1,338 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'formulas_database.dart'; + +// ignore_for_file: type=lint +class $FormulasTable extends Formulas with TableInfo<$FormulasTable, Formula> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $FormulasTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _formulaMeta = const VerificationMeta( + 'formula', + ); + @override + late final GeneratedColumn formula = GeneratedColumn( + 'formula', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, formula]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'formulas'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('formula')) { + context.handle( + _formulaMeta, + formula.isAcceptableOrUnknown(data['formula']!, _formulaMeta), + ); + } else if (isInserting) { + context.missing(_formulaMeta); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Formula map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Formula( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + formula: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}formula'], + )!, + ); + } + + @override + $FormulasTable createAlias(String alias) { + return $FormulasTable(attachedDatabase, alias); + } +} + +class Formula extends DataClass implements Insertable { + final int id; + final String formula; + const Formula({required this.id, required this.formula}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['formula'] = Variable(formula); + return map; + } + + FormulasCompanion toCompanion(bool nullToAbsent) { + return FormulasCompanion(id: Value(id), formula: Value(formula)); + } + + factory Formula.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Formula( + id: serializer.fromJson(json['id']), + formula: serializer.fromJson(json['formula']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'formula': serializer.toJson(formula), + }; + } + + Formula copyWith({int? id, String? formula}) => + Formula(id: id ?? this.id, formula: formula ?? this.formula); + Formula copyWithCompanion(FormulasCompanion data) { + return Formula( + id: data.id.present ? data.id.value : this.id, + formula: data.formula.present ? data.formula.value : this.formula, + ); + } + + @override + String toString() { + return (StringBuffer('Formula(') + ..write('id: $id, ') + ..write('formula: $formula') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, formula); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Formula && + other.id == this.id && + other.formula == this.formula); +} + +class FormulasCompanion extends UpdateCompanion { + final Value id; + final Value formula; + const FormulasCompanion({ + this.id = const Value.absent(), + this.formula = const Value.absent(), + }); + FormulasCompanion.insert({ + this.id = const Value.absent(), + required String formula, + }) : formula = Value(formula); + static Insertable custom({ + Expression? id, + Expression? formula, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (formula != null) 'formula': formula, + }); + } + + FormulasCompanion copyWith({Value? id, Value? formula}) { + return FormulasCompanion( + id: id ?? this.id, + formula: formula ?? this.formula, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (formula.present) { + map['formula'] = Variable(formula.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('FormulasCompanion(') + ..write('id: $id, ') + ..write('formula: $formula') + ..write(')')) + .toString(); + } +} + +abstract class _$FormulasDatabase extends GeneratedDatabase { + _$FormulasDatabase(QueryExecutor e) : super(e); + $FormulasDatabaseManager get managers => $FormulasDatabaseManager(this); + late final $FormulasTable formulas = $FormulasTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [formulas]; +} + +typedef $$FormulasTableCreateCompanionBuilder = + FormulasCompanion Function({Value id, required String formula}); +typedef $$FormulasTableUpdateCompanionBuilder = + FormulasCompanion Function({Value id, Value formula}); + +class $$FormulasTableFilterComposer + extends Composer<_$FormulasDatabase, $FormulasTable> { + $$FormulasTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get formula => $composableBuilder( + column: $table.formula, + builder: (column) => ColumnFilters(column), + ); +} + +class $$FormulasTableOrderingComposer + extends Composer<_$FormulasDatabase, $FormulasTable> { + $$FormulasTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get formula => $composableBuilder( + column: $table.formula, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$FormulasTableAnnotationComposer + extends Composer<_$FormulasDatabase, $FormulasTable> { + $$FormulasTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get formula => + $composableBuilder(column: $table.formula, builder: (column) => column); +} + +class $$FormulasTableTableManager + extends + RootTableManager< + _$FormulasDatabase, + $FormulasTable, + Formula, + $$FormulasTableFilterComposer, + $$FormulasTableOrderingComposer, + $$FormulasTableAnnotationComposer, + $$FormulasTableCreateCompanionBuilder, + $$FormulasTableUpdateCompanionBuilder, + ( + Formula, + BaseReferences<_$FormulasDatabase, $FormulasTable, Formula>, + ), + Formula, + PrefetchHooks Function() + > { + $$FormulasTableTableManager(_$FormulasDatabase db, $FormulasTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$FormulasTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$FormulasTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$FormulasTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value formula = const Value.absent(), + }) => FormulasCompanion(id: id, formula: formula), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required String formula, + }) => FormulasCompanion.insert(id: id, formula: formula), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$FormulasTableProcessedTableManager = + ProcessedTableManager< + _$FormulasDatabase, + $FormulasTable, + Formula, + $$FormulasTableFilterComposer, + $$FormulasTableOrderingComposer, + $$FormulasTableAnnotationComposer, + $$FormulasTableCreateCompanionBuilder, + $$FormulasTableUpdateCompanionBuilder, + (Formula, BaseReferences<_$FormulasDatabase, $FormulasTable, Formula>), + Formula, + PrefetchHooks Function() + >; + +class $FormulasDatabaseManager { + final _$FormulasDatabase _db; + $FormulasDatabaseManager(this._db); + $$FormulasTableTableManager get formulas => + $$FormulasTableTableManager(_db, _db.formulas); +} diff --git a/lib/database/formulas_database_web.dart b/lib/database/formulas_database_web.dart new file mode 100644 index 0000000..1129aad --- /dev/null +++ b/lib/database/formulas_database_web.dart @@ -0,0 +1,54 @@ +import 'package:drift/drift.dart'; +import 'package:drift/web.dart'; +import 'package:path_provider/path_provider.dart'; + +part 'formulas_database_web.g.dart'; + +// Define the formulas table with a single text column for formula descriptions +class Formulas extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get formula => text()(); +} + +@DriftDatabase(tables: [Formulas]) +class FormulasDatabase extends _$FormulasDatabase { + FormulasDatabase() : super(_openConnection()); + + @override + int get schemaVersion => 1; + + // Method to insert a new formula + Future insertFormula(String formulaText) { + return into(formulas).insert(FormulasCompanion.insert(formula: formulaText)); + } + + // Method to get all formulas + Future> getAllFormulas() { + return select(formulas).get(); + } + + // Method to get a formula by ID + Future getFormulaById(int id) { + return (select(formulas)..where((tbl) => tbl.id.equals(id))).getSingleOrNull(); + } + + // Method to update a formula + Future updateFormula(int id, String newFormula) { + return (update(formulas)..where((tbl) => tbl.id.equals(id))) + .write(FormulasCompanion.insert(formula: newFormula)); + } + + // Method to delete a formula + Future deleteFormula(int id) { + return (delete(formulas)..where((tbl) => tbl.id.equals(id))).go(); + } +} + +LazyDatabase _openConnection() { + return LazyDatabase(() async { + // For web, use the web implementation + return WebDatabase.withStorage( + await DriftWebStorage.indexedDb('formulas_db'), + ); + }); +} \ No newline at end of file diff --git a/lib/database/formulas_database_web.g.dart b/lib/database/formulas_database_web.g.dart new file mode 100644 index 0000000..91e0205 --- /dev/null +++ b/lib/database/formulas_database_web.g.dart @@ -0,0 +1,338 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'formulas_database_web.dart'; + +// ignore_for_file: type=lint +class $FormulasTable extends Formulas with TableInfo<$FormulasTable, Formula> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $FormulasTable(this.attachedDatabase, [this._alias]); + static const VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', + aliasedName, + false, + hasAutoIncrement: true, + type: DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: GeneratedColumn.constraintIsAlways( + 'PRIMARY KEY AUTOINCREMENT', + ), + ); + static const VerificationMeta _formulaMeta = const VerificationMeta( + 'formula', + ); + @override + late final GeneratedColumn formula = GeneratedColumn( + 'formula', + aliasedName, + false, + type: DriftSqlType.string, + requiredDuringInsert: true, + ); + @override + List get $columns => [id, formula]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'formulas'; + @override + VerificationContext validateIntegrity( + Insertable instance, { + bool isInserting = false, + }) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('formula')) { + context.handle( + _formulaMeta, + formula.isAcceptableOrUnknown(data['formula']!, _formulaMeta), + ); + } else if (isInserting) { + context.missing(_formulaMeta); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Formula map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return Formula( + id: attachedDatabase.typeMapping.read( + DriftSqlType.int, + data['${effectivePrefix}id'], + )!, + formula: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}formula'], + )!, + ); + } + + @override + $FormulasTable createAlias(String alias) { + return $FormulasTable(attachedDatabase, alias); + } +} + +class Formula extends DataClass implements Insertable { + final int id; + final String formula; + const Formula({required this.id, required this.formula}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['formula'] = Variable(formula); + return map; + } + + FormulasCompanion toCompanion(bool nullToAbsent) { + return FormulasCompanion(id: Value(id), formula: Value(formula)); + } + + factory Formula.fromJson( + Map json, { + ValueSerializer? serializer, + }) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Formula( + id: serializer.fromJson(json['id']), + formula: serializer.fromJson(json['formula']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'formula': serializer.toJson(formula), + }; + } + + Formula copyWith({int? id, String? formula}) => + Formula(id: id ?? this.id, formula: formula ?? this.formula); + Formula copyWithCompanion(FormulasCompanion data) { + return Formula( + id: data.id.present ? data.id.value : this.id, + formula: data.formula.present ? data.formula.value : this.formula, + ); + } + + @override + String toString() { + return (StringBuffer('Formula(') + ..write('id: $id, ') + ..write('formula: $formula') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, formula); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Formula && + other.id == this.id && + other.formula == this.formula); +} + +class FormulasCompanion extends UpdateCompanion { + final Value id; + final Value formula; + const FormulasCompanion({ + this.id = const Value.absent(), + this.formula = const Value.absent(), + }); + FormulasCompanion.insert({ + this.id = const Value.absent(), + required String formula, + }) : formula = Value(formula); + static Insertable custom({ + Expression? id, + Expression? formula, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (formula != null) 'formula': formula, + }); + } + + FormulasCompanion copyWith({Value? id, Value? formula}) { + return FormulasCompanion( + id: id ?? this.id, + formula: formula ?? this.formula, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (formula.present) { + map['formula'] = Variable(formula.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('FormulasCompanion(') + ..write('id: $id, ') + ..write('formula: $formula') + ..write(')')) + .toString(); + } +} + +abstract class _$FormulasDatabase extends GeneratedDatabase { + _$FormulasDatabase(QueryExecutor e) : super(e); + $FormulasDatabaseManager get managers => $FormulasDatabaseManager(this); + late final $FormulasTable formulas = $FormulasTable(this); + @override + Iterable> get allTables => + allSchemaEntities.whereType>(); + @override + List get allSchemaEntities => [formulas]; +} + +typedef $$FormulasTableCreateCompanionBuilder = + FormulasCompanion Function({Value id, required String formula}); +typedef $$FormulasTableUpdateCompanionBuilder = + FormulasCompanion Function({Value id, Value formula}); + +class $$FormulasTableFilterComposer + extends Composer<_$FormulasDatabase, $FormulasTable> { + $$FormulasTableFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnFilters(column), + ); + + ColumnFilters get formula => $composableBuilder( + column: $table.formula, + builder: (column) => ColumnFilters(column), + ); +} + +class $$FormulasTableOrderingComposer + extends Composer<_$FormulasDatabase, $FormulasTable> { + $$FormulasTableOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get id => $composableBuilder( + column: $table.id, + builder: (column) => ColumnOrderings(column), + ); + + ColumnOrderings get formula => $composableBuilder( + column: $table.formula, + builder: (column) => ColumnOrderings(column), + ); +} + +class $$FormulasTableAnnotationComposer + extends Composer<_$FormulasDatabase, $FormulasTable> { + $$FormulasTableAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get id => + $composableBuilder(column: $table.id, builder: (column) => column); + + GeneratedColumn get formula => + $composableBuilder(column: $table.formula, builder: (column) => column); +} + +class $$FormulasTableTableManager + extends + RootTableManager< + _$FormulasDatabase, + $FormulasTable, + Formula, + $$FormulasTableFilterComposer, + $$FormulasTableOrderingComposer, + $$FormulasTableAnnotationComposer, + $$FormulasTableCreateCompanionBuilder, + $$FormulasTableUpdateCompanionBuilder, + ( + Formula, + BaseReferences<_$FormulasDatabase, $FormulasTable, Formula>, + ), + Formula, + PrefetchHooks Function() + > { + $$FormulasTableTableManager(_$FormulasDatabase db, $FormulasTable table) + : super( + TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $$FormulasTableFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $$FormulasTableOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $$FormulasTableAnnotationComposer($db: db, $table: table), + updateCompanionCallback: + ({ + Value id = const Value.absent(), + Value formula = const Value.absent(), + }) => FormulasCompanion(id: id, formula: formula), + createCompanionCallback: + ({ + Value id = const Value.absent(), + required String formula, + }) => FormulasCompanion.insert(id: id, formula: formula), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + ), + ); +} + +typedef $$FormulasTableProcessedTableManager = + ProcessedTableManager< + _$FormulasDatabase, + $FormulasTable, + Formula, + $$FormulasTableFilterComposer, + $$FormulasTableOrderingComposer, + $$FormulasTableAnnotationComposer, + $$FormulasTableCreateCompanionBuilder, + $$FormulasTableUpdateCompanionBuilder, + (Formula, BaseReferences<_$FormulasDatabase, $FormulasTable, Formula>), + Formula, + PrefetchHooks Function() + >; + +class $FormulasDatabaseManager { + final _$FormulasDatabase _db; + $FormulasDatabaseManager(this._db); + $$FormulasTableTableManager get formulas => + $$FormulasTableTableManager(_db, _db.formulas); +} diff --git a/lib/main.dart b/lib/main.dart index 0f44288..edc1921 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,32 +1,45 @@ import 'package:flutter/material.dart'; - +import 'database/database_service.dart'; import 'ai/formula_list.dart'; import 'corpus.dart'; import 'defaults/default_corpus.dart'; -void main() { +void main() async { WidgetsFlutterBinding.ensureInitialized(); - runApp(MaterialApp( - home: FutureBuilder( - future: createDefaultCorpus(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasError) { - return Center(child: Text('Error loading units: ${snapshot.error}')); + + // Setup service locator and initialize the database + setupLocator(); + + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: FutureBuilder( + future: createDefaultCorpus(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return Center(child: Text('Error loading units: ${snapshot.error}')); + } + return Scaffold( + appBar: AppBar(title: const Text('Formulas')), + body: FormulaList( + corpus: snapshot.data!, + formulas: snapshot.data!.getFormulas(), + ), + ); } - return Scaffold( - appBar: AppBar(title: const Text('Formulas')), - body: FormulaList( - corpus: snapshot.data!, - formulas: snapshot.data!.getFormulas(), - ), - ); - } - return const Center(child: CircularProgressIndicator()); - }, - ), - )); + return const Center(child: CircularProgressIndicator()); + }, + ), + ); + } } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index f6f23bf..4c0025f 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); + sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f16b4c3..ad279a8 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + sqlite3_flutter_libs url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 8236f57..eeb37f4 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,10 @@ import FlutterMacOS import Foundation +import sqlite3_flutter_libs import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 82ade9b..b18c678 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,6 +49,70 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: ce76b1d48875e3233fde17717c23d1f60a91cc631597e49a400c89b475395b1d + url: "https://pub.dev" + source: hosted + version: "3.1.0" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 + url: "https://pub.dev" + source: hosted + version: "4.1.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: d1d57f7807debd7349b4726a19fd32ec8bc177c71ad0febf91a20f84cd2d4b46 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: b24597fceb695969d47025c958f3837f9f0122e237c6a22cb082a5ac66c3ca30 + url: "https://pub.dev" + source: hosted + version: "2.7.1" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "066dda7f73d8eb48ba630a55acb50c4a84a2e6b453b1cb4567f581729e794f7b" + url: "https://pub.dev" + source: hosted + version: "9.3.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "7931c90b84bc573fef103548e354258ae4c9d28d140e41961df6843c5d60d4d8" + url: "https://pub.dev" + source: hosted + version: "8.12.3" characters: dependency: transitive description: @@ -65,6 +129,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" cli_config: dependency: transitive description: @@ -73,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c + url: "https://pub.dev" + source: hosted + version: "0.4.2" clock: dependency: transitive description: @@ -81,6 +161,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + url: "https://pub.dev" + source: hosted + version: "4.11.1" collection: dependency: "direct main" description: @@ -129,6 +225,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.9" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + drift: + dependency: "direct main" + description: + name: drift + sha256: "83290a32ae006a7535c5ecf300722cb77177250d9df4ee2becc5fa8a36095114" + url: "https://pub.dev" + source: hosted + version: "2.29.0" + drift_dev: + dependency: "direct dev" + description: + name: drift_dev + sha256: "6019f827544e77524ffd5134ae0cb75dfd92ef5ef3e269872af92840c929cd43" + url: "https://pub.dev" + source: hosted + version: "2.29.0" equatable: dependency: transitive description: @@ -145,6 +265,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c + url: "https://pub.dev" + source: hosted + version: "2.1.5" file: dependency: transitive description: @@ -153,6 +281,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -240,6 +376,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: ae78de7c3f2304b8d81f2bb6e320833e5e81de942188542328f074978cc0efa9 + url: "https://pub.dev" + source: hosted + version: "8.3.0" glob: dependency: transitive description: @@ -248,6 +392,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" highlight: dependency: transitive description: @@ -264,6 +416,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" http: dependency: transitive description: @@ -304,6 +464,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "805fa86df56383000f640384b282ce0cb8431f1a7a2396de92fb66186d8c57df" + url: "https://pub.dev" + source: hosted + version: "4.10.0" leak_tracker: dependency: transitive description: @@ -400,6 +568,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" + url: "https://pub.dev" + source: hosted + version: "0.17.4" nested: dependency: transitive description: @@ -416,6 +592,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" package_config: dependency: transitive description: @@ -425,7 +609,7 @@ packages: source: hosted version: "2.2.0" path: - dependency: transitive + dependency: "direct main" description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" @@ -440,6 +624,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e + url: "https://pub.dev" + source: hosted + version: "2.2.22" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + url: "https://pub.dev" + source: hosted + version: "2.6.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" petitparser: dependency: transitive description: @@ -448,6 +680,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -480,6 +720,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" resource_portable: dependency: "direct main" description: @@ -533,6 +789,14 @@ packages: description: flutter source: sdk version: "0.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "800f12fb87434defa13432ab37e33051b43b290a174e15259563b043cda40c46" + url: "https://pub.dev" + source: hosted + version: "4.0.0" source_map_stack_trace: dependency: transitive description: @@ -557,6 +821,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.1" + sqlite3: + dependency: transitive + description: + name: sqlite3 + sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" + url: "https://pub.dev" + source: hosted + version: "2.9.4" + sqlite3_flutter_libs: + dependency: "direct main" + description: + name: sqlite3_flutter_libs + sha256: "1e800ebe7f85a80a66adacaa6febe4d5f4d8b75f244e9838a27cb2ffc7aec08d" + url: "https://pub.dev" + source: hosted + version: "0.5.41" + sqlparser: + dependency: transitive + description: + name: sqlparser + sha256: "162435ede92bcc793ea939fdc0452eef0a73d11f8ed053b58a89792fba749da5" + url: "https://pub.dev" + source: hosted + version: "0.42.1" stack_trace: dependency: transitive description: @@ -573,6 +861,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" string_scanner: dependency: transitive description: @@ -613,6 +909,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.12" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" tuple: dependency: transitive description: @@ -773,6 +1077,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" xml: dependency: transitive description: @@ -791,4 +1103,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.10.4 <4.0.0" - flutter: ">=3.38.0" + flutter: ">=3.38.4" diff --git a/pubspec.yaml b/pubspec.yaml index 530b4ea..6bf20be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: + cupertino_icons: resource_portable: d4rt: flutter_d4rt: @@ -41,6 +41,13 @@ dependencies: flutter_markdown_latex: flutter_code_editor: + # Drift dependencies for database support + drift: ^2.18.0 + sqlite3_flutter_libs: ^0.5.9 + path_provider: ^2.1.1 + path: ^1.8.3 + get_it: ^8.0.2 + collection: any dev_dependencies: flutter_test: @@ -54,6 +61,10 @@ dev_dependencies: flutter_lints: test: + # Drift build dependencies + drift_dev: ^2.18.0 + build_runner: ^2.4.7 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/database_test.dart b/test/database_test.dart new file mode 100644 index 0000000..583272d --- /dev/null +++ b/test/database_test.dart @@ -0,0 +1,13 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:d4rt_formulas/database/database_service.dart'; + +void main() { + setUp(() { + setupLocator(); + }); + + test('Database service can be initialized', () { + final database = getDatabase(); + expect(database, isNotNull); + }); +} \ No newline at end of file diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 4f78848..76d5285 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,12 @@ #include "generated_plugin_registrant.h" +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + Sqlite3FlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 88b22e5..22aeaae 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + sqlite3_flutter_libs url_launcher_windows )