Replace database import with CSV import

This commit is contained in:
Brandon Presley 2023-11-29 16:57:19 +13:00
parent 36b8ce37ad
commit 98991a3d02
5 changed files with 104 additions and 61 deletions

View File

@ -17,7 +17,7 @@ class MyDatabase extends _$MyDatabase {
MyDatabase() : super(_openConnection()); MyDatabase() : super(_openConnection());
@override @override
int get schemaVersion => 3; int get schemaVersion => 1;
@override @override
MigrationStrategy get migration => MigrationStrategy( MigrationStrategy get migration => MigrationStrategy(
@ -27,41 +27,7 @@ class MyDatabase extends _$MyDatabase {
var data = await (db.select(db.settings)..limit(1)).get(); var data = await (db.select(db.settings)..limit(1)).get();
if (data.isEmpty) await db.into(db.settings).insert(defaultSettings); if (data.isEmpty) await db.into(db.settings).insert(defaultSettings);
}, },
onUpgrade: (Migrator m, int from, int to) async { onUpgrade: (Migrator m, int from, int to) async {},
if (from == 1) {
await m.create(db.gymSets);
await db.customInsert('''
INSERT INTO gym_sets(id, name, reps, weight, created, unit, hidden, image, sets, minutes, seconds, steps)
SELECT id, name, reps, weight, created, unit, hidden, image, sets, minutes, seconds, steps FROM sets
''');
await m.addColumn(settings, settings.darkColor);
await db.customStatement('''
UPDATE settings SET dark_color = darkColor
''');
await m.addColumn(settings, settings.lightColor);
await db.customStatement('''
UPDATE settings SET light_color = lightColor
''');
await m.addColumn(settings, settings.showDate);
await db.customStatement('''
UPDATE settings SET show_date = showDate
''');
await m.addColumn(settings, settings.showSets);
await db.customStatement('''
UPDATE settings SET show_sets = showSets
''');
await m.addColumn(settings, settings.showUnit);
await db.customStatement('''
UPDATE settings SET show_unit = showUnit
''');
}
if (from == 2) {
await m.addColumn(settings, settings.noSound);
await db.customStatement('''
UPDATE settings SET no_sound = noSound
''');
}
},
); );
} }

51
lib/delete_all_sets.dart Normal file
View File

@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
import 'package:fmassive/main.dart';
import 'package:moor/moor.dart';
class DeleteAllSets extends StatelessWidget {
const DeleteAllSets({
super.key,
required this.mounted,
});
final bool mounted;
@override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
child: const Text("Delete all sets"),
onPressed: () async {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("Delete all sets"),
content: const Text(
"This will irreversibly destroy all your gym set data. Are you sure?"),
actions: <Widget>[
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
ElevatedButton(
child: const Text('Delete'),
onPressed: () async {
await db.gymSets.delete().go();
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Deleted all sets')));
final navigator = Navigator.of(context);
navigator.pop();
},
),
],
);
});
},
),
);
}
}

View File

@ -1,14 +1,15 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:csv/csv.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as material; import 'package:flutter/material.dart' as material;
import 'package:fmassive/database.dart'; import 'package:fmassive/database.dart';
import 'package:fmassive/delete_all_sets.dart';
import 'package:fmassive/main.dart'; import 'package:fmassive/main.dart';
import 'package:fmassive/sound_picker.dart'; import 'package:fmassive/sound_picker.dart';
import 'package:moor/moor.dart'; import 'package:moor/moor.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
class SettingsPage extends StatelessWidget { class SettingsPage extends StatelessWidget {
const SettingsPage({super.key, required this.search}); const SettingsPage({super.key, required this.search});
@ -63,7 +64,8 @@ class _SettingsPageState extends State<_SettingsPage> {
{'title': 'Show Unit', 'value': settings.showUnit}, {'title': 'Show Unit', 'value': settings.showUnit},
{'title': 'Steps', 'value': settings.steps}, {'title': 'Steps', 'value': settings.steps},
{'title': 'Sound', 'value': settings.sound}, {'title': 'Sound', 'value': settings.sound},
{'title': 'Import', 'value': settings.sound}, {'title': 'Import', 'value': null},
{'title': 'Delete all sets', 'value': null},
] ]
.where((item) => (item['title'] as String) .where((item) => (item['title'] as String)
.toLowerCase() .toLowerCase()
@ -78,32 +80,47 @@ class _SettingsPageState extends State<_SettingsPage> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = filteredItems[index]; final item = filteredItems[index];
if (item['title'] == 'Delete all sets')
return DeleteAllSets(mounted: mounted);
if (item['title'] == 'Import') if (item['title'] == 'Import')
return Center( return Center(
child: ElevatedButton( child: ElevatedButton(
child: const Text("Import"),
onPressed: () async { onPressed: () async {
final result = final result = await FilePicker.platform.pickFiles(
await FilePicker.platform.pickFiles( type: FileType.custom,
type: FileType.any, allowedExtensions: ['csv']);
);
if (result == null) return; if (result == null) return;
final file = File(result.files.single.path!); final file = File(result.files.single.path!);
final path = await getDatabasesPath(); final input = file.openRead();
final to = join(path, 'massive.db'); final fields = await input
await db.close(); .transform(utf8.decoder)
await file.copy(to); .transform(const CsvToListConverter(eol: "\n"))
print('Migrating...'); .skip(1)
db = MyDatabase(); .toList();
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member final gymSets = fields.map((row) => GymSetsCompanion(
final migrator = db.createMigrator(); id: Value(int.tryParse(row[0]) ?? 0),
await migrator.createAll(); name: Value(row[1]),
await db.update(db.settings).write( reps: Value(int.tryParse(row[2]) ?? 0),
const SettingsCompanion( weight: Value(double.tryParse(row[3]) ?? 0),
sound: Value(null))); created: Value(row[4]),
print('Migrated.'); unit: Value(row[5]),
hidden: Value(row[6] == 'true'),
image: Value(row[7]),
sets: Value(int.tryParse(row[8]) ?? 0),
minutes: Value(int.tryParse(row[9]) ?? 0),
seconds: Value(int.tryParse(row[10]) ?? 0),
steps: Value(row[11]),
));
await db.batch(
(batch) => batch.insertAll(db.gymSets, gymSets));
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Imported data')));
}, },
child: const Text("Import"))); ));
if (item['title'] == 'Sound') { if (item['title'] == 'Sound') {
return Center( return Center(

View File

@ -241,6 +241,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.3"
csv:
dependency: "direct main"
description:
name: csv
sha256: "63ed2871dd6471193dffc52c0e6c76fb86269c00244d244297abbb355c84a86e"
url: "https://pub.dev"
source: hosted
version: "5.1.1"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -47,6 +47,7 @@ dependencies:
intl: ^0.18.0 intl: ^0.18.0
permission_handler: ^11.0.1 permission_handler: ^11.0.1
infinite_scroll_pagination: ^4.0.0 infinite_scroll_pagination: ^4.0.0
csv: ^5.1.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: