From c1369154a860afa9dd343e273fe5bc05db66ba94 Mon Sep 17 00:00:00 2001 From: a-mabe Date: Tue, 1 Oct 2024 20:01:52 -0400 Subject: [PATCH 1/2] Optimize database manager, use provider to add/delete workouts --- lib/models/workout_type.dart | 72 ++++ lib/pages/home/home.dart | 9 +- lib/pages/import_workout/import_workout.dart | 16 +- .../constants/sounds.dart | 0 .../set_sounds.dart | 49 +-- .../widgets/sound_dropdown.dart | 0 .../constants/set_timings_constants.dart | 0 .../set_timings.dart | 2 +- .../utils/set_timings_utils.dart | 0 .../expansion_additional_config_tile.dart | 0 .../widgets/time_input_trailing.dart | 0 .../widgets/time_list_item.dart | 0 lib/pages/view_workout/view_workout.dart | 39 +-- lib/providers/workout_provider.dart | 21 +- lib/utils/database/database_manager.dart | 317 +++++++----------- 15 files changed, 231 insertions(+), 294 deletions(-) rename lib/pages/{set_sounds.dart => set_sounds}/constants/sounds.dart (100%) rename lib/pages/{set_sounds.dart => set_sounds}/set_sounds.dart (84%) rename lib/pages/{set_sounds.dart => set_sounds}/widgets/sound_dropdown.dart (100%) rename lib/pages/{set_timings.dart => set_timings}/constants/set_timings_constants.dart (100%) rename lib/pages/{set_timings.dart => set_timings}/set_timings.dart (99%) rename lib/pages/{set_timings.dart => set_timings}/utils/set_timings_utils.dart (100%) rename lib/pages/{set_timings.dart => set_timings}/widgets/expansion_additional_config_tile.dart (100%) rename lib/pages/{set_timings.dart => set_timings}/widgets/time_input_trailing.dart (100%) rename lib/pages/{set_timings.dart => set_timings}/widgets/time_list_item.dart (100%) diff --git a/lib/models/workout_type.dart b/lib/models/workout_type.dart index 2dc769f..5b56a13 100644 --- a/lib/models/workout_type.dart +++ b/lib/models/workout_type.dart @@ -198,6 +198,30 @@ class Workout { }; } + Workout.fromMap(Map map) { + id = map['id']; + title = map['title']; + numExercises = map['numExercises']; + exercises = map['exercises']; + getReadyTime = map['getReadyTime']; + workTime = map['exerciseTime']; + restTime = map['restTime']; + halfTime = map['halfTime']; + breakTime = map['breakTime']; + warmupTime = map['warmupTime']; + cooldownTime = map['cooldownTime']; + iterations = map['iterations']; + halfwayMark = map['halfwayMark']; + workSound = map['workSound']; + restSound = map['restSound']; + halfwaySound = map['halfwaySound']; + completeSound = map['completeSound']; + countdownSound = map['countdownSound']; + colorInt = map['colorInt']; + workoutIndex = map['workoutIndex']; + showMinutes = map['showMinutes']; + } + Map toJson() { return { 'id': id, @@ -274,6 +298,54 @@ class Workout { ); } + Workout copyWith({ + String? id, + String? title, + int? numExercises, + String? exercises, + int? getReadyTime, + int? workTime, + int? restTime, + int? halfTime, + int? breakTime, + int? warmupTime, + int? cooldownTime, + int? iterations, + int? halfwayMark, + String? workSound, + String? restSound, + String? halfwaySound, + String? completeSound, + String? countdownSound, + int? colorInt, + int? workoutIndex, + int? showMinutes, + }) { + return Workout( + id ?? this.id, + title ?? this.title, + numExercises ?? this.numExercises, + exercises ?? this.exercises, + getReadyTime ?? this.getReadyTime, + workTime ?? this.workTime, + restTime ?? this.restTime, + halfTime ?? this.halfTime, + breakTime ?? this.breakTime, + warmupTime ?? this.warmupTime, + cooldownTime ?? this.cooldownTime, + iterations ?? this.iterations, + halfwayMark ?? this.halfwayMark, + workSound ?? this.workSound, + restSound ?? this.restSound, + halfwaySound ?? this.halfwaySound, + completeSound ?? this.completeSound, + countdownSound ?? this.countdownSound, + colorInt ?? this.colorInt, + workoutIndex ?? this.workoutIndex, + showMinutes ?? this.showMinutes, + ); + } + /// Implement toString to print information about /// each Workout more easily. /// diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 3194596..9461b61 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -15,7 +15,6 @@ import 'package:openhiit/widgets/home/timer_list_tile.dart'; import 'package:openhiit/widgets/loader.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; -import 'package:sqflite/sqflite.dart'; import 'package:url_launcher/url_launcher.dart'; // Global flag to indicate if exporting is in progress @@ -77,13 +76,7 @@ class _MyHomePageState extends State { } }); - // Initialize the database and update the workout order in the database. - Database database = await DatabaseManager().initDB(); - - for (var i = 0; i < reorderableWorkoutList.length; i++) { - // Update the workout order in the database. - await DatabaseManager().updateList(reorderableWorkoutList[i], database); - } + DatabaseManager().updateWorkouts(reorderableWorkoutList); } // --- diff --git a/lib/pages/import_workout/import_workout.dart b/lib/pages/import_workout/import_workout.dart index 6f314a3..62cbcd7 100644 --- a/lib/pages/import_workout/import_workout.dart +++ b/lib/pages/import_workout/import_workout.dart @@ -7,7 +7,6 @@ import 'package:openhiit/pages/home/home.dart'; import 'package:openhiit/utils/database/database_manager.dart'; import 'package:openhiit/pages/import_workout/widgets/file_error.dart'; import 'package:openhiit/widgets/loader.dart'; -import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:uuid/uuid.dart'; import 'widgets/copy_or_skip.dart'; import '../../models/workout_type.dart'; @@ -37,8 +36,7 @@ class ImportWorkoutState extends State { /// of the list of workouts on the home page. If this is an existing workout /// that was edited, keep its index where it is. /// - Future importWorkoutUpdateDatabase( - Database database, Workout workoutArgument) async { + Future importWorkoutUpdateDatabase(Workout workoutArgument) async { /// Grab the list of existing workouts so we can bump down the /// index of each in order to make room for this new workout to be at /// the top of the list. @@ -47,8 +45,7 @@ class ImportWorkoutState extends State { logger.i( "Adding imported workout to database: ${workoutArgument.toString()}"); - List workouts = - await DatabaseManager().lists(DatabaseManager().initDB()); + List workouts = await DatabaseManager().getWorkouts(); logger.i("Grabbed existing workouts: ${workouts.length}"); @@ -59,10 +56,10 @@ class ImportWorkoutState extends State { for (var i = 0; i < workouts.length; i++) { if (i == 0) { workouts[i].workoutIndex = 0; - await DatabaseManager().insertList(workouts[i], database); + await DatabaseManager().insertWorkout(workouts[i]); } else { workouts[i].workoutIndex = workouts[i].workoutIndex + 1; - await DatabaseManager().updateList(workouts[i], database); + await DatabaseManager().updateWorkout(workouts[i]); } } @@ -152,12 +149,9 @@ class ImportWorkoutState extends State { "Attempting to import ${workout.title}"); try { - Database database = - await DatabaseManager().initDB(); - importStatus = await importWorkoutUpdateDatabase( - database, workout); + workout); } on Exception catch (e) { logger.e( "Database conflict on import: $e"); diff --git a/lib/pages/set_sounds.dart/constants/sounds.dart b/lib/pages/set_sounds/constants/sounds.dart similarity index 100% rename from lib/pages/set_sounds.dart/constants/sounds.dart rename to lib/pages/set_sounds/constants/sounds.dart diff --git a/lib/pages/set_sounds.dart/set_sounds.dart b/lib/pages/set_sounds/set_sounds.dart similarity index 84% rename from lib/pages/set_sounds.dart/set_sounds.dart rename to lib/pages/set_sounds/set_sounds.dart index 122a068..682a6f3 100644 --- a/lib/pages/set_sounds.dart/set_sounds.dart +++ b/lib/pages/set_sounds/set_sounds.dart @@ -1,8 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:openhiit/pages/home/home.dart'; +import 'package:openhiit/providers/workout_provider.dart'; +import 'package:provider/provider.dart'; import 'package:soundpool/soundpool.dart'; -import 'package:sqflite/sqflite.dart'; import 'package:uuid/uuid.dart'; import '../../models/workout_type.dart'; import '../../utils/database/database_manager.dart'; @@ -26,9 +27,7 @@ class _SetSoundsState extends State { /// is successfully added to the DB, push to the home screen. /// void submitWorkout(Workout workoutArgument) async { - Database database = await DatabaseManager().initDB(); - - await updateDatabase(database, workoutArgument).then((value) => pushHome()); + await saveWorkout(workoutArgument).then((value) => pushHome()); } /// Update the database with the workout. If this is a brand new workout, @@ -37,38 +36,20 @@ class _SetSoundsState extends State { /// of the list of workouts on the home page. If this is an existing workout /// that was edited, keep its index where it is. /// - Future updateDatabase(database, Workout workoutArgument) async { - /// If the workout does not have an ID, that means this is a brand new - /// workout. Grab the list of existing workouts so we can bump down the - /// index of each in order to make room for this new workout to be at - /// the top of the list. - /// - if (workoutArgument.id == "") { - List workouts = - await DatabaseManager().lists(DatabaseManager().initDB()); + Future saveWorkout(Workout workoutArgument) async { + WorkoutProvider workoutProvider = + Provider.of(context, listen: false); + DatabaseManager databaseManager = DatabaseManager(); - // Give the new workout an ID + if (workoutArgument.id == "") { workoutArgument.id = const Uuid().v1(); - - // Insert the new workout into the top (beginning) of the list - workouts.insert(0, workoutArgument); - - // Increase the index of all old workouts by 1. - for (var i = 0; i < workouts.length; i++) { - if (i == 0) { - await DatabaseManager().insertList(workouts[i], database); - } else { - workouts[i].workoutIndex = workouts[i].workoutIndex + 1; - await DatabaseManager().updateList(workouts[i], database); - } - } - } - - /// If the workout already has an ID, that means this is an existing - /// workout that was edited. Simply update the workout in the DB. - /// - else { - await DatabaseManager().updateList(workoutArgument, database); + workoutProvider.updateWorkoutIndices(1); + await workoutProvider.addWorkout(workoutArgument).then((value) { + workoutProvider.sort((d) => d.workoutIndex, true); + databaseManager.updateWorkouts(workoutProvider.workouts); + }); + } else { + await workoutProvider.updateWorkout(workoutArgument); } } diff --git a/lib/pages/set_sounds.dart/widgets/sound_dropdown.dart b/lib/pages/set_sounds/widgets/sound_dropdown.dart similarity index 100% rename from lib/pages/set_sounds.dart/widgets/sound_dropdown.dart rename to lib/pages/set_sounds/widgets/sound_dropdown.dart diff --git a/lib/pages/set_timings.dart/constants/set_timings_constants.dart b/lib/pages/set_timings/constants/set_timings_constants.dart similarity index 100% rename from lib/pages/set_timings.dart/constants/set_timings_constants.dart rename to lib/pages/set_timings/constants/set_timings_constants.dart diff --git a/lib/pages/set_timings.dart/set_timings.dart b/lib/pages/set_timings/set_timings.dart similarity index 99% rename from lib/pages/set_timings.dart/set_timings.dart rename to lib/pages/set_timings/set_timings.dart index 30c457b..d47bc0d 100644 --- a/lib/pages/set_timings.dart/set_timings.dart +++ b/lib/pages/set_timings/set_timings.dart @@ -89,7 +89,7 @@ class _SetTimingsState extends State { addListeners(); logger.i( - "Loading for workout object for creation/editing: ${workout.toString()}"); + "Loading workout object for creation/editing: ${workout.toString()}"); Map> notifierMap = { "Work": ValueNotifier(workout.workTime), diff --git a/lib/pages/set_timings.dart/utils/set_timings_utils.dart b/lib/pages/set_timings/utils/set_timings_utils.dart similarity index 100% rename from lib/pages/set_timings.dart/utils/set_timings_utils.dart rename to lib/pages/set_timings/utils/set_timings_utils.dart diff --git a/lib/pages/set_timings.dart/widgets/expansion_additional_config_tile.dart b/lib/pages/set_timings/widgets/expansion_additional_config_tile.dart similarity index 100% rename from lib/pages/set_timings.dart/widgets/expansion_additional_config_tile.dart rename to lib/pages/set_timings/widgets/expansion_additional_config_tile.dart diff --git a/lib/pages/set_timings.dart/widgets/time_input_trailing.dart b/lib/pages/set_timings/widgets/time_input_trailing.dart similarity index 100% rename from lib/pages/set_timings.dart/widgets/time_input_trailing.dart rename to lib/pages/set_timings/widgets/time_input_trailing.dart diff --git a/lib/pages/set_timings.dart/widgets/time_list_item.dart b/lib/pages/set_timings/widgets/time_list_item.dart similarity index 100% rename from lib/pages/set_timings.dart/widgets/time_list_item.dart rename to lib/pages/set_timings/widgets/time_list_item.dart diff --git a/lib/pages/view_workout/view_workout.dart b/lib/pages/view_workout/view_workout.dart index 7b6c64e..8766d85 100644 --- a/lib/pages/view_workout/view_workout.dart +++ b/lib/pages/view_workout/view_workout.dart @@ -1,12 +1,13 @@ import 'dart:convert'; import 'dart:io'; import 'package:openhiit/pages/home/home.dart'; +import 'package:openhiit/providers/workout_provider.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:provider/provider.dart'; import 'package:uuid/uuid.dart'; import 'package:flutter/material.dart'; import '../../utils/functions.dart'; import 'widgets/start_button.dart'; -import 'package:sqflite/sqflite.dart'; import '../../widgets/card_item_animated.dart'; import '../../utils/database/database_manager.dart'; import 'widgets/view_workout_appbar.dart'; @@ -42,27 +43,13 @@ class ViewWorkoutState extends State { /// Returns: /// - A Future representing the completion of the delete operation. Future deleteList(workoutArgument) async { - // Initialize the database. - Future database = DatabaseManager().initDB(); + WorkoutProvider workoutProvider = + Provider.of(context, listen: false); + DatabaseManager databaseManager = DatabaseManager(); - // Delete the specified workout list from the database. - await DatabaseManager() - .deleteList(workoutArgument.id, database) - .then((value) async { - // Retrieve the updated list of workouts from the database. - List workouts = - await DatabaseManager().lists(DatabaseManager().initDB()); - - // Sort the workouts based on their workout indices. - workouts.sort((a, b) => a.workoutIndex.compareTo(b.workoutIndex)); - - // Update the workout indices of remaining lists after the deleted list. - for (int i = workoutArgument.workoutIndex; i < workouts.length; i++) { - workouts[i].workoutIndex = i; - await DatabaseManager() - .updateList(workouts[i], await DatabaseManager().initDB()); - } - }); + workoutProvider.deleteWorkout(workoutArgument); + workoutProvider.updateWorkoutIndices(0); + databaseManager.updateWorkouts(workoutProvider.workouts); } @override @@ -163,8 +150,7 @@ class ViewWorkoutState extends State { /// It duplicates the current workout and updates the list and the database accordingly. /// Fetch the list of workouts from the database. - List workouts = - await DatabaseManager().lists(DatabaseManager().initDB()); + List workouts = await DatabaseManager().getWorkouts(); /// Increment the workoutIndex of each workout in the list. for (Workout workout in workouts) { @@ -199,15 +185,12 @@ class ViewWorkoutState extends State { /// Insert the duplicate workout at the beginning of the list. workouts.insert(0, duplicateWorkout); - /// Initialize the database. - Database database = await DatabaseManager().initDB(); - /// Insert the duplicate workout into the database. - await DatabaseManager().insertList(duplicateWorkout, database); + await DatabaseManager().insertWorkout(duplicateWorkout); /// Update the workoutIndex of each workout in the database. for (Workout workout in workouts) { - await DatabaseManager().updateList(workout, database); + await DatabaseManager().updateWorkout(workout); } /// Navigate back to the main screen to show that the workout has been copied. diff --git a/lib/providers/workout_provider.dart b/lib/providers/workout_provider.dart index c0bdaa7..0a78543 100644 --- a/lib/providers/workout_provider.dart +++ b/lib/providers/workout_provider.dart @@ -9,7 +9,7 @@ class WorkoutProvider extends ChangeNotifier { Future> loadWorkoutData() async { var dbManager = DatabaseManager(); - return dbManager.lists(dbManager.initDB()).then((workouts) { + return dbManager.getWorkouts().then((workouts) { _workouts = workouts; return _workouts; }).whenComplete(() { @@ -19,9 +19,7 @@ class WorkoutProvider extends ChangeNotifier { Future updateWorkout(Workout workout) async { var dbManager = DatabaseManager(); - return dbManager - .updateList(workout, await DatabaseManager().initDB()) - .then((_) { + return dbManager.updateWorkout(workout).then((_) { var updated = false; for (var i = 0; i < _workouts.length; i++) { if (_workouts[i].id == workout.id) { @@ -38,18 +36,14 @@ class WorkoutProvider extends ChangeNotifier { Future addWorkout(Workout workout) async { var dbManager = DatabaseManager(); - return dbManager - .insertList(workout, await DatabaseManager().initDB()) - .then((val) { + return dbManager.insertWorkout(workout).then((val) { _workouts.add(workout); }).whenComplete(() => notifyListeners()); } Future deleteWorkout(Workout workout) async { var dbManager = DatabaseManager(); - return dbManager - .deleteList(workout.id, DatabaseManager().initDB()) - .then((_) { + return dbManager.deleteWorkout(workout.id).then((_) { _workouts.removeWhere((workout) => workout.id == workout.id); }).whenComplete(() => notifyListeners()); } @@ -67,4 +61,11 @@ class WorkoutProvider extends ChangeNotifier { }); notifyListeners(); } + + void updateWorkoutIndices(int start) { + for (var i = 0; i < _workouts.length; i++) { + _workouts[i] = _workouts[i].copyWith(workoutIndex: start + i); + } + notifyListeners(); + } } diff --git a/lib/utils/database/database_manager.dart b/lib/utils/database/database_manager.dart index 29cd099..8ddc89a 100644 --- a/lib/utils/database/database_manager.dart +++ b/lib/utils/database/database_manager.dart @@ -1,166 +1,107 @@ import 'dart:async'; import 'dart:io'; -import 'package:flutter/material.dart'; +import 'package:openhiit/utils/log/log.dart'; import 'package:path/path.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import '../../models/workout_type.dart'; class DatabaseManager { - /// The name of the database. - /// - /// e.g., "database.db" - /// static const String _databaseName = "core1.db"; - - /// The name of the table in the database where workouts are stored. - /// - /// e.g., "workouts" - /// static const String _workoutTableName = "WorkoutTable"; + Database? _database; - Future initDB() async { - debugPrint("initDB executed"); + DatabaseManager() { + _initPlatformDatabaseSettings(); + } + void _initPlatformDatabaseSettings() { if (Platform.isWindows || Platform.isLinux) { - // Initialize FFI sqfliteFfiInit(); - // Change the default factory databaseFactory = databaseFactoryFfiNoIsolate; } + } + + Future _getDatabase() async { + if (_database != null) return _database!; + return _database = await openWorkoutDatabase(); + } + + Future openWorkoutDatabase() async { + logger.d("Opening database"); + + const createWorkoutTableQuery = ''' + CREATE TABLE IF NOT EXISTS $_workoutTableName( + id TEXT PRIMARY KEY, + title TEXT, + numExercises INTEGER, + exercises TEXT, + getReadyTime INTEGER, + exerciseTime INTEGER, + restTime INTEGER, + halfTime INTEGER, + breakTime INTEGER, + warmupTime INTEGER, + cooldownTime INTEGER, + iterations INTEGER, + halfwayMark INTEGER, + workSound TEXT, + restSound TEXT, + halfwaySound TEXT, + completeSound TEXT, + countdownSound TEXT, + colorInt INTEGER, + workoutIndex INTEGER, + showMinutes INTEGER + ) + '''; - //Directory documentsDirectory = await getApplicationDocumentsDirectory(); String path = join(await getDatabasesPath(), _databaseName); - // Clear database for testing - // await deleteDatabase(path); - if (Platform.isWindows || Platform.isLinux) { - return await openDatabase( - inMemoryDatabasePath, - version: 5, - onCreate: (db, version) async { - await db.execute(''' - CREATE TABLE IF NOT EXISTS WorkoutTable(id TEXT PRIMARY KEY, - title TEXT, - numExercises INTEGER, - exercises TEXT, - getReadyTime INTEGER, - exerciseTime INTEGER, - restTime INTEGER, - halfTime INTEGER, - breakTime INTEGER, - warmupTime INTEGER, - cooldownTime INTEGER, - iterations INTEGER, - halfwayMark INTEGER, - workSound TEXT, - restSound TEXT, - halfwaySound TEXT, - completeSound TEXT, - countdownSound TEXT, - colorInt INTEGER, - workoutIndex INTEGER, - showMinutes INTEGER - ) - '''); - }, - onUpgrade: (db, oldVersion, newVersion) async { - if (oldVersion == 1) { - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN colorInt INTEGER;"); - } - if (oldVersion == 2) { - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN workoutIndex INTEGER;"); - } - if (oldVersion == 3) { - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN showMinutes INTEGER;"); - } - if (oldVersion < newVersion) { - print("Add columns"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN getReadyTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN breakTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN warmupTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN cooldownTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN iterations INTEGER;"); - } - }, - ); - } - return await openDatabase( - path, - version: 6, - onCreate: (Database db, int version) async { - await db.execute(''' - CREATE TABLE IF NOT EXISTS WorkoutTable(id TEXT PRIMARY KEY, - title TEXT, - numExercises INTEGER, - exercises TEXT, - getReadyTime INTEGER, - exerciseTime INTEGER, - restTime INTEGER, - halfTime INTEGER, - breakTime INTEGER, - warmupTime INTEGER, - cooldownTime INTEGER, - iterations INTEGER, - halfwayMark INTEGER, - workSound TEXT, - restSound TEXT, - halfwaySound TEXT, - completeSound TEXT, - countdownSound TEXT, - colorInt INTEGER, - workoutIndex INTEGER, - showMinutes INTEGER - ) - '''); - }, - onUpgrade: (db, oldVersion, newVersion) async { - if (oldVersion == 2) { - await db - .execute("ALTER TABLE WorkoutTable ADD COLUMN colorInt INTEGER;"); - } - if (oldVersion == 3) { - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN workoutIndex INTEGER;"); - } - if (oldVersion == 4) { - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN showMinutes INTEGER;"); - } - if (oldVersion < newVersion) { - print("Add columns"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN getReadyTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN breakTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN warmupTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN cooldownTime INTEGER;"); - await db.execute( - "ALTER TABLE WorkoutTable ADD COLUMN iterations INTEGER;"); - } + String dbPath = + (Platform.isWindows || Platform.isLinux) ? inMemoryDatabasePath : path; + int dbVersion = (Platform.isWindows || Platform.isLinux) ? 5 : 6; + + return openDatabase( + dbPath, + version: dbVersion, + onCreate: (db, version) async { + await db.execute(createWorkoutTableQuery); }, + onUpgrade: _handleUpgrade, ); } - /// Inserts the given list into the given database. - /// - Future insertList(Workout workout, Database database) async { - /// Get a reference to the database. - /// - final db = database; - - /// Insert the TodoList into the correct table. - /// - /// In this case, replace any previous data. - /// + Future _handleUpgrade( + Database db, int oldVersion, int newVersion) async { + if (oldVersion != newVersion) { + logger.d("Upgrading database from $oldVersion to $newVersion"); + } + + Map> upgradeQueries = { + 1: ["ALTER TABLE $_workoutTableName ADD COLUMN colorInt INTEGER;"], + 2: ["ALTER TABLE $_workoutTableName ADD COLUMN workoutIndex INTEGER;"], + 3: ["ALTER TABLE $_workoutTableName ADD COLUMN showMinutes INTEGER;"], + 4: [ + "ALTER TABLE $_workoutTableName ADD COLUMN getReadyTime INTEGER;", + "ALTER TABLE $_workoutTableName ADD COLUMN breakTime INTEGER;", + "ALTER TABLE $_workoutTableName ADD COLUMN warmupTime INTEGER;", + "ALTER TABLE $_workoutTableName ADD COLUMN cooldownTime INTEGER;", + "ALTER TABLE $_workoutTableName ADD COLUMN iterations INTEGER;" + ] + }; + + for (int i = oldVersion; i < newVersion; i++) { + if (upgradeQueries.containsKey(i)) { + for (var query in upgradeQueries[i]!) { + await db.execute(query); + } + } + } + } + + Future insertWorkout(Workout workout) async { + logger.d("Inserting workout: ${workout.title}"); + + final db = await _getDatabase(); await db.insert( _workoutTableName, workout.toMap(), @@ -168,80 +109,52 @@ class DatabaseManager { ); } - /// Update the given list in the given database. - /// - Future updateList(Workout workout, Database database) async { - /// Get a reference to the database. - /// - final db = database; + Future updateWorkout(Workout workout) async { + logger.d("Updating workout: ${workout.title}"); + final db = await _getDatabase(); await db.update( _workoutTableName, workout.toMap(), - where: 'id = ?', // Ensure that the List has a matching id. - whereArgs: [ - workout.id - ], // Pass the id as a whereArg to prevent SQL injection. + where: 'id = ?', + whereArgs: [workout.id], ); } - Future deleteList(String id, Future database) async { - /// Get a reference to the database. - /// - final db = await database; + Future updateWorkouts(List workouts) async { + logger.d("Updating ${workouts.length} workouts"); + + final db = await _getDatabase(); + Batch batch = db.batch(); + + for (var workout in workouts) { + batch.update( + _workoutTableName, + workout.toMap(), + where: 'id = ?', + whereArgs: [workout.id], + ); + } + + await batch.commit(noResult: true); + } + + Future deleteWorkout(String id) async { + logger.d("Deleting workout with ID: $id"); + final db = await _getDatabase(); await db.delete( _workoutTableName, - where: 'id = ?', // Use a `where` clause to delete a specific list. - whereArgs: [ - id - ], // Pass the List's id as a whereArg to prevent SQL injection. + where: 'id = ?', + whereArgs: [id], ); } - Future> lists(Future database) async { - /// Get a reference to the database. - /// - final db = await database; + Future> getWorkouts() async { + logger.d("Getting all workouts"); - /// Query the table for all the TodoLists. - /// + final db = await _getDatabase(); final List> maps = await db.query(_workoutTableName); - - /// Convert the List into a List. - /// - return List.generate(maps.length, (i) { - return Workout( - maps[i]['id'], - maps[i]['title'], - maps[i]['numExercises'], - maps[i]['exercises'], - maps[i]['getReadyTime'] ?? 10, - maps[i]['exerciseTime'], - maps[i]['restTime'], - maps[i]['halfTime'], - maps[i]['breakTime'] ?? 0, - maps[i]['warmupTime'] ?? 0, - maps[i]['cooldownTime'] ?? 0, - maps[i]['iterations'] ?? 0, - maps[i]['halfwayMark'], - maps[i]['workSound'], - maps[i]['restSound'], - maps[i]['halfwaySound'], - maps[i]['completeSound'], - maps[i]['countdownSound'], - maps[i]['colorInt'] ?? - 4280391411, // Default to blue if no previous color selected - maps[i]['workoutIndex'] ?? - i, // Default to the current index if no index change passed - maps[i]['showMinutes'] ?? 0 // Default to 0 if no previous selection - ); - }); + return maps.map((map) => Workout.fromMap(map)).toList(); } - - /// - /// ------------- - /// END FUNCTIONS - /// ------------- - /// } From 26488386d24471127d26a060d31746fb3f843029 Mon Sep 17 00:00:00 2001 From: a-mabe Date: Tue, 1 Oct 2024 20:36:31 -0400 Subject: [PATCH 2/2] Fix folder names and imports --- lib/pages/create_timer/create_timer.dart | 2 +- .../{set_exercises.dart => set_exercises}/set_exercises.dart | 2 +- lib/pages/set_timings/set_timings.dart | 4 ++-- lib/pages/set_timings/widgets/time_input_trailing.dart | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename lib/pages/{set_exercises.dart => set_exercises}/set_exercises.dart (99%) diff --git a/lib/pages/create_timer/create_timer.dart b/lib/pages/create_timer/create_timer.dart index caf4981..1a45de3 100644 --- a/lib/pages/create_timer/create_timer.dart +++ b/lib/pages/create_timer/create_timer.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:openhiit/widgets/form_widgets/create_form.dart'; import '../../models/workout_type.dart'; -import '../set_timings.dart/set_timings.dart'; +import '../set_timings/set_timings.dart'; import '../../widgets/form_widgets/submit_button.dart'; class CreateTimer extends StatefulWidget { diff --git a/lib/pages/set_exercises.dart/set_exercises.dart b/lib/pages/set_exercises/set_exercises.dart similarity index 99% rename from lib/pages/set_exercises.dart/set_exercises.dart rename to lib/pages/set_exercises/set_exercises.dart index 586616c..e1add4d 100644 --- a/lib/pages/set_exercises.dart/set_exercises.dart +++ b/lib/pages/set_exercises/set_exercises.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; import 'dart:convert'; import '../../models/workout_type.dart'; -import '../set_timings.dart/set_timings.dart'; +import '../set_timings/set_timings.dart'; import '../../widgets/form_widgets/submit_button.dart'; var logger = Logger( diff --git a/lib/pages/set_timings/set_timings.dart b/lib/pages/set_timings/set_timings.dart index d47bc0d..7e5a802 100644 --- a/lib/pages/set_timings/set_timings.dart +++ b/lib/pages/set_timings/set_timings.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; -import 'package:openhiit/pages/set_timings.dart/constants/set_timings_constants.dart'; +import 'package:openhiit/pages/set_timings/constants/set_timings_constants.dart'; import 'widgets/time_input_trailing.dart'; import '../../models/workout_type.dart'; import '../../widgets/form_widgets/submit_button.dart'; import 'widgets/time_list_item.dart'; -import '../set_sounds.dart/set_sounds.dart'; +import '../set_sounds/set_sounds.dart'; var logger = Logger( printer: PrettyPrinter(methodCount: 0), diff --git a/lib/pages/set_timings/widgets/time_input_trailing.dart b/lib/pages/set_timings/widgets/time_input_trailing.dart index a66bed7..efd95d5 100644 --- a/lib/pages/set_timings/widgets/time_input_trailing.dart +++ b/lib/pages/set_timings/widgets/time_input_trailing.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:openhiit/pages/set_timings.dart/utils/set_timings_utils.dart'; +import 'package:openhiit/pages/set_timings/utils/set_timings_utils.dart'; import '../../../widgets/form_widgets/number_input.dart';