Commit 1d36290

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-07-02 08:18:33
Remove foreign db import (#338)
* remove foreign db import --------- Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 3b21ec6
Changed files (4)
app/lib/features/settings/foreign_db_import_screen.dart
@@ -1,189 +0,0 @@
-import 'dart:convert';
-
-import 'package:blood_pressure_app/components/tree_selection_dialoge.dart';
-import 'package:blood_pressure_app/data_util/consistent_future_builder.dart';
-import 'package:blood_pressure_app/model/blood_pressure/needle_pin.dart';
-import 'package:blood_pressure_app/model/export_import/import_field_type.dart';
-import 'package:blood_pressure_app/model/storage/convert_util.dart';
-import 'package:blood_pressure_app/model/storage/settings_store.dart';
-import 'package:collection/collection.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:health_data_store/health_data_store.dart';
-import 'package:provider/provider.dart';
-import 'package:sqflite/sqflite.dart';
-import 'package:sqlparser/sqlparser.dart';
-
-/// Screen to select the columns from a database and annotate types.
-///
-/// Parses data table to [BloodPressureRecord] list.
-class ForeignDBImportScreen extends StatefulWidget {
-  /// Create a screen to import data from a database with unknown structure.
-  /// 
-  /// Parses selected data to a [BloodPressureRecord] list.
-  const ForeignDBImportScreen({super.key,
-    required this.db,
-    required this.bottomAppBars,
-  });
-
-  /// Database from which to import data.
-  final Database db;
-
-  /// Whether to move the app bar for saving and loading to the bottom of the
-  /// screen.
-  final bool bottomAppBars;
-
-  @override
-  State<ForeignDBImportScreen> createState() => _ForeignDBImportScreenState();
-}
-
-class _ForeignDBImportScreenState extends State<ForeignDBImportScreen> {
-  @override
-  Widget build(BuildContext context) => ConsistentFutureBuilder(
-    future: _ColumnImportData.loadFromDB(widget.db),
-    onData: (BuildContext context, _ColumnImportData data) {
-      final localizations = AppLocalizations.of(context)!;
-      return TreeSelectionDialoge(
-        buildOptions: (selections) {
-          if (selections.isEmpty) {
-            return data.tableNames.toList();
-          }
-          if (selections.length == 1) {
-            return data.columns[selections[0]]!;
-          }
-
-          if ((selections.length % 2 == 0)) {
-            final columns = data.columns[selections[0]]!;
-            return columns.whereNot((e) => selections.contains(e)).toList();
-          } else {
-            return RowDataFieldType.values
-                .whereNot((e) => e == RowDataFieldType.timestamp
-                || selections.contains(e),)
-                .map((e) => e.localize(localizations))
-                .toList();
-          }
-        },
-        validator: (List<String> elements) {
-          const kMetaColumns = 2;
-          if (elements.isEmpty) return 'No table selected';
-          if (elements.length < kMetaColumns) return 'No time column selected';
-          if (elements.length % 2 != kMetaColumns % 2) {
-            return 'Select a data column or return to last screen';
-          }
-          if (elements.length < 4) return 'Select at least one data column';
-
-          // return 'The schnibledumps doesn\'t schwibble!'; // TODO check if more tests are required
-          return null;
-        },
-        onSaved: (List<String> madeSelections) async {
-          final tableName = madeSelections.removeAt(0);
-          final timeColumn = madeSelections.removeAt(0);
-          final dataColumns = <(String, RowDataFieldType)>[];
-          while (madeSelections.isNotEmpty) {
-            final column = madeSelections.removeAt(0);
-            final typeStr = madeSelections.removeAt(0);
-            final type = RowDataFieldType.values
-                .firstWhere((t) => t.localize(localizations) == typeStr);
-            dataColumns.add((column, type));
-          }
-
-          final data = await widget.db.query(tableName);
-          final entries = <FullEntry>[];
-          for (final row in data) {
-            assert(row.containsKey(timeColumn)
-                && madeSelections.every(row.containsKey),);
-            final timestamp = ConvertUtil.parseTime(row[timeColumn]);
-            if (timestamp == null) throw FormatException('Unable to parse time: ${row[timeColumn]}'); // TODO: error handling
-            FullEntry entry = (BloodPressureRecord(time: timestamp), Note(time: timestamp), []);
-            final settings = context.read<Settings>();
-            for (final colType in dataColumns) {
-              switch (colType.$2) {
-                case RowDataFieldType.timestamp:
-                  assert(false, 'Not up for selection');
-                case RowDataFieldType.sys:
-                  final val = ConvertUtil.parseInt(row[colType.$1]);
-                  entry = (entry.$1.copyWith(sys: (val == null) ? null : settings.preferredPressureUnit.wrap(val),), entry.$2, entry.$3);
-                case RowDataFieldType.dia:
-                  final val = ConvertUtil.parseInt(row[colType.$1]);
-                  entry = (entry.$1.copyWith(dia: (val == null) ? null : settings.preferredPressureUnit.wrap(val),), entry.$2, entry.$3);
-                case RowDataFieldType.pul:
-                  entry = (entry.$1.copyWith(pul: ConvertUtil.parseInt(row[colType.$1]),), entry.$2, entry.$3);
-                case RowDataFieldType.notes:
-                  final note = ConvertUtil.parseString(row[colType.$1]);
-                  entry = (entry.$1, entry.$2.copyWith(note: note), entry.$3);
-                case RowDataFieldType.color:
-                  try {
-                    final json = jsonDecode(row[colType.$1].toString());
-                    if (json is! Map<String, dynamic>) continue;
-                    final pin = MeasurementNeedlePin.fromMap(json);
-                    entry = (entry.$1, entry.$2.copyWith(color: pin.color.value), entry.$3);
-                  } on FormatException {
-                    // Not parsable: silently ignore for now
-                  }
-              }
-            }
-            entries.add(entry);
-          }
-          if (context.mounted) Navigator.pop(context, entries);
-        },
-        buildTitle: (List<String> selections) {
-          if (selections.isEmpty) return 'Select table';
-          if (selections.length == 1) return 'Select time column';
-          if ((selections.length % 2 == 0)) {
-            return 'Select data column';
-          } else {
-            return 'Select column type (${selections.last})';
-          }
-        },
-        bottomAppBars: widget.bottomAppBars, // TODO
-      );
-      // TODO: localize everything
-      // TODO: detect when no more selections are possible
-    },
-  );
-}
-
-class _ColumnImportData {
-  _ColumnImportData._create(this.columns);
-
-  static Future<_ColumnImportData> loadFromDB(Database db) async {
-    final engine = SqlEngine();
-
-    final masterTable = await db.query('sqlite_master',
-      columns: ['sql'],
-      where: 'type = "table"',
-    );
-    final columns = <String, List<String>?>{};
-    for (final e in masterTable) {
-      final creationSql = e['sql']!.toString();
-      final rootNode = engine.analyze(creationSql).root;
-      if (rootNode is CreateTableStatement) {
-        final colNames = rootNode.columns
-            .map((e) => e.columnName)
-            .toSet()
-            .toList();
-
-        if (colNames.isNotEmpty) columns[rootNode.tableName] = colNames;
-      }
-    }
-    return _ColumnImportData._create(columns);
-  }
-
-  /// Map of table names and their respective column names.
-  Map<String, List<String>?> columns;
-
-  /// Names of all tables.
-  Iterable<String> get tableNames => columns.keys;
-}
-
-/// Shows a dialoge to import arbitrary data from a external database.
-Future<List<FullEntry>?> showForeignDBImportDialoge(
-    BuildContext context,
-    bool bottomAppBars,
-    Database db,) =>
-    showDialog<List<FullEntry>>(
-      context: context, builder: (context) => ForeignDBImportScreen(
-        bottomAppBars: bottomAppBars,
-        db: db,
-      ),
-    );
app/lib/screens/settings_screen.dart
@@ -6,7 +6,6 @@ import 'package:blood_pressure_app/data_util/consistent_future_builder.dart';
 import 'package:blood_pressure_app/features/settings/delete_data_screen.dart';
 import 'package:blood_pressure_app/features/settings/enter_timeformat_dialoge.dart';
 import 'package:blood_pressure_app/features/settings/export_import_screen.dart';
-import 'package:blood_pressure_app/features/settings/foreign_db_import_screen.dart';
 import 'package:blood_pressure_app/features/settings/graph_markings_screen.dart';
 import 'package:blood_pressure_app/features/settings/medicine_manager_screen.dart';
 import 'package:blood_pressure_app/features/settings/tiles/color_picker_list_tile.dart';
@@ -23,9 +22,7 @@ import 'package:blood_pressure_app/model/storage/storage.dart';
 import 'package:blood_pressure_app/platform_integration/platform_client.dart';
 import 'package:file_picker/file_picker.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:health_data_store/health_data_store.dart';
 import 'package:package_info_plus/package_info_plus.dart';
 import 'package:path/path.dart';
 import 'package:provider/provider.dart';
@@ -347,56 +344,6 @@ class SettingsPage extends StatelessWidget {
                     );
                   },
                 ),
-                ListTile(
-                  title: Text('Import foreign database (Preview)'), // TODO
-                  subtitle: Text('Unstable feature: Use at your own risk. Please'
-                      ' open issues and give feedback in form of issues on this '
-                      'projects GitHub page (accessible through the source code button).'),
-                  leading: Icon(Icons.add_circle, color: Colors.orange,),
-                  onTap: () async {
-                    final messenger = ScaffoldMessenger.of(context);
-                    final result = await FilePicker.platform.pickFiles();
-
-                    if (result == null) {
-                      messenger.showSnackBar(SnackBar(content: Text(localizations.errNoFileOpened)));
-                      return;
-                    }
-                    final path = result.files.single.path;
-                    if (path == null) {
-                      messenger.showSnackBar(SnackBar(content: Text(localizations.errCantReadFile)));
-                      return;
-                    } // TODO: stop duplicating file selection code
-
-                    final db = await openDatabase(path);
-
-                    if (!context.mounted) return;
-                    final data = await showForeignDBImportDialoge(context,
-                        settings.bottomAppBars, db,);
-
-                    if (!context.mounted) return;
-                    if (data == null) {
-                      messenger.showSnackBar(SnackBar(content: Text(localizations.errNotImportable)));
-                      return;
-                    }
-
-                    final bpRepo = RepositoryProvider.of<BloodPressureRepository>(context);
-                    final noteRepo = RepositoryProvider.of<NoteRepository>(context);
-                    await Future.forEach(data, (e) async {
-                      if (e.sys != null || e.dia != null || e.pul != null) {
-                        await bpRepo.add(e.$1);
-                      }
-                      if (e.note != null || e.color != null) {
-                        await noteRepo.add(e.$2);
-                      }
-                      assert(e.$3.isEmpty);
-                    });
-
-                    // TODO: Show import preview
-
-                    messenger.showSnackBar(SnackBar(content: Text(
-                      localizations.importSuccess(data.length),),),);
-                  },
-                ),
               ],
             ),
             TitledColumn(title: Text(localizations.aboutWarnValuesScreen), children: [
app/pubspec.lock
@@ -166,14 +166,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.3.0"
-  charcode:
-    dependency: transitive
-    description:
-      name: charcode
-      sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.3.1"
   checked_yaml:
     dependency: transitive
     description:
@@ -941,14 +933,6 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.4.4"
-  sqlparser:
-    dependency: "direct main"
-    description:
-      name: sqlparser
-      sha256: ade9a67fd70d0369329ed3373208de7ebd8662470e8c396fc8d0d60f9acdfc9f
-      url: "https://pub.dev"
-    source: hosted
-    version: "0.36.0"
   stack_trace:
     dependency: transitive
     description:
app/pubspec.yaml
@@ -29,7 +29,6 @@ dependencies:
   url_launcher: ^6.1.11
   health_data_store:
     path: ../health_data_store/
-  sqlparser: ^0.36.0
   flutter_bloc: ^8.1.4
   flutter_blue_plus: ^1.32.4