Compare commits

...

4 Commits

Author SHA1 Message Date
0a7675797b Add basic database import button
Still need to make sure we move across sets -> gym_sets
since moor won't let me use sets as a table name.

Moor doesnt like me having a class called sets with a property
called sets.
2023-04-17 11:51:35 +12:00
8bda4d593d Remove try catch from set_list pagination
All this does is obscure errors. I want it
to break when things go wrong and show me
why in the logs.
2023-04-17 11:50:31 +12:00
f11ade393a Rename inner class for HomePage 2023-04-17 11:03:36 +12:00
59c9c539d2 Add pagination to home page 2023-04-17 11:03:27 +12:00
6 changed files with 114 additions and 52 deletions

View File

@ -23,7 +23,7 @@ class MyDatabase extends _$MyDatabase {
MigrationStrategy get migration => MigrationStrategy( MigrationStrategy get migration => MigrationStrategy(
onCreate: (Migrator m) async { onCreate: (Migrator m) async {
await m.createAll(); await m.createAll();
var data = await db.select(db.settings).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 {

View File

@ -1,19 +1,19 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fmassive/best_page.dart'; import 'package:fmassive/best_page.dart';
import 'package:fmassive/plans_page.dart'; import 'package:fmassive/plans_page.dart';
import 'package:fmassive/set_list.dart';
import 'package:fmassive/settings_page.dart'; import 'package:fmassive/settings_page.dart';
import 'package:fmassive/timer_page.dart'; import 'package:fmassive/timer_page.dart';
import 'package:fmassive/workouts_page.dart'; import 'package:fmassive/workouts_page.dart';
import 'package:fmassive/set_list.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({super.key}); const HomePage({super.key});
@override @override
createState() => RootPage(); createState() => _HomePage();
} }
class RootPage extends State<HomePage> { class _HomePage extends State<HomePage> {
bool showSearch = false; bool showSearch = false;
int selected = 0; int selected = 0;
String search = ''; String search = '';

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:fmassive/database.dart'; import 'package:fmassive/database.dart';
import 'package:fmassive/edit_set.dart'; import 'package:fmassive/edit_set.dart';
import 'package:fmassive/main.dart'; import 'package:fmassive/main.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:moor_flutter/moor_flutter.dart'; import 'package:moor_flutter/moor_flutter.dart';
@ -16,25 +17,37 @@ class SetList extends StatefulWidget {
class _SetList extends State<SetList> { class _SetList extends State<SetList> {
bool showSearch = false; bool showSearch = false;
late Stream<List<GymSet>> stream; final PagingController<int, GymSet> pagingController =
PagingController(firstPageKey: 0);
@override @override
initState() { initState() {
super.initState(); super.initState();
setStream(); pagingController.addPageRequestListener((pageKey) {
} fetch(pageKey);
});
void setStream() {
stream = (db.select(db.gymSets)
..where((gymSet) => gymSet.name.contains(widget.search))
..limit(10, offset: 0))
.watch();
} }
@override @override
didUpdateWidget(covariant SetList oldWidget) { didUpdateWidget(covariant SetList oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
setStream(); pagingController.refresh();
}
Future<void> fetch(int pageKey) async {
final gymSets = await (db.select(db.gymSets)
..where((gymSet) => gymSet.name.contains(widget.search))
..limit(10, offset: pageKey * 10))
.get();
final isLastPage = gymSets.length < 10;
if (isLastPage) {
pagingController.appendLastPage(gymSets);
} else {
final nextPageKey = pageKey + 1;
pagingController.appendPage(gymSets, nextPageKey);
}
} }
void toggleSearch() { void toggleSearch() {
@ -46,50 +59,53 @@ class _SetList extends State<SetList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: StreamBuilder<List<GymSet>>( body: PagedListView<int, GymSet>(
stream: stream, pagingController: pagingController,
builder: (context, snapshot) { builderDelegate: PagedChildBuilderDelegate<GymSet>(
final gymSets = snapshot.data; itemBuilder: (context, gymSet, index) => ListTile(
title: Text(gymSet.name),
if (gymSets == null) subtitle: Text("${gymSet.reps} x ${gymSet.weight}kg"),
return const Center(child: CircularProgressIndicator()); trailing: Text(
DateFormat("yyyy-MM-dd").format(DateTime.parse(gymSet.created)),
return ListView.builder( ),
itemCount: gymSets.length, onTap: () async {
itemBuilder: (context, index) {
return ListTile(
title: Text(gymSets[index].name),
subtitle: Text(
"${gymSets[index].reps} x ${gymSets[index].weight}kg"),
trailing: Text(DateFormat("yyyy-MM-dd")
.format(DateTime.parse(gymSets[index].created))),
onTap: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditGymSetPage(
gymSet: gymSets[index].toCompanion(false)),
),
);
});
},
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push( await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => EditGymSetPage( builder: (context) => EditGymSetPage(
gymSet: GymSetsCompanion( gymSet: gymSet.toCompanion(false),
name: const Value(''), ),
reps: const Value(0),
weight: const Value(0),
image: const Value(''),
created: Value(DateTime.now().toString()))),
), ),
); );
pagingController.refresh();
}, },
child: const Icon(Icons.add))); ),
firstPageProgressIndicatorBuilder: (_) =>
const Center(child: CircularProgressIndicator()),
newPageProgressIndicatorBuilder: (_) =>
const Center(child: CircularProgressIndicator()),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditGymSetPage(
gymSet: GymSetsCompanion(
name: const Value(''),
reps: const Value(0),
weight: const Value(0),
image: const Value(''),
created: Value(DateTime.now().toString()),
),
),
),
);
pagingController.refresh();
},
child: const Icon(Icons.add),
),
);
} }
} }

View File

@ -1,9 +1,14 @@
import 'dart:io';
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/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});
@ -57,6 +62,7 @@ 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},
] ]
.where((item) => (item['title'] as String) .where((item) => (item['title'] as String)
.toLowerCase() .toLowerCase()
@ -71,6 +77,29 @@ class _SettingsPageState extends State<_SettingsPage> {
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = filteredItems[index]; final item = filteredItems[index];
if (item['title'] == 'Import')
return Center(
child: ElevatedButton(
onPressed: () async {
final result =
await FilePicker.platform.pickFiles(
type: FileType.any,
);
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();
final migrator = db.createMigrator();
await migrator.createAll();
print('Migrated.');
},
child: const Text("Import")));
if (item['title'] == 'Sound') { if (item['title'] == 'Sound') {
return Center( return Center(
child: SoundPicker( child: SoundPicker(

View File

@ -392,6 +392,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.2"
infinite_scroll_pagination:
dependency: "direct main"
description:
name: infinite_scroll_pagination
sha256: "9517328f4e373f08f57dbb11c5aac5b05554142024d6b60c903f3b73476d52db"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -677,6 +685,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.99"
sliver_tools:
dependency: transitive
description:
name: sliver_tools
sha256: ccdc502098a8bfa07b3ec582c282620031481300035584e1bb3aca296a505e8c
url: "https://pub.dev"
source: hosted
version: "0.2.10"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:

View File

@ -46,6 +46,7 @@ dependencies:
audioplayers: ^4.0.1 audioplayers: ^4.0.1
intl: ^0.18.0 intl: ^0.18.0
permission_handler: ^10.2.0 permission_handler: ^10.2.0
infinite_scroll_pagination: ^3.2.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: