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());
@override
int get schemaVersion => 3;
int get schemaVersion => 1;
@override
MigrationStrategy get migration => MigrationStrategy(
@ -27,41 +27,7 @@ class MyDatabase extends _$MyDatabase {
var data = await (db.select(db.settings)..limit(1)).get();
if (data.isEmpty) await db.into(db.settings).insert(defaultSettings);
},
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
''');
}
},
onUpgrade: (Migrator m, int from, int to) async {},
);
}

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

View File

@ -241,6 +241,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: "direct main"
description:

View File

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