diff --git a/lib/api_client.dart b/lib/api_client.dart new file mode 100644 index 000000000..bde351c5c --- /dev/null +++ b/lib/api_client.dart @@ -0,0 +1,64 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:http/http.dart' as http; +import 'package:logging/logging.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'helpers/consts.dart'; + +final log = Logger('powersync-test'); + +class ApiClient { + final String baseUrl; + + const ApiClient(this.baseUrl); + + /// Returns a powersync JWT token token + /// + /// Note that at the moment we use the permanent API token for authentication + /// but this should be probably changed to the wger API JWT tokens in the + /// future since they are not permanent and could be easily revoked. + Future> getPowersyncToken() async { + final prefs = await SharedPreferences.getInstance(); + final apiData = json.decode(prefs.getString(PREFS_USER)!); + print('posting our token "${apiData["token"]}" to $baseUrl/api/v2/powersync-token'); + final response = await http.get( + Uri.parse('$baseUrl/api/v2/powersync-token'), + headers: { + HttpHeaders.contentTypeHeader: 'application/json', + HttpHeaders.authorizationHeader: 'Token ${apiData["token"]}', + }, + ); + print('response: status ${response.statusCode}, body ${response.body}'); + if (response.statusCode == 200) { + log.log(Level.ALL, response.body); + return json.decode(response.body); + } + throw Exception('Failed to fetch token'); + } + + Future upsert(Map record) async { + await http.put( + Uri.parse('$baseUrl/api/upload-powersync-data'), + headers: {'Content-Type': 'application/json'}, + body: json.encode(record), + ); + } + + Future update(Map record) async { + await http.patch( + Uri.parse('$baseUrl/api/upload-powersync-data'), + headers: {'Content-Type': 'application/json'}, + body: json.encode(record), + ); + } + + Future delete(Map record) async { + await http.delete( + Uri.parse('$baseUrl/api/v2/upload-powersync-data'), + headers: {'Content-Type': 'application/json'}, + body: json.encode(record), + ); + } +} diff --git a/lib/helpers/consts.dart b/lib/helpers/consts.dart index 2b976165b..cf2193e1b 100644 --- a/lib/helpers/consts.dart +++ b/lib/helpers/consts.dart @@ -103,7 +103,7 @@ enum EXERCISE_IMAGE_ART_STYLE { } /// Dummy ID for pseudo meals -const PSEUDO_MEAL_ID = -1; +const PSEUDO_MEAL_ID = 'deadbeef'; /// Colors used for muscles const COLOR_MAIN_MUSCLES = Colors.red; diff --git a/lib/main.dart b/lib/main.dart index 956c4874b..4228f72d4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -161,9 +161,8 @@ class MainApp extends StatelessWidget { providers: [ ChangeNotifierProvider(create: (ctx) => AuthProvider()), ChangeNotifierProxyProvider( - create: (context) => ExercisesProvider( - WgerBaseProvider(Provider.of(context, listen: false)), - ), + create: (context) => + ExercisesProvider(WgerBaseProvider(Provider.of(context, listen: false))), update: (context, base, previous) => previous ?? ExercisesProvider(WgerBaseProvider(base)), ), @@ -177,44 +176,34 @@ class MainApp extends StatelessWidget { previous ?? RoutinesProvider(WgerBaseProvider(auth), exercises, []), ), ChangeNotifierProxyProvider( - create: (context) => NutritionPlansProvider( - WgerBaseProvider(Provider.of(context, listen: false)), - [], - ), + create: (context) => + NutritionPlansProvider(WgerBaseProvider(Provider.of(context, listen: false)), []), update: (context, auth, previous) => previous ?? NutritionPlansProvider(WgerBaseProvider(auth), []), ), ChangeNotifierProxyProvider( - create: (context) => MeasurementProvider( - WgerBaseProvider(Provider.of(context, listen: false)), - ), + create: (context) => + MeasurementProvider(WgerBaseProvider(Provider.of(context, listen: false))), update: (context, base, previous) => previous ?? MeasurementProvider(WgerBaseProvider(base)), ), ChangeNotifierProxyProvider( - create: (context) => UserProvider( - WgerBaseProvider(Provider.of(context, listen: false)), - ), + create: (context) => UserProvider(WgerBaseProvider(Provider.of(context, listen: false))), update: (context, base, previous) => previous ?? UserProvider(WgerBaseProvider(base)), ), ChangeNotifierProxyProvider( - create: (context) => BodyWeightProvider( - WgerBaseProvider(Provider.of(context, listen: false)), - ), + create: (context) => + BodyWeightProvider(WgerBaseProvider(Provider.of(context, listen: false))), update: (context, base, previous) => previous ?? BodyWeightProvider(WgerBaseProvider(base)), ), ChangeNotifierProxyProvider( - create: (context) => GalleryProvider( - Provider.of(context, listen: false), - [], - ), + create: (context) => GalleryProvider(Provider.of(context, listen: false), []), update: (context, auth, previous) => previous ?? GalleryProvider(auth, []), ), ChangeNotifierProxyProvider( - create: (context) => AddExerciseProvider( - WgerBaseProvider(Provider.of(context, listen: false)), - ), + create: (context) => + AddExerciseProvider(WgerBaseProvider(Provider.of(context, listen: false))), update: (context, base, previous) => previous ?? AddExerciseProvider(WgerBaseProvider(base)), ), diff --git a/lib/models/muscle.dart b/lib/models/muscle.dart new file mode 100644 index 000000000..2c86437e5 --- /dev/null +++ b/lib/models/muscle.dart @@ -0,0 +1,37 @@ +import 'package:powersync/sqlite3.dart' as sqlite; +import 'package:wger/models/schema.dart'; +import 'package:wger/powersync.dart'; + +class Muscle { + final String id; + final String name; + final String nameEn; + final bool isFront; + + const Muscle({ + required this.id, + required this.name, + required this.nameEn, + required this.isFront, + }); + + factory Muscle.fromRow(sqlite.Row row) { + return Muscle( + id: row['id'], + name: row['name'], + nameEn: row['name_en'], + isFront: row['is_front'] == 1, + ); + } + + Future delete() async { + await db.execute('DELETE FROM $tableMuscles WHERE id = ?', [id]); + } + + /// Watch all lists. + static Stream> watchMuscles() { + return db.watch('SELECT * FROM $tableMuscles ORDER BY id').map((results) { + return results.map(Muscle.fromRow).toList(growable: false); + }); + } +} diff --git a/lib/models/nutrition/log.dart b/lib/models/nutrition/log.dart index 118b62549..4c47dcf08 100644 --- a/lib/models/nutrition/log.dart +++ b/lib/models/nutrition/log.dart @@ -17,24 +17,28 @@ */ import 'package:json_annotation/json_annotation.dart'; +import 'package:powersync/powersync.dart'; +import 'package:powersync/sqlite3.dart' as sqlite; import 'package:wger/helpers/json.dart'; import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient_weight_unit.dart'; import 'package:wger/models/nutrition/meal_item.dart'; import 'package:wger/models/nutrition/nutritional_values.dart'; +import 'package:wger/models/schema.dart'; +import 'package:wger/powersync.dart'; part 'log.g.dart'; @JsonSerializable() class Log { @JsonKey(required: true) - int? id; + String? id; @JsonKey(required: false, name: 'meal') - int? mealId; + String? mealId; @JsonKey(required: true, name: 'plan') - int planId; + String planId; @JsonKey(required: true, fromJson: utcIso8601ToLocalDate, toJson: dateToUtcIso8601) late DateTime datetime; @@ -75,6 +79,19 @@ class Log { amount = mealItem.amount; } + factory Log.fromRow(sqlite.Row row) { + return Log( + id: row['id'], + mealId: row['meal_id'], + ingredientId: row['ingredient_id'], + weightUnitId: row['weight_unit_id'], + amount: row['amount'], + planId: row['plan_id'], + datetime: DateTime.parse(row['datetime']), + comment: row['comment'], + ); + } + // Boilerplate factory Log.fromJson(Map json) => _$LogFromJson(json); @@ -90,4 +107,38 @@ class Log { return ingredient.nutritionalValues / (100 / weight); } + + static Future> readByMealId(String mealId) async { + final results = await db.getAll('SELECT * FROM $tableLogItems WHERE meal_id = ?', [mealId]); + return results.map((r) => Log.fromRow(r)).toList(); + } + + static Future> readByPlanId(String planId) async { + final results = await db.getAll('SELECT * FROM $tableLogItems WHERE plan_id = ?', [planId]); + return results.map((r) => Log.fromRow(r)).toList(); + } + + /* + Future delete() async { + await db.execute('DELETE FROM $logItemsTable WHERE id = ?', [id]); + } + */ + + Future log() async { + print('DIETER Log.log called id=$id, planId=$planId'); + await db.execute( + 'INSERT INTO $tableLogItems (id, meal_id, ingredient_id, weight_unit_id, amount, plan_id, datetime, comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', + [ + // generate an id using uuid + uuid.v4(), + mealId, + ingredientId, + weightUnitId, + amount, + planId, + datetime.toIso8601String(), + comment, + ], + ); + } } diff --git a/lib/models/nutrition/log.g.dart b/lib/models/nutrition/log.g.dart index 102125b48..0da0e6836 100644 --- a/lib/models/nutrition/log.g.dart +++ b/lib/models/nutrition/log.g.dart @@ -19,13 +19,13 @@ Log _$LogFromJson(Map json) { ], ); return Log( - id: (json['id'] as num?)?.toInt(), - mealId: (json['meal'] as num?)?.toInt(), + id: json['id'] as String?, + mealId: json['meal'] as String?, ingredientId: (json['ingredient'] as num).toInt(), weightUnitId: (json['weight_unit'] as num?)?.toInt(), amount: stringToNum(json['amount'] as String?), - planId: (json['plan'] as num).toInt(), - datetime: utcIso8601ToLocalDate(json['datetime'] as String), + planId: json['plan'] as String, + datetime: DateTime.parse(json['datetime'] as String), comment: json['comment'] as String?, ); } diff --git a/lib/models/nutrition/meal.dart b/lib/models/nutrition/meal.dart index b7c51e4d1..83a95b9b4 100644 --- a/lib/models/nutrition/meal.dart +++ b/lib/models/nutrition/meal.dart @@ -18,22 +18,25 @@ import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; +import 'package:powersync/sqlite3.dart' as sqlite; import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/date.dart'; import 'package:wger/helpers/json.dart'; import 'package:wger/models/nutrition/log.dart'; import 'package:wger/models/nutrition/meal_item.dart'; import 'package:wger/models/nutrition/nutritional_values.dart'; +import 'package:wger/models/schema.dart'; +import 'package:wger/powersync.dart'; part 'meal.g.dart'; @JsonSerializable() class Meal { @JsonKey(required: false) - late int? id; + late String? id; @JsonKey(name: 'plan') - late int planId; + late String planId; @JsonKey(toJson: timeToString, fromJson: stringToTimeNull) TimeOfDay? time; @@ -52,7 +55,7 @@ class Meal { Meal({ this.id, - int? plan, + String? plan, this.time, String? name, List? mealItems, @@ -87,11 +90,20 @@ class Meal { // Boilerplate factory Meal.fromJson(Map json) => _$MealFromJson(json); + factory Meal.fromRow(sqlite.Row row) { + return Meal( + id: row['id'], + plan: row['plan_id'], + time: stringToTime(row['time']), + name: row['name'], + ); + } + Map toJson() => _$MealToJson(this); Meal copyWith({ - int? id, - int? planId, + String? id, + String? plan, TimeOfDay? time, String? name, List? mealItems, @@ -99,11 +111,31 @@ class Meal { }) { return Meal( id: id ?? this.id, - plan: planId ?? this.planId, + plan: plan ?? planId, time: time ?? this.time, name: name ?? this.name, mealItems: mealItems ?? this.mealItems, diaryEntries: diaryEntries ?? this.diaryEntries, ); } + + Future loadChildren() async { + print('loadChildren called. plan is $planId'); + return copyWith( + mealItems: await MealItem.readByMealId(id!), + diaryEntries: await Log.readByMealId(id!), + ); + } + + static Future read(String id) async { + final results = await db.get('SELECT * FROM $tableMeals WHERE id = ?', [id]); + return Meal.fromRow(results); + } + + static Future> readByPlanId(String planId) async { + print('Meal.readByPlanId: SELECT * FROM $tableMeals WHERE plan_id = $planId'); + final results = await db.getAll('SELECT * FROM $tableMeals WHERE plan_id = ?', [planId]); + print(results.rows.length); + return Future.wait(results.map((r) => Meal.fromRow(r).loadChildren())); + } } diff --git a/lib/models/nutrition/meal.g.dart b/lib/models/nutrition/meal.g.dart index 0edad8cd6..95efb2e6a 100644 --- a/lib/models/nutrition/meal.g.dart +++ b/lib/models/nutrition/meal.g.dart @@ -7,10 +7,10 @@ part of 'meal.dart'; // ************************************************************************** Meal _$MealFromJson(Map json) => Meal( - id: (json['id'] as num?)?.toInt(), + id: json['id'] as String?, time: stringToTimeNull(json['time'] as String?), name: json['name'] as String?, -)..planId = (json['plan'] as num).toInt(); +)..planId = json['plan'] as String; Map _$MealToJson(Meal instance) => { 'id': instance.id, diff --git a/lib/models/nutrition/meal_item.dart b/lib/models/nutrition/meal_item.dart index 410e43064..e740d4c2c 100644 --- a/lib/models/nutrition/meal_item.dart +++ b/lib/models/nutrition/meal_item.dart @@ -17,10 +17,14 @@ */ import 'package:json_annotation/json_annotation.dart'; +import 'package:powersync/sqlite3.dart' as sqlite; + import 'package:wger/helpers/json.dart'; import 'package:wger/models/nutrition/ingredient.dart'; import 'package:wger/models/nutrition/ingredient_weight_unit.dart'; import 'package:wger/models/nutrition/nutritional_values.dart'; +import 'package:wger/models/schema.dart'; +import 'package:wger/powersync.dart'; part 'meal_item.g.dart'; @@ -30,7 +34,7 @@ class MealItem { int? id; @JsonKey(required: false, name: 'meal') - late int mealId; + late String mealId; @JsonKey(required: false, name: 'ingredient') late int ingredientId; @@ -49,7 +53,7 @@ class MealItem { MealItem({ this.id, - int? mealId, + String? mealId, required this.ingredientId, this.weightUnitId, required this.amount, @@ -71,6 +75,15 @@ class MealItem { Map toJson() => _$MealItemToJson(this); + factory MealItem.fromRow(sqlite.Row row) { + return MealItem( + amount: row['amount'], + weightUnitId: row['weight_unit_id'], + mealId: row['meal_id'], + ingredientId: row['ingredient_id'], + ); + } + /// Calculations /// TODO why does this not consider weightUnitObj ? should we do the same as Log.nutritionalValues here? NutritionalValues get nutritionalValues { @@ -94,7 +107,7 @@ class MealItem { MealItem copyWith({ int? id, - int? mealId, + String? mealId, int? ingredientId, int? weightUnitId, num? amount, @@ -112,4 +125,9 @@ class MealItem { m.weightUnitObj = weightUnitObj ?? this.weightUnitObj; return m; } + + static Future> readByMealId(String mealId) async { + final results = await db.getAll('SELECT * FROM $tableMealItems WHERE meal_id = ?', [mealId]); + return results.map((r) => MealItem.fromRow(r)).toList(); + } } diff --git a/lib/models/nutrition/meal_item.g.dart b/lib/models/nutrition/meal_item.g.dart index 91b201ed8..a961f4e05 100644 --- a/lib/models/nutrition/meal_item.g.dart +++ b/lib/models/nutrition/meal_item.g.dart @@ -10,7 +10,7 @@ MealItem _$MealItemFromJson(Map json) { $checkKeys(json, requiredKeys: const ['id', 'amount']); return MealItem( id: (json['id'] as num?)?.toInt(), - mealId: (json['meal'] as num?)?.toInt(), + mealId: json['meal'] as String?, ingredientId: (json['ingredient'] as num).toInt(), weightUnitId: (json['weight_unit'] as num?)?.toInt(), amount: stringToNum(json['amount'] as String?), diff --git a/lib/models/nutrition/nutritional_plan.dart b/lib/models/nutrition/nutritional_plan.dart index 0af740b69..409394a86 100644 --- a/lib/models/nutrition/nutritional_plan.dart +++ b/lib/models/nutrition/nutritional_plan.dart @@ -20,6 +20,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/widgets.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:logging/logging.dart'; +import 'package:powersync/sqlite3.dart' as sqlite; import 'package:wger/helpers/consts.dart'; import 'package:wger/helpers/json.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; @@ -28,6 +29,8 @@ import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal_item.dart'; import 'package:wger/models/nutrition/nutritional_goals.dart'; import 'package:wger/models/nutrition/nutritional_values.dart'; +import 'package:wger/models/schema.dart'; +import 'package:wger/powersync.dart'; part 'nutritional_plan.g.dart'; @@ -36,7 +39,7 @@ class NutritionalPlan { final _logger = Logger('NutritionalPlan Model'); @JsonKey(required: true) - int? id; + String? id; @JsonKey(required: true) late String description; @@ -106,6 +109,56 @@ class NutritionalPlan { } } + factory NutritionalPlan.fromRow(sqlite.Row row) { + return NutritionalPlan( + id: row['id'], + description: row['description'], + creationDate: DateTime.parse(row['creation_date']), + startDate: row['start'] != null ? DateTime.parse(row['start']) : DateTime.now(), + endDate: row['end'] != null ? DateTime.parse(row['end']) : null, + onlyLogging: row['only_logging'] == 1, + goalEnergy: row['goal_energy'], + goalProtein: row['goal_protein'], + goalCarbohydrates: row['goal_carbohydrates'], + goalFat: row['goal_fat'], + goalFiber: row['goal_fiber'], + ); + } + + NutritionalPlan copyWith({ + String? id, + String? description, + DateTime? creationDate, + bool? onlyLogging, + num? goalEnergy, + num? goalProtein, + num? goalCarbohydrates, + num? goalFat, + num? goalFiber, + List? meals, + List? diaryEntries, + }) { + return NutritionalPlan( + id: id ?? this.id, + description: description ?? this.description, + creationDate: creationDate ?? this.creationDate, + startDate: startDate ?? this.startDate, + endDate: endDate ?? this.endDate, + onlyLogging: onlyLogging ?? this.onlyLogging, + goalEnergy: goalEnergy ?? this.goalEnergy, + goalProtein: goalProtein ?? this.goalProtein, + goalCarbohydrates: goalCarbohydrates ?? this.goalCarbohydrates, + goalFat: goalFat ?? this.goalFat, + goalFiber: goalFiber ?? this.goalFiber, + meals: meals ?? this.meals, + diaryEntries: diaryEntries ?? this.diaryEntries, + ); + } + + Future loadChildren() async { + return copyWith(diaryEntries: await Log.readByPlanId(id!), meals: await Meal.readByPlanId(id!)); + } + NutritionalPlan.empty() { creationDate = DateTime.now(); startDate = DateTime.now(); @@ -160,10 +213,7 @@ class NutritionalPlan { return NutritionalGoals(); } // otherwise, add up all the nutritional values of the meals and use that as goals - final sumValues = meals.fold( - NutritionalValues(), - (a, b) => a + b.plannedNutritionalValues, - ); + final sumValues = meals.fold(NutritionalValues(), (a, b) => a + b.plannedNutritionalValues); return NutritionalGoals( energy: sumValues.energy, fat: sumValues.fat, @@ -273,4 +323,69 @@ class NutritionalPlan { diaryEntries: diaryEntries.where((e) => e.mealId == null).toList(), ); } + + static Future read(String id) async { + final row = await db.get('SELECT * FROM $tableNutritionPlans WHERE id = ?', [id]); + return NutritionalPlan.fromRow(row).loadChildren(); + } + + // this is a bit complicated. + // what we need at the end of the day, is a stream of List, where + // a new value is emitted any time a plan is changed. But the plan is not just the plan record + // we need to load data for Logs and Meals corresponding to the plan also. + // so our options are: + // 1) db.watch with a select query on plans; and extra dart code to load the logs/meals stuff, + // but this only triggers for updates on the plans table, and misses logs/meals updates + // 2) db.watch with a huge join query across all tables from which we need info, + // so we have all the data in our resultset to create the datastructures with, but: + // - this creates long rows with lots of duplicated data (e.g. all the plan data) for every row + // which would only differ for e.g. the meal or the log item + // - it would probably get a bit messy to parse the resultset into the datastructures + // 3) the best of both worlds: load the data we need in dart at runtime, but explicitly + // trigger our code execution when *any* of the relevant tables changes + // + static Stream> watchNutritionPlans() { + return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async { + final data = await db.getAll('SELECT * FROM $tableNutritionPlans ORDER BY creation_date'); + final futures = Future.wait(data.map((row) => NutritionalPlan.fromRow(row).loadChildren())); + return (await futures).toList(growable: false); + }); + } + + static Stream watchNutritionPlan(String id) { + return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async { + final row = await db.getOptional('SELECT * FROM $tableNutritionPlans WHERE id = ?', [id]); + return row == null ? null : NutritionalPlan.fromRow(row).loadChildren(); + }); + } + + static Stream watchNutritionPlanLast() { + return db.onChange([tableNutritionPlans, tableLogItems, tableMeals]).asyncMap((event) async { + final res = await db.getAll( + 'SELECT * FROM $tableNutritionPlans ORDER BY creation_date DESC LIMIT 1', + ); + if (res.isEmpty) { + return null; + } + return NutritionalPlan.fromRow(res.first).loadChildren(); + }); + } + /* + static Stream> watchNutritionPlan(int id) { + return db + .watch('SELECT * FROM $tableNutritionPlans WHERE id = ?', parameters: [id]).map((results) { + return results.map(NutritionalPlan.fromRow).toList(growable: false); + }); + } + + static Stream> watchNutritionPlans() { + return db.watch('SELECT * FROM $tableNutritionPlans ORDER BY creation_date').map((results) { + return results.map(NutritionalPlan.fromRow).toList(growable: false); + }); + } + */ + + Future delete() async { + await db.execute('DELETE FROM $tableNutritionPlans WHERE id = ?', [id]); + } } diff --git a/lib/models/nutrition/nutritional_plan.g.dart b/lib/models/nutrition/nutritional_plan.g.dart index 3efe23b15..1257cd9a4 100644 --- a/lib/models/nutrition/nutritional_plan.g.dart +++ b/lib/models/nutrition/nutritional_plan.g.dart @@ -24,7 +24,7 @@ NutritionalPlan _$NutritionalPlanFromJson(Map json) { ], ); return NutritionalPlan( - id: (json['id'] as num?)?.toInt(), + id: json['id'] as String?, description: json['description'] as String, creationDate: utcIso8601ToLocalDate(json['creation_date'] as String), startDate: DateTime.parse(json['start'] as String), diff --git a/lib/models/schema.dart b/lib/models/schema.dart new file mode 100644 index 000000000..08ecd01b2 --- /dev/null +++ b/lib/models/schema.dart @@ -0,0 +1,82 @@ +import 'package:powersync/powersync.dart'; + +/* nutrition tables in postgres: +| public | nutrition_image | table> +| public | nutrition_ingredient | table> * # millions of ingredients +| public | nutrition_ingredientcategory | table> +| public | nutrition_ingredientweightunit | table> +| public | nutrition_logitem | table> * OK +| public | nutrition_meal | table> * OK +| public | nutrition_mealitem | table> * +| public | nutrition_nutritionplan | table> * OK +| public | nutrition_weightunit | table> + +assumptions: nutrition_ingredientcategory, nutrition_weightunit, nutrition_ingredientweightunit globals? +*/ + +// User,NutritionPlan,Meal,LogItem,MealItem,Ingredient +const tableMuscles = 'exercises_muscle'; +const tableLogItems = 'nutrition_logitem'; +const tableNutritionPlans = 'nutrition_nutritionplan'; +const tableMeals = 'nutrition_meal'; +const tableMealItems = 'nutrition_mealitem'; + +Schema schema = const Schema([ + Table( + tableMuscles, + [Column.text('name'), Column.text('name_en'), Column.text('is_front')], + ), + Table( + tableNutritionPlans, + [ + Column.text('creation_date'), + Column.text('description'), + Column.integer('has_goal_calories'), + Column.integer('user_id'), + Column.integer('remote_id'), + Column.integer('only_logging'), + Column.integer('goal_carbohydrates'), + Column.integer('goal_energy'), + Column.integer('goal_fat'), + Column.integer('goal_protein'), + Column.integer('goal_fiber'), + ], + ), + Table( + tableLogItems, + [ + Column.text('datetime'), + Column.text('comment'), + Column.integer('amount'), + Column.integer('remote_id'), + Column.integer('ingredient_id'), + Column.text('plan_id'), + Column.integer('weight_unit_id'), + Column.text('meal_id'), // optional + ], + indexes: [ + // Index('plan', [IndexedColumn('plan_id')]) + ], + ), + Table( + tableMeals, + [ + Column.integer('order'), + Column.integer('remote_id'), + Column.text('time'), + Column.text('plan_id'), + Column.text('name'), + ], + ), + Table( + tableMealItems, + [ + Column.integer('order'), + Column.integer('amount'), + Column.integer('ingredient_id'), + Column.text('meal_id'), + Column.integer('remote_id'), + Column.integer('weight_unit_id'), + ], + ), +]); diff --git a/lib/powersync.dart b/lib/powersync.dart new file mode 100644 index 000000000..a8559c9d3 --- /dev/null +++ b/lib/powersync.dart @@ -0,0 +1,122 @@ +// This file performs setup of the PowerSync database +import 'package:logging/logging.dart'; +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:powersync/powersync.dart'; +import 'package:wger/api_client.dart'; + +import './models/schema.dart'; + +final log = Logger('powersync-django'); + +/// Postgres Response codes that we cannot recover from by retrying. +final List fatalResponseCodes = [ + // Class 22 — Data Exception + // Examples include data type mismatch. + RegExp(r'^22...$'), + // Class 23 — Integrity Constraint Violation. + // Examples include NOT NULL, FOREIGN KEY and UNIQUE violations. + RegExp(r'^23...$'), + // INSUFFICIENT PRIVILEGE - typically a row-level security violation + RegExp(r'^42501$'), +]; + +class DjangoConnector extends PowerSyncBackendConnector { + PowerSyncDatabase db; + String baseUrl; + String powersyncUrl; + late ApiClient apiClient; + + DjangoConnector(this.db, this.baseUrl, this.powersyncUrl) { + apiClient = ApiClient(baseUrl); + } + + /// Get a token to authenticate against the PowerSync instance. + @override + Future fetchCredentials() async { + // Somewhat contrived to illustrate usage, see auth docs here: + // https://docs.powersync.com/usage/installation/authentication-setup/custom + // final wgerSession = await apiClient.getWgerJWTToken(); + final session = await apiClient.getPowersyncToken(); + // note: we don't set userId and expires property here. not sure if needed + return PowerSyncCredentials(endpoint: powersyncUrl, token: session['token']); + } + + // Upload pending changes to Postgres via Django backend + // this is generic. on the django side we inspect the request and do model-specific operations + // would it make sense to do api calls here specific to the relevant model? (e.g. put to a todo-specific endpoint) + @override + Future uploadData(PowerSyncDatabase database) async { + final transaction = await database.getNextCrudTransaction(); + + if (transaction == null) { + return; + } + + try { + for (final op in transaction.crud) { + final record = { + 'table': op.table, + 'data': {'id': op.id, ...?op.opData}, + }; + + log.fine('DIETER Uploading record', record); + + switch (op.op) { + case UpdateType.put: + await apiClient.upsert(record); + break; + case UpdateType.patch: + await apiClient.update(record); + break; + case UpdateType.delete: + await apiClient.delete(record); + break; + } + } + await transaction.complete(); + } on Exception catch (e) { + log.severe('Error uploading data', e); + // Error may be retryable - e.g. network error or temporary server error. + // Throwing an error here causes this call to be retried after a delay. + rethrow; + } + } +} + +/// Global reference to the database +late final PowerSyncDatabase db; + +// Hacky flag to ensure the database is only initialized once, better to do this with listeners +bool _dbInitialized = false; + +Future getDatabasePath() async { + final dir = await getApplicationSupportDirectory(); + return join(dir.path, 'powersync-demo.db'); +} + +// opens the database and connects if logged in +Future openDatabase(bool connect, String baseUrl, String powersyncUrl) async { + // Open the local database + if (!_dbInitialized) { + db = PowerSyncDatabase(schema: schema, path: await getDatabasePath(), logger: attachedLogger); + await db.initialize(); + _dbInitialized = true; + } + + if (connect) { + // If the user is already logged in, connect immediately. + // Otherwise, connect once logged in. + + final currentConnector = DjangoConnector(db, baseUrl, powersyncUrl); + db.connect(connector: currentConnector); + + // TODO: should we respond to login state changing? like here: + // https://www.powersync.com/blog/flutter-tutorial-building-an-offline-first-chat-app-with-supabase-and-powersync#implement-auth-methods + } +} + +/// Explicit sign out - clear database and log out. +Future logout() async { + await db.disconnectAndClear(); +} diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index 6bbcb044d..a48232f91 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -193,6 +193,7 @@ class AuthProvider with ChangeNotifier { } // Log user in + // should we update the backend to just include a powersync token also? state = AuthState.loggedIn; notifyListeners(); diff --git a/lib/providers/nutrition.dart b/lib/providers/nutrition.dart index 12435e372..70ff14124 100644 --- a/lib/providers/nutrition.dart +++ b/lib/providers/nutrition.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2026 wger Team + * Copyright (c) 2020 - 2026 wger Team * * wger Workout Manager is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -16,18 +16,17 @@ * along with this program. If not, see . */ +import 'dart:async'; import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:logging/logging.dart'; import 'package:wger/core/exceptions/http_exception.dart'; -import 'package:wger/core/exceptions/no_such_entry_exception.dart'; import 'package:wger/core/locator.dart'; import 'package:wger/database/ingredients/ingredients_database.dart'; import 'package:wger/helpers/consts.dart'; import 'package:wger/models/nutrition/ingredient.dart'; -import 'package:wger/models/nutrition/ingredient_image.dart'; import 'package:wger/models/nutrition/log.dart'; import 'package:wger/models/nutrition/meal.dart'; import 'package:wger/models/nutrition/meal_item.dart'; @@ -37,6 +36,7 @@ import 'package:wger/providers/base_provider.dart'; class NutritionPlansProvider with ChangeNotifier { final _logger = Logger('NutritionPlansProvider'); + // TODO: should be able to delete many of these paths and their corresponding code static const _nutritionalPlansPath = 'nutritionplan'; static const _nutritionalPlansInfoPath = 'nutritionplaninfo'; static const _mealPath = 'meal'; @@ -83,7 +83,7 @@ class NutritionPlansProvider with ChangeNotifier { .sorted((a, b) => b.creationDate.compareTo(a.creationDate)) .firstOrNull; } - + /* NutritionalPlan findById(int id) { return _plans.firstWhere( (plan) => plan.id == id, @@ -91,6 +91,7 @@ class NutritionPlansProvider with ChangeNotifier { ); } + Meal? findMealById(int id) { for (final plan in _plans) { try { @@ -100,95 +101,78 @@ class NutritionPlansProvider with ChangeNotifier { } return null; } + */ - /// Fetches and sets all plans sparsely, i.e. only with the data on the plan - /// object itself and no child attributes - Future fetchAndSetAllPlansSparse() async { - final data = await baseProvider.fetchPaginated( - baseProvider.makeUrl(_nutritionalPlansPath, query: {'limit': API_MAX_PAGE_SIZE}), - ); - _plans = []; - for (final planData in data) { - final plan = NutritionalPlan.fromJson(planData); - _plans.add(plan); - _plans.sort((a, b) => b.creationDate.compareTo(a.creationDate)); - } - notifyListeners(); - } - - /// Fetches and sets all plans fully, i.e. with all corresponding child objects - Future fetchAndSetAllPlansFull() async { - final data = await baseProvider.fetchPaginated( - baseProvider.makeUrl(_nutritionalPlansPath, query: {'limit': API_MAX_PAGE_SIZE}), - ); - await Future.wait(data.map((e) => fetchAndSetPlanFull(e['id'])).toList()); - } + Future _enrichPlan(NutritionalPlan plan) async { + // TODO: set up ingredient images - /// Fetches and sets the given nutritional plan - /// - /// This method only loads the data on the nutritional plan object itself, - /// no meals, etc. - Future fetchAndSetPlanSparse(int planId) async { - final url = baseProvider.makeUrl(_nutritionalPlansPath, id: planId); - final planData = await baseProvider.fetch(url); - final plan = NutritionalPlan.fromJson(planData); - _plans.add(plan); - _plans.sort((a, b) => b.creationDate.compareTo(a.creationDate)); - - notifyListeners(); - return plan; - } - - /// Fetches a plan fully, i.e. with all corresponding child objects - Future fetchAndSetPlanFull(int planId) async { - _logger.fine('Fetching full nutritional plan $planId'); - - NutritionalPlan plan; - try { - plan = findById(planId); - } on NoSuchEntryException { - // TODO: remove this useless call, because we will fetch all details below - plan = await fetchAndSetPlanSparse(planId); + final List diaryEntries = []; + for (final diaryEntry in plan.diaryEntries) { + diaryEntry.ingredient = await fetchIngredient(diaryEntry.ingredientId); + diaryEntries.add(diaryEntry); } - // Plan - final url = baseProvider.makeUrl(_nutritionalPlansInfoPath, id: planId); - final fullPlanData = await baseProvider.fetch(url); - - // Meals final List meals = []; - for (final mealData in fullPlanData['meals']) { + for (final meal in plan.meals) { final List mealItems = []; - final meal = Meal.fromJson(mealData); - - // TODO: we should add these ingredients to the ingredient cache - for (final mealItemData in mealData['meal_items']) { - final mealItem = MealItem.fromJson(mealItemData); - - final ingredient = Ingredient.fromJson(mealItemData['ingredient_obj']); - if (mealItemData['image'] != null) { - final image = IngredientImage.fromJson(mealItemData['image']); - ingredient.image = image; - } - mealItem.ingredient = ingredient; + for (final mealItem in meal.mealItems) { + mealItem.ingredient = await fetchIngredient(mealItem.ingredientId); mealItems.add(mealItem); } meal.mealItems = mealItems; + meal.diaryEntries = diaryEntries.where((d) => d.mealId == meal.id).toList(); meals.add(meal); } - plan.meals = meals; - // Logs - await fetchAndSetLogs(plan); - for (final meal in meals) { - meal.diaryEntries = plan.diaryEntries.where((e) => e.mealId == meal.id).toList(); - } + plan.meals = meals; + plan.diaryEntries = diaryEntries; - // ... and done - notifyListeners(); return plan; } + Stream watchNutritionPlan(String id) { + return NutritionalPlan.watchNutritionPlan(id).transform( + StreamTransformer.fromHandlers( + handleData: (plan, sink) async { + if (plan == null) { + sink.add(plan); + return; + } + sink.add(await _enrichPlan(plan)); + }, + ), + ); + } + + Stream watchNutritionPlanLast() { + return NutritionalPlan.watchNutritionPlanLast().transform( + StreamTransformer.fromHandlers( + handleData: (plan, sink) async { + if (plan == null) { + return; + } + sink.add(await _enrichPlan(plan)); + }, + ), + ); + } + + Stream> watchNutritionPlans() { + return NutritionalPlan.watchNutritionPlans().transform( + StreamTransformer.fromHandlers( + handleData: (plans, sink) async { + sink.add(await Future.wait(plans.map((plan) => _enrichPlan(plan)))); + }, + ), + ); + } + /* +TODO implement: + ingredient.image = image; + mealItem.ingredient = ingredient; + + */ + Future addPlan(NutritionalPlan planData) async { final data = await baseProvider.post( planData.toJson(), @@ -226,7 +210,8 @@ class NutritionPlansProvider with ChangeNotifier { } /// Adds a meal to a plan - Future addMeal(Meal meal, int planId) async { + Future addMeal(Meal meal, String planId) async { + /* final plan = findById(planId); final data = await baseProvider.post(meal.toJson(), baseProvider.makeUrl(_mealPath)); @@ -235,10 +220,13 @@ class NutritionPlansProvider with ChangeNotifier { notifyListeners(); return meal; + */ + return meal; } /// Edits an existing meal Future editMeal(Meal meal) async { + /* final data = await baseProvider.patch( meal.toJson(), baseProvider.makeUrl(_mealPath, id: meal.id), @@ -246,6 +234,7 @@ class NutritionPlansProvider with ChangeNotifier { meal = Meal.fromJson(data); notifyListeners(); + */ return meal; } @@ -438,6 +427,7 @@ class NutritionPlansProvider with ChangeNotifier { /// Log meal to nutrition diary Future logMealToDiary(Meal meal, DateTime mealDateTime) async { + /* for (final item in meal.mealItems) { final plan = findById(meal.planId); final Log log = Log.fromMealItem(item, plan.id!, meal.id, mealDateTime); @@ -447,10 +437,15 @@ class NutritionPlansProvider with ChangeNotifier { plan.diaryEntries.add(log); } notifyListeners(); + */ } /// Log custom ingredient to nutrition diary - Future logIngredientToDiary(MealItem mealItem, int planId, [DateTime? dateTime]) async { + Future logIngredientToDiary(MealItem mealItem, String planId, [DateTime? dateTime]) async { + print( + 'DIETER logIngredientToDiary called ingredient=${mealItem.ingredientId}, planId=$planId, dateTime=$dateTime', + ); + /* final plan = findById(planId); mealItem.ingredient = await fetchIngredient(mealItem.ingredientId); final log = Log.fromMealItem(mealItem, plan.id!, null, dateTime); @@ -458,16 +453,20 @@ class NutritionPlansProvider with ChangeNotifier { final data = await baseProvider.post(log.toJson(), baseProvider.makeUrl(_nutritionDiaryPath)); log.id = data['id']; plan.diaryEntries.add(log); + + */ notifyListeners(); } /// Deletes a log entry - Future deleteLog(int logId, int planId) async { + Future deleteLog(String logId, String planId) async { + /* await baseProvider.deleteRequest(_nutritionDiaryPath, logId); final plan = findById(planId); plan.diaryEntries.removeWhere((element) => element.id == logId); notifyListeners(); + */ } /// Load nutrition diary entries for plan diff --git a/lib/screens/auth_screen.dart b/lib/screens/auth_screen.dart index aaa55e46a..5dd5ad730 100644 --- a/lib/screens/auth_screen.dart +++ b/lib/screens/auth_screen.dart @@ -54,10 +54,7 @@ class AuthScreen extends StatelessWidget { top: 0, right: 0, left: 0, - child: Container( - height: 0.55 * deviceSize.height, - color: wgerPrimaryColor, - ), + child: Container(height: 0.55 * deviceSize.height, color: wgerPrimaryColor), ), SingleChildScrollView( child: SizedBox( @@ -68,16 +65,10 @@ class AuthScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 0.15 * deviceSize.height), - const Image( - image: AssetImage('assets/images/logo-white.png'), - width: 85, - ), + const Image(image: AssetImage('assets/images/logo-white.png'), width: 85), Container( margin: const EdgeInsets.only(bottom: 20.0), - padding: const EdgeInsets.symmetric( - vertical: 8.0, - horizontal: 94.0, - ), + padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 94.0), child: const Text( 'wger', style: TextStyle( @@ -245,16 +236,11 @@ class _AuthCardState extends State { final deviceSize = MediaQuery.sizeOf(context); return Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15.0), - ), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15.0)), elevation: 8.0, child: Container( width: deviceSize.width * 0.9, - padding: EdgeInsets.symmetric( - horizontal: 15.0, - vertical: 0.025 * deviceSize.height, - ), + padding: EdgeInsets.symmetric(horizontal: 15.0, vertical: 0.025 * deviceSize.height), child: Form( key: _formKey, child: SingleChildScrollView( @@ -387,13 +373,7 @@ class _AuthCardState extends State { children: [ // TODO: i18n! Text( - text.substring(0, text.lastIndexOf('?') + 1), - ), - Text( - text.substring( - text.lastIndexOf('?') + 1, - text.length, - ), + text.substring(text.lastIndexOf('?') + 1, text.length), style: const TextStyle( //color: wgerPrimaryColor, fontWeight: FontWeight.w700, diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index 56a8e5b9b..f232e4a65 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2026 wger Team + * Copyright (c) 2020 - 2026 wger Team * * wger Workout Manager is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/lib/screens/home_tabs_screen.dart b/lib/screens/home_tabs_screen.dart index 10de168f7..91126cdf7 100644 --- a/lib/screens/home_tabs_screen.dart +++ b/lib/screens/home_tabs_screen.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2026 wger Team + * Copyright (c) 2020 - 2026 wger Team * * wger Workout Manager is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -24,6 +24,7 @@ import 'package:provider/provider.dart'; import 'package:rive/rive.dart'; import 'package:wger/helpers/material.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; +import 'package:wger/powersync.dart'; import 'package:wger/providers/auth.dart'; import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/exercises.dart'; @@ -57,6 +58,14 @@ class _HomeTabsScreenState extends ConsumerState int _selectedIndex = 0; bool _isWideScreen = false; + @override + void initState() { + super.initState(); + + // do we need to await this? or if it's async, how do we handle failures? + _setupPowersync(); + } + @override void didChangeDependencies() { super.didChangeDependencies(); @@ -80,6 +89,25 @@ class _HomeTabsScreenState extends ConsumerState const GalleryScreen(), ]; + Future _setupPowersync() async { + final authProvider = context.read(); + final baseUrl = authProvider.serverUrl!; + final powerSyncUrl = baseUrl.replaceAll(':8000', ':8080'); + + await openDatabase(false, baseUrl, powerSyncUrl); + + final connector = DjangoConnector(db, baseUrl, powerSyncUrl); + try { + // TODO: should we cache these credentials? that's what their demo does? + // we could maybe get the initial token from the /api/v2/login call + final credentials = await connector.fetchCredentials(); + print('fetched credentials' + credentials.toString()); + await openDatabase(true, baseUrl, powerSyncUrl); + } catch (e) { + print('failed to fetchCredentials()' + e.toString()); + } + } + /// Load initial data from the server Future _loadEntries() async { final languageCode = Localizations.localeOf(context).languageCode; @@ -121,7 +149,7 @@ class _HomeTabsScreenState extends ConsumerState widget._logger.info('Loading routines, weight, measurements and gallery'); await Future.wait([ galleryProvider.fetchAndSetGallery(), - nutritionPlansProvider.fetchAndSetAllPlansSparse(), + // nutritionPlansProvider.fetchAndSetAllPlansSparse(), routinesProvider.fetchAndSetAllRoutinesSparse(), // routinesProvider.fetchAndSetAllRoutinesFull(), weightProvider.fetchAndSetEntries(), @@ -131,11 +159,11 @@ class _HomeTabsScreenState extends ConsumerState // // Current nutritional plan - widget._logger.info('Loading current nutritional plan'); - if (nutritionPlansProvider.currentPlan != null) { - final plan = nutritionPlansProvider.currentPlan!; - await nutritionPlansProvider.fetchAndSetPlanFull(plan.id!); - } + // widget._logger.info('Loading current nutritional plan'); + // if (nutritionPlansProvider.currentPlan != null) { + // final plan = nutritionPlansProvider.currentPlan!; + // await nutritionPlansProvider.fetchAndSetPlanFull(plan.id!); + // } // // Current routine diff --git a/lib/screens/measurement_entries_screen.dart b/lib/screens/measurement_entries_screen.dart index 3f30ed3e3..327d9316c 100644 --- a/lib/screens/measurement_entries_screen.dart +++ b/lib/screens/measurement_entries_screen.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2025 wger Team + * Copyright (c) 2020 - 2025 wger Team * * wger Workout Manager is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -27,10 +27,7 @@ import 'package:wger/screens/form_screen.dart'; import 'package:wger/widgets/measurements/entries.dart'; import 'package:wger/widgets/measurements/forms.dart'; -enum MeasurementOptions { - edit, - delete, -} +enum MeasurementOptions { edit, delete } class MeasurementEntriesScreen extends StatelessWidget { const MeasurementEntriesScreen(); @@ -89,9 +86,7 @@ class MeasurementEntriesScreen extends StatelessWidget { TextButton( child: Text( AppLocalizations.of(context).delete, - style: TextStyle( - color: Theme.of(context).colorScheme.error, - ), + style: TextStyle(color: Theme.of(context).colorScheme.error), ), onPressed: () { // Confirmed, delete the workout diff --git a/lib/screens/nutritional_diary_screen.dart b/lib/screens/nutritional_diary_screen.dart index 11ad28a0e..6be709bc4 100644 --- a/lib/screens/nutritional_diary_screen.dart +++ b/lib/screens/nutritional_diary_screen.dart @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; @@ -27,32 +29,59 @@ import 'package:wger/widgets/nutrition/nutritional_diary_detail.dart'; /// Arguments passed to the form screen class NutritionalDiaryArguments { /// Nutritional plan - final NutritionalPlan plan; + final String planId; /// Date to show data for final DateTime date; - const NutritionalDiaryArguments(this.plan, this.date); + const NutritionalDiaryArguments(this.planId, this.date); } -class NutritionalDiaryScreen extends StatelessWidget { +class NutritionalDiaryScreen extends StatefulWidget { const NutritionalDiaryScreen(); static const routeName = '/nutritional-diary'; @override - Widget build(BuildContext context) { + State createState() => _NutritionalDiaryScreenState(); +} + +class _NutritionalDiaryScreenState extends State { + NutritionalPlan? _plan; + late DateTime date; + StreamSubscription? _subscription; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); final args = ModalRoute.of(context)!.settings.arguments as NutritionalDiaryArguments; + date = args.date; + + final stream = Provider.of( + context, + listen: false, + ).watchNutritionPlan(args.planId); + _subscription = stream.listen((plan) { + if (!context.mounted) { + return; + } + setState(() { + _plan = plan; + }); + }); + } + @override + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(DateFormat.yMd(Localizations.localeOf(context).languageCode).format(args.date)), + title: Text(DateFormat.yMd(Localizations.localeOf(context).languageCode).format(date)), ), body: WidescreenWrapper( child: Consumer( builder: (context, nutritionProvider, child) => SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(8.0), - child: NutritionalDiaryDetailWidget(args.plan, args.date), + child: NutritionalDiaryDetailWidget(_plan!, date), ), ), ), diff --git a/lib/screens/nutritional_plan_screen.dart b/lib/screens/nutritional_plan_screen.dart index b22082235..78552a20c 100644 --- a/lib/screens/nutritional_plan_screen.dart +++ b/lib/screens/nutritional_plan_screen.dart @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_svg_icons/flutter_svg_icons.dart'; import 'package:provider/provider.dart'; @@ -27,165 +29,196 @@ import 'package:wger/screens/log_meals_screen.dart'; import 'package:wger/widgets/nutrition/forms.dart'; import 'package:wger/widgets/nutrition/nutritional_plan_detail.dart'; -enum NutritionalPlanOptions { - edit, - delete, -} +enum NutritionalPlanOptions { edit, delete } -class NutritionalPlanScreen extends StatelessWidget { +class NutritionalPlanScreen extends StatefulWidget { const NutritionalPlanScreen(); static const routeName = '/nutritional-plan-detail'; - Future _loadFullPlan(BuildContext context, int planId) { - return Provider.of(context, listen: false).fetchAndSetPlanFull(planId); + @override + _NutritionalPlanScreenState createState() => _NutritionalPlanScreenState(); +} + +class _NutritionalPlanScreenState extends State { + NutritionalPlan? _plan; + StreamSubscription? _subscription; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final id = ModalRoute.of(context)!.settings.arguments as String; + //final id = 111; + + final stream = Provider.of( + context, + listen: false, + ).watchNutritionPlan(id); + _subscription = stream.listen((plan) { + if (!context.mounted) { + return; + } + setState(() { + _plan = plan; + }); + }); + } + + @override + void dispose() { + _subscription?.cancel(); + super.dispose(); } @override Widget build(BuildContext context) { const appBarForeground = Colors.white; - final nutritionalPlan = ModalRoute.of(context)!.settings.arguments as NutritionalPlan; return Scaffold( //appBar: getAppBar(nutritionalPlan), floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - FloatingActionButton( - heroTag: null, - tooltip: AppLocalizations.of(context).logIngredient, - onPressed: () { - Navigator.pushNamed( - context, - FormScreen.routeName, - arguments: FormScreenArguments( - AppLocalizations.of(context).logIngredient, - getIngredientLogForm(nutritionalPlan), - hasListView: true, - ), - ); - }, - child: const SvgIcon( - icon: SvgIconData('assets/icons/ingredient-diary.svg'), - color: Colors.white, + if (_plan != null) + FloatingActionButton( + heroTag: null, + tooltip: AppLocalizations.of(context).logIngredient, + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).logIngredient, + getIngredientLogForm(_plan!), + hasListView: true, + ), + ); + }, + child: const SvgIcon( + icon: SvgIconData('assets/icons/ingredient-diary.svg'), + color: Colors.white, + ), ), - ), const SizedBox(width: 8), - FloatingActionButton( - heroTag: null, - tooltip: AppLocalizations.of(context).logMeal, - onPressed: () { - Navigator.of(context).pushNamed( - LogMealsScreen.routeName, - arguments: nutritionalPlan, - ); - }, - child: const SvgIcon( - icon: SvgIconData('assets/icons/meal-diary.svg'), - color: Colors.white, + if (_plan != null) + FloatingActionButton( + heroTag: null, + tooltip: AppLocalizations.of(context).logMeal, + onPressed: () { + Navigator.of(context).pushNamed( + LogMealsScreen.routeName, + arguments: _plan, + ); + }, + child: const SvgIcon( + icon: SvgIconData('assets/icons/meal-diary.svg'), + color: Colors.white, + ), ), - ), ], ), - body: CustomScrollView( - slivers: [ - SliverAppBar( - foregroundColor: appBarForeground, - pinned: true, - iconTheme: const IconThemeData(color: appBarForeground), - actions: [ - if (!nutritionalPlan.onlyLogging) - IconButton( - icon: const SvgIcon( - icon: SvgIconData('assets/icons/meal-add.svg'), - ), - onPressed: () { - Navigator.pushNamed( - context, - FormScreen.routeName, - arguments: FormScreenArguments( - AppLocalizations.of(context).addMeal, - MealForm(nutritionalPlan.id!), - ), - ); - }, - ), - PopupMenuButton( - icon: const Icon(Icons.more_vert, color: appBarForeground), - onSelected: (value) { - switch (value) { - case NutritionalPlanOptions.edit: - Navigator.pushNamed( - context, - FormScreen.routeName, - arguments: FormScreenArguments( - AppLocalizations.of(context).edit, - PlanForm(nutritionalPlan), - hasListView: true, + body: _plan == null + ? const Text('plan not found') + : CustomScrollView( + slivers: [ + SliverAppBar( + foregroundColor: appBarForeground, + pinned: true, + iconTheme: const IconThemeData(color: appBarForeground), + actions: [ + if (!_plan!.onlyLogging) + IconButton( + icon: const SvgIcon( + icon: SvgIconData('assets/icons/meal-add.svg'), ), - ); - break; - case NutritionalPlanOptions.delete: - Provider.of( - context, - listen: false, - ).deletePlan(nutritionalPlan.id!); - Navigator.of(context).pop(); - break; - } - }, - itemBuilder: (BuildContext context) { - return [ - PopupMenuItem( - value: NutritionalPlanOptions.edit, - child: ListTile( - leading: const Icon(Icons.edit), - title: Text(AppLocalizations.of(context).edit), + onPressed: () { + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).addMeal, + MealForm(_plan!.id!), + ), + ); + }, ), + PopupMenuButton( + icon: const Icon(Icons.more_vert, color: appBarForeground), + onSelected: (value) { + switch (value) { + case NutritionalPlanOptions.edit: + Navigator.pushNamed( + context, + FormScreen.routeName, + arguments: FormScreenArguments( + AppLocalizations.of(context).edit, + PlanForm(_plan), + hasListView: true, + ), + ); + break; + case NutritionalPlanOptions.delete: + Provider.of( + context, + listen: false, + ).deletePlan(_plan!.id!); + Navigator.of(context).pop(); + break; + } + }, + itemBuilder: (BuildContext context) { + return [ + PopupMenuItem( + value: NutritionalPlanOptions.edit, + child: ListTile( + leading: const Icon(Icons.edit), + title: Text(AppLocalizations.of(context).edit), + ), + ), + const PopupMenuDivider(), + PopupMenuItem( + value: NutritionalPlanOptions.delete, + child: ListTile( + leading: const Icon(Icons.delete), + title: Text(AppLocalizations.of(context).delete), + ), + ), + ]; + }, ), - const PopupMenuDivider(), - PopupMenuItem( - value: NutritionalPlanOptions.delete, - child: ListTile( - leading: const Icon(Icons.delete), - title: Text(AppLocalizations.of(context).delete), - ), + ], + flexibleSpace: FlexibleSpaceBar( + titlePadding: const EdgeInsets.fromLTRB(56, 0, 56, 16), + title: Text( + _plan!.getLabel(context), + style: Theme.of( + context, + ).textTheme.titleLarge?.copyWith(color: appBarForeground), ), - ]; - }, - ), - ], - flexibleSpace: FlexibleSpaceBar( - titlePadding: const EdgeInsets.fromLTRB(56, 0, 56, 16), - title: Text( - nutritionalPlan.getLabel(context), - style: Theme.of(context).textTheme.titleLarge?.copyWith(color: appBarForeground), - ), - ), - ), - FutureBuilder( - future: _loadFullPlan(context, nutritionalPlan.id!), - builder: (context, AsyncSnapshot snapshot) => - snapshot.connectionState == ConnectionState.waiting - ? SliverList( - delegate: SliverChildListDelegate( - [ - const SizedBox( - height: 200, - child: Center( - child: CircularProgressIndicator(), + ), + ), + FutureBuilder( + future: NutritionalPlan.read(_plan!.id!), + builder: (context, AsyncSnapshot snapshot) => + snapshot.connectionState == ConnectionState.waiting + ? SliverList( + delegate: SliverChildListDelegate( + [ + const SizedBox( + height: 200, + child: Center( + child: CircularProgressIndicator(), + ), + ), + ], ), + ) + : Consumer( + builder: (context, value, child) => NutritionalPlanDetailWidget(_plan!), ), - ], - ), - ) - : Consumer( - builder: (context, value, child) => - NutritionalPlanDetailWidget(nutritionalPlan), - ), - ), - ], - ), + ), + ], + ), ); } } diff --git a/lib/screens/nutritional_plans_screen.dart b/lib/screens/nutritional_plans_screen.dart index d070b1c0c..0fba3d5b5 100644 --- a/lib/screens/nutritional_plans_screen.dart +++ b/lib/screens/nutritional_plans_screen.dart @@ -51,7 +51,7 @@ class NutritionalPlansScreen extends StatelessWidget { ), body: WidescreenWrapper( child: Consumer( - builder: (context, nutritionProvider, child) => NutritionalPlansList(nutritionProvider), + builder: (context, nutritionProvider, child) => NutritionalPlansList(), ), ), ); diff --git a/lib/widgets/core/app_bar.dart b/lib/widgets/core/app_bar.dart index be52f0638..3345d39b7 100644 --- a/lib/widgets/core/app_bar.dart +++ b/lib/widgets/core/app_bar.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2026 wger Team + * Copyright (c) 2020 - 2026 wger Team * * wger Workout Manager is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/lib/widgets/exercises/filter_row.dart b/lib/widgets/exercises/filter_row.dart index fdfc88094..0106f08d7 100644 --- a/lib/widgets/exercises/filter_row.dart +++ b/lib/widgets/exercises/filter_row.dart @@ -59,9 +59,7 @@ class _FilterRowState extends State { decoration: InputDecoration( hintText: '${AppLocalizations.of(context).exerciseName}...', contentPadding: const EdgeInsets.symmetric(horizontal: 10), - border: const OutlineInputBorder( - borderSide: BorderSide(color: Colors.black), - ), + border: const OutlineInputBorder(borderSide: BorderSide(color: Colors.black)), ), ), ), diff --git a/lib/widgets/gallery/forms.dart b/lib/widgets/gallery/forms.dart index a2d6a8e81..1e8f977ec 100644 --- a/lib/widgets/gallery/forms.dart +++ b/lib/widgets/gallery/forms.dart @@ -131,9 +131,7 @@ class _ImageFormState extends State { _showPicker(ImageSource.gallery); }, leading: const Icon(Icons.photo_library), - title: Text( - AppLocalizations.of(context).chooseFromLibrary, - ), + title: Text(AppLocalizations.of(context).chooseFromLibrary), ), ], ), @@ -181,9 +179,7 @@ class _ImageFormState extends State { ), TextFormField( key: const Key('field-description'), - decoration: InputDecoration( - labelText: AppLocalizations.of(context).description, - ), + decoration: InputDecoration(labelText: AppLocalizations.of(context).description), minLines: 3, maxLines: 10, controller: descriptionController, diff --git a/lib/widgets/measurements/helpers.dart b/lib/widgets/measurements/helpers.dart index 00369b06d..bc8954dae 100644 --- a/lib/widgets/measurements/helpers.dart +++ b/lib/widgets/measurements/helpers.dart @@ -12,11 +12,7 @@ List getOverviewWidgets( BuildContext context, ) { return [ - Text( - title, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleLarge, - ), + Text(title, textAlign: TextAlign.center, style: Theme.of(context).textTheme.titleLarge), Container( padding: const EdgeInsets.all(15), height: 220, diff --git a/lib/widgets/nutrition/forms.dart b/lib/widgets/nutrition/forms.dart index c3c917a8b..f6d84557c 100644 --- a/lib/widgets/nutrition/forms.dart +++ b/lib/widgets/nutrition/forms.dart @@ -35,7 +35,7 @@ import 'package:wger/widgets/nutrition/widgets.dart'; class MealForm extends StatelessWidget { late final Meal _meal; - final int _planId; + final String _planId; final _form = GlobalKey(); final _timeController = TextEditingController(); @@ -64,10 +64,7 @@ class MealForm extends StatelessWidget { FocusScope.of(context).requestFocus(FocusNode()); // Open time picker - final pickedTime = await showTimePicker( - context: context, - initialTime: _meal.time!, - ); + final pickedTime = await showTimePicker(context: context, initialTime: _meal.time!); if (pickedTime != null) { _timeController.text = timeToString(pickedTime)!; } @@ -122,7 +119,7 @@ Widget getMealItemForm( ]) { return IngredientForm( // TODO we use planId 0 here cause we don't have one and we don't need it I think? - recent: recent.map((e) => Log.fromMealItem(e, 0, e.mealId)).toList(), + recent: recent.map((e) => Log.fromMealItem(e, '0', e.mealId)).toList(), onSave: (BuildContext context, MealItem mealItem, DateTime? dt) { mealItem.mealId = meal.id!; Provider.of(context, listen: false).addMealItem(mealItem, meal); @@ -143,10 +140,7 @@ Widget getIngredientLogForm(NutritionalPlan plan) { ).logIngredientToDiary(mealItem, plan.id!, dt); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text( - AppLocalizations.of(context).ingredientLogged, - textAlign: TextAlign.center, - ), + content: Text(AppLocalizations.of(context).ingredientLogged, textAlign: TextAlign.center), ), ); }, @@ -426,11 +420,7 @@ class IngredientFormState extends State { itemBuilder: (context, index) { void select() { final ingredient = suggestions[index].ingredient; - selectIngredient( - ingredient.id, - ingredient.name, - suggestions[index].amount, - ); + selectIngredient(ingredient.id, ingredient.name, suggestions[index].amount); } return Card( diff --git a/lib/widgets/nutrition/ingredient_dialogs.dart b/lib/widgets/nutrition/ingredient_dialogs.dart index b918b3607..7c79d533a 100644 --- a/lib/widgets/nutrition/ingredient_dialogs.dart +++ b/lib/widgets/nutrition/ingredient_dialogs.dart @@ -194,9 +194,7 @@ class IngredientScanResultDialog extends StatelessWidget { if (snapshot.connectionState == ConnectionState.done && ingredient == null) Padding( padding: const EdgeInsets.only(bottom: 8.0), - child: Text( - AppLocalizations.of(context).productNotFoundDescription(barcode), - ), + child: Text(AppLocalizations.of(context).productNotFoundDescription(barcode)), ), if (ingredient != null) Padding( diff --git a/lib/widgets/nutrition/macro_nutrients_table.dart b/lib/widgets/nutrition/macro_nutrients_table.dart index 7a1bfc62d..9226f7a40 100644 --- a/lib/widgets/nutrition/macro_nutrients_table.dart +++ b/lib/widgets/nutrition/macro_nutrients_table.dart @@ -53,10 +53,7 @@ class MacronutrientsTable extends StatelessWidget { return Table( defaultVerticalAlignment: TableCellVerticalAlignment.middle, border: TableBorder( - horizontalInside: BorderSide( - width: 1, - color: Theme.of(context).colorScheme.outline, - ), + horizontalInside: BorderSide(width: 1, color: Theme.of(context).colorScheme.outline), ), columnWidths: const {0: FractionColumnWidth(0.4)}, children: [ diff --git a/lib/widgets/nutrition/meal.dart b/lib/widgets/nutrition/meal.dart index 4ba99cf63..bf3a715b3 100644 --- a/lib/widgets/nutrition/meal.dart +++ b/lib/widgets/nutrition/meal.dart @@ -45,12 +45,7 @@ class MealWidget extends StatefulWidget { final bool popTwice; final bool readOnly; - const MealWidget( - this._meal, - this._recentMealItems, - this.popTwice, - this.readOnly, - ); + const MealWidget(this._meal, this._recentMealItems, this.popTwice, this.readOnly); @override _MealWidgetState createState() => _MealWidgetState(); diff --git a/lib/widgets/nutrition/nutrition_tiles.dart b/lib/widgets/nutrition/nutrition_tiles.dart index 36f20155b..2d72b1b95 100644 --- a/lib/widgets/nutrition/nutrition_tiles.dart +++ b/lib/widgets/nutrition/nutrition_tiles.dart @@ -18,11 +18,7 @@ class MealItemValuesTile extends StatelessWidget { final Ingredient ingredient; final NutritionalValues nutritionalValues; - const MealItemValuesTile({ - super.key, - required this.ingredient, - required this.nutritionalValues, - }); + const MealItemValuesTile({super.key, required this.ingredient, required this.nutritionalValues}); @override Widget build(BuildContext context) { @@ -53,11 +49,7 @@ class DiaryheaderTile extends StatelessWidget { /// a NutritionTitle showing diary entries class DiaryEntryTile extends StatelessWidget { - const DiaryEntryTile({ - super.key, - required this.diaryEntry, - this.nutritionalPlan, - }); + const DiaryEntryTile({super.key, required this.diaryEntry, this.nutritionalPlan}); final Log diaryEntry; final NutritionalPlan? nutritionalPlan; diff --git a/lib/widgets/nutrition/nutritional_diary_detail.dart b/lib/widgets/nutrition/nutritional_diary_detail.dart index 3da5beaf1..3b2ceb720 100644 --- a/lib/widgets/nutrition/nutritional_diary_detail.dart +++ b/lib/widgets/nutrition/nutritional_diary_detail.dart @@ -61,20 +61,14 @@ class NutritionalDiaryDetailWidget extends StatelessWidget { ), const SizedBox(height: 15), const DiaryheaderTile(), - ...logs.map( - (e) => DiaryEntryTile(diaryEntry: e, nutritionalPlan: _nutritionalPlan), - ), + ...logs.map((e) => DiaryEntryTile(diaryEntry: e, nutritionalPlan: _nutritionalPlan)), ], ); } } class NutritionDiaryTable extends StatelessWidget { - const NutritionDiaryTable({ - super.key, - required this.planned, - required this.logged, - }); + const NutritionDiaryTable({super.key, required this.planned, required this.logged}); static const double tablePadding = 7; final NutritionalValues planned; diff --git a/lib/widgets/nutrition/nutritional_diary_table.dart b/lib/widgets/nutrition/nutritional_diary_table.dart index d00a6f2f0..03365d9f7 100644 --- a/lib/widgets/nutrition/nutritional_diary_table.dart +++ b/lib/widgets/nutrition/nutritional_diary_table.dart @@ -8,10 +8,8 @@ import 'package:wger/models/nutrition/nutritional_values.dart'; import 'package:wger/screens/nutritional_diary_screen.dart'; class NutritionalDiaryTable extends StatelessWidget { - const NutritionalDiaryTable({ - super.key, - required NutritionalPlan nutritionalPlan, - }) : plan = nutritionalPlan; + const NutritionalDiaryTable({super.key, required NutritionalPlan nutritionalPlan}) + : plan = nutritionalPlan; final NutritionalPlan plan; @@ -115,7 +113,7 @@ class NutritionalDiaryTable extends StatelessWidget { return GestureDetector( onTap: () => Navigator.of(context).pushNamed( NutritionalDiaryScreen.routeName, - arguments: NutritionalDiaryArguments(plan, date), + arguments: NutritionalDiaryArguments(plan.id!, date), ), child: element, ); diff --git a/lib/widgets/nutrition/nutritional_plans_list.dart b/lib/widgets/nutrition/nutritional_plans_list.dart index 3c9d0e95e..7a79f1133 100644 --- a/lib/widgets/nutrition/nutritional_plans_list.dart +++ b/lib/widgets/nutrition/nutritional_plans_list.dart @@ -16,11 +16,14 @@ * along with this program. If not, see . */ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:wger/helpers/measurements.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; +import 'package:wger/models/nutrition/nutritional_plan.dart'; import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/nutrition.dart'; import 'package:wger/providers/user.dart'; @@ -28,10 +31,37 @@ import 'package:wger/screens/nutritional_plan_screen.dart'; import 'package:wger/widgets/core/text_prompt.dart'; import 'package:wger/widgets/measurements/charts.dart'; -class NutritionalPlansList extends StatelessWidget { - final NutritionPlansProvider _nutritionProvider; +class NutritionalPlansList extends StatefulWidget { + @override + _NutritionalPlansListState createState() => _NutritionalPlansListState(); +} + +class _NutritionalPlansListState extends State { + List _plans = []; + StreamSubscription? _subscription; - const NutritionalPlansList(this._nutritionProvider); + @override + void initState() { + super.initState(); + final stream = Provider.of( + context, + listen: false, + ).watchNutritionPlans(); + _subscription = stream.listen((plans) { + if (!context.mounted) { + return; + } + setState(() { + _plans = plans; + }); + }); + } + + @override + void dispose() { + _subscription?.cancel(); + super.dispose(); + } /// Builds the weight change information for a nutritional plan period Widget _buildWeightChangeInfo(BuildContext context, DateTime startDate, DateTime? endDate) { @@ -88,103 +118,102 @@ class NutritionalPlansList extends StatelessWidget { @override Widget build(BuildContext context) { - return RefreshIndicator( - onRefresh: () => _nutritionProvider.fetchAndSetAllPlansSparse(), - child: _nutritionProvider.items.isEmpty - ? const TextPrompt() - : ListView.builder( - padding: const EdgeInsets.all(10.0), - itemCount: _nutritionProvider.items.length, - itemBuilder: (context, index) { - final currentPlan = _nutritionProvider.items[index]; - return Card( - child: ListTile( - onTap: () { - Navigator.of(context).pushNamed( - NutritionalPlanScreen.routeName, - arguments: currentPlan, - ); - }, - title: Text(currentPlan.getLabel(context)), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - currentPlan.endDate != null - ? 'from ${DateFormat.yMd( - Localizations.localeOf(context).languageCode, - ).format(currentPlan.startDate)} to ${DateFormat.yMd( - Localizations.localeOf(context).languageCode, - ).format(currentPlan.endDate!)}' - : 'from ${DateFormat.yMd( - Localizations.localeOf(context).languageCode, - ).format(currentPlan.startDate)} (open ended)', - ), - _buildWeightChangeInfo(context, currentPlan.startDate, currentPlan.endDate), - ], - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const VerticalDivider(), - IconButton( - icon: const Icon(Icons.delete), - tooltip: AppLocalizations.of(context).delete, - onPressed: () async { - // Delete the plan from DB - await showDialog( - context: context, - builder: (BuildContext contextDialog) { - return AlertDialog( - content: Text( - AppLocalizations.of( - context, - ).confirmDelete(currentPlan.description), + final nutritionProvider = Provider.of(context); + + return _plans.isEmpty + ? const TextPrompt() + : ListView.builder( + padding: const EdgeInsets.all(10.0), + itemCount: _plans.length, + itemBuilder: (context, index) { + final currentPlan = _plans[index]; + return Card( + child: ListTile( + onTap: () { + Navigator.of(context).pushNamed( + NutritionalPlanScreen.routeName, + arguments: currentPlan, + ); + }, + title: Text(currentPlan.getLabel(context)), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + currentPlan.endDate != null + ? 'from ${DateFormat.yMd( + Localizations.localeOf(context).languageCode, + ).format(currentPlan.startDate)} to ${DateFormat.yMd( + Localizations.localeOf(context).languageCode, + ).format(currentPlan.endDate!)}' + : 'from ${DateFormat.yMd( + Localizations.localeOf(context).languageCode, + ).format(currentPlan.startDate)} (open ended)', + ), + _buildWeightChangeInfo(context, currentPlan.startDate, currentPlan.endDate), + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const VerticalDivider(), + IconButton( + icon: const Icon(Icons.delete), + tooltip: AppLocalizations.of(context).delete, + onPressed: () async { + // Delete the plan from DB + await showDialog( + context: context, + builder: (BuildContext contextDialog) { + return AlertDialog( + content: Text( + AppLocalizations.of( + context, + ).confirmDelete(currentPlan.description), + ), + actions: [ + TextButton( + child: Text( + MaterialLocalizations.of(context).cancelButtonLabel, + ), + onPressed: () => Navigator.of(contextDialog).pop(), ), - actions: [ - TextButton( - child: Text( - MaterialLocalizations.of(context).cancelButtonLabel, + TextButton( + child: Text( + AppLocalizations.of(context).delete, + style: TextStyle( + color: Theme.of(context).colorScheme.error, ), - onPressed: () => Navigator.of(contextDialog).pop(), ), - TextButton( - child: Text( - AppLocalizations.of(context).delete, - style: TextStyle( - color: Theme.of(context).colorScheme.error, - ), - ), - onPressed: () { - // Confirmed, delete the plan - _nutritionProvider.deletePlan(currentPlan.id!); - - // Close the popup - Navigator.of(contextDialog).pop(); - - // and inform the user - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - AppLocalizations.of(context).successfullyDeleted, - textAlign: TextAlign.center, - ), + onPressed: () { + // Confirmed, delete the plan + nutritionProvider.deletePlan(currentPlan.id!); + + // Close the popup + Navigator.of(contextDialog).pop(); + + // and inform the user + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + AppLocalizations.of(context).successfullyDeleted, + textAlign: TextAlign.center, ), - ); - }, - ), - ], - ); - }, - ); - }, - ), - ], - ), + ), + ); + }, + ), + ], + ); + }, + ); + }, + ), + ], ), - ); - }, - ), - ); + ), + ); + }, + ); } } diff --git a/lib/widgets/routines/gym_mode/navigation.dart b/lib/widgets/routines/gym_mode/navigation.dart index 9639c3d05..f770ae88f 100644 --- a/lib/widgets/routines/gym_mode/navigation.dart +++ b/lib/widgets/routines/gym_mode/navigation.dart @@ -1,6 +1,6 @@ /* * This file is part of wger Workout Manager . - * Copyright (c) 2026 wger Team + * Copyright (c) 2020 - 2026 wger Team * * wger Workout Manager is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by diff --git a/lib/widgets/user/forms.dart b/lib/widgets/user/forms.dart index 1ed19191e..66a3e3a93 100644 --- a/lib/widgets/user/forms.dart +++ b/lib/widgets/user/forms.dart @@ -132,9 +132,7 @@ class _UserProfileFormState extends State { context.read().saveProfile(); Navigator.of(context).pop(); ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(AppLocalizations.of(context).successfullySaved), - ), + SnackBar(content: Text(AppLocalizations.of(context).successfullySaved)), ); }, child: Text(AppLocalizations.of(context).save), diff --git a/lib/widgets/weight/forms.dart b/lib/widgets/weight/forms.dart index c3e182554..c7dbe00ad 100644 --- a/lib/widgets/weight/forms.dart +++ b/lib/widgets/weight/forms.dart @@ -62,10 +62,7 @@ class WeightForm extends StatelessWidget { readOnly: true, decoration: InputDecoration( labelText: AppLocalizations.of(context).date, - suffixIcon: const Icon( - Icons.calendar_today, - key: Key('calendarIcon'), - ), + suffixIcon: const Icon(Icons.calendar_today, key: Key('calendarIcon')), ), enableInteractiveSelection: false, controller: dateController, diff --git a/lib/widgets/weight/weight_overview.dart b/lib/widgets/weight/weight_overview.dart index f6f9050ea..caecfd210 100644 --- a/lib/widgets/weight/weight_overview.dart +++ b/lib/widgets/weight/weight_overview.dart @@ -56,10 +56,7 @@ class WeightOverview extends StatelessWidget { context, ), TextButton( - onPressed: () => Navigator.pushNamed( - context, - MeasurementCategoriesScreen.routeName, - ), + onPressed: () => Navigator.pushNamed(context, MeasurementCategoriesScreen.routeName), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index a30d39a62..b84c55f03 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -15,6 +16,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) powersync_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "PowersyncFlutterLibsPlugin"); + powersync_flutter_libs_plugin_register_with_registrar(powersync_flutter_libs_registrar); g_autoptr(FlPluginRegistrar) rive_common_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "RivePlugin"); rive_plugin_register_with_registrar(rive_common_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index bec164056..122005a4d 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_linux + powersync_flutter_libs rive_common sqlite3_flutter_libs url_launcher_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 06cb02d8d..20619c357 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,6 +7,8 @@ import Foundation import file_selector_macos import package_info_plus +import path_provider_foundation +import powersync_flutter_libs import rive_common import shared_preferences_foundation import sqlite3_flutter_libs @@ -16,6 +18,8 @@ import video_player_avfoundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + PowersyncFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "PowersyncFlutterLibsPlugin")) RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) diff --git a/pubspec.lock b/pubspec.lock index ab517cdbc..d5253a346 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d + sha256: f0bb5d1648339c8308cc0b9838d8456b3cfe5c91f9dc1a735b4d003269e5da9a url: "https://pub.dev" source: hosted - version: "91.0.0" + version: "88.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 + sha256: "0b7b9c329d2879f8f05d6c05b32ee9ec025f39b077864bdb5ac9a7b63418a98f" url: "https://pub.dev" source: hosted - version: "8.4.1" + version: "8.1.1" analyzer_buffer: dependency: transitive description: @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: archive - sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff + sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" url: "https://pub.dev" source: hosted - version: "4.0.9" + version: "4.0.7" args: dependency: transitive description: @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: build - sha256: "275bf6bb2a00a9852c28d4e0b410da1d833a734d57d39d44f94bfc895a484ec3" + sha256: "5b887c55a0f734b433b3b2d89f9cd1f99eb636b17e268a5b4259258bc916504b" url: "https://pub.dev" source: hosted - version: "4.0.4" + version: "4.0.0" build_config: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 + sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "4.0.4" build_runner: dependency: "direct dev" description: @@ -101,50 +101,50 @@ packages: dependency: transitive description: name: built_value - sha256: "7931c90b84bc573fef103548e354258ae4c9d28d140e41961df6843c5d60d4d8" + sha256: "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27" url: "https://pub.dev" source: hosted - version: "8.12.3" + version: "8.10.1" camera: dependency: transitive description: name: camera - sha256: "4142a19a38e388d3bab444227636610ba88982e36dff4552d5191a86f65dc437" + sha256: "413d2b34fe28496c35c69ede5b232fb9dd5ca2c3a4cb606b14efc1c7546cc8cb" url: "https://pub.dev" source: hosted - version: "0.11.4" + version: "0.11.1" camera_android_camerax: dependency: transitive description: name: camera_android_camerax - sha256: "8516fe308bc341a5067fb1a48edff0ddfa57c0d3cdcc9dbe7ceca3ba119e2577" + sha256: "9fb44e73e0fea3647a904dc26d38db24055e5b74fc68fd2b6d3abfa1bd20f536" url: "https://pub.dev" source: hosted - version: "0.6.30" + version: "0.6.17" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "11b4aee2f5e5e038982e152b4a342c749b414aa27857899d20f4323e94cb5f0b" + sha256: ca36181194f429eef3b09de3c96280f2400693f9735025f90d1f4a27465fdd72 url: "https://pub.dev" source: hosted - version: "0.9.23+2" + version: "0.9.19" camera_platform_interface: dependency: transitive description: name: camera_platform_interface - sha256: "98cfc9357e04bad617671b4c1f78a597f25f08003089dd94050709ae54effc63" + sha256: "2f757024a48696ff4814a789b0bd90f5660c0fb25f393ab4564fb483327930e2" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.10.0" camera_web: dependency: transitive description: name: camera_web - sha256: "57f49a635c8bf249d07fb95eb693d7e4dda6796dedb3777f9127fb54847beba7" + sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" url: "https://pub.dev" source: hosted - version: "0.3.5+3" + version: "0.3.5" carousel_slider: dependency: "direct main" description: @@ -181,10 +181,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.4" + version: "2.0.3" cider: dependency: "direct dev" description: @@ -217,22 +217,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" - code_assets: - dependency: transitive - description: - name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" - url: "https://pub.dev" - source: hosted - version: "1.0.0" code_builder: dependency: transitive description: name: code_builder - sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.11.1" + version: "4.10.1" collection: dependency: "direct main" description: @@ -261,18 +253,18 @@ packages: dependency: transitive description: name: cross_file - sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.5+2" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.0.6" csslib: dependency: transitive description: @@ -293,10 +285,10 @@ packages: dependency: transitive description: name: dart_style - sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b + sha256: c87dfe3d56f183ffe9106a18aebc6db431fc7c98c31a54b952a77f3d54a85697 url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.2" drift: dependency: "direct main" description: @@ -333,10 +325,10 @@ packages: dependency: transitive description: name: ffi - sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.1.4" file: dependency: transitive description: @@ -349,34 +341,34 @@ packages: dependency: transitive description: name: file_selector_linux - sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" url: "https://pub.dev" source: hosted - version: "0.9.4" + version: "0.9.3+2" file_selector_macos: dependency: transitive description: name: file_selector_macos - sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" url: "https://pub.dev" source: hosted - version: "0.9.5" + version: "0.9.4+2" file_selector_platform_interface: dependency: transitive description: name: file_selector_platform_interface - sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.6.2" file_selector_windows: dependency: transitive description: name: file_selector_windows - sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" url: "https://pub.dev" source: hosted - version: "0.9.3+5" + version: "0.9.3+4" fixnum: dependency: transitive description: @@ -492,10 +484,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e url: "https://pub.dev" source: hosted - version: "2.0.33" + version: "2.0.28" flutter_riverpod: dependency: "direct main" description: @@ -615,14 +607,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" - hooks: - dependency: transitive - description: - name: hooks - sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" html: dependency: transitive description: @@ -659,10 +643,10 @@ packages: dependency: transitive description: name: image - sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.5.4" image_picker: dependency: "direct main" description: @@ -675,26 +659,26 @@ packages: dependency: transitive description: name: image_picker_android - sha256: "518a16108529fc18657a3e6dde4a043dc465d16596d20ab2abd49a4cac2e703d" + sha256: e83b2b05141469c5e19d77e1dfa11096b6b1567d09065b2265d7c6904560050c url: "https://pub.dev" source: hosted - version: "0.8.13+13" + version: "0.8.13" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" + sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.0" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 + sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e url: "https://pub.dev" source: hosted - version: "0.8.13+6" + version: "0.8.13" image_picker_linux: dependency: transitive description: @@ -707,18 +691,18 @@ packages: dependency: transitive description: name: image_picker_macos - sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" + sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04 url: "https://pub.dev" source: hosted - version: "0.2.2+1" + version: "0.2.2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665" url: "https://pub.dev" source: hosted - version: "2.11.1" + version: "2.11.0" image_picker_windows: dependency: transitive description: @@ -800,10 +784,10 @@ packages: dependency: transitive description: name: lints - sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.0.0" list_counter: dependency: transitive description: @@ -872,10 +856,10 @@ packages: dependency: "direct dev" description: name: mockito - sha256: a45d1aa065b796922db7b9e7e7e45f921aed17adf3a8318a1f47097e7e695566 + sha256: "4feb43bc4eb6c03e832f5fcd637d1abb44b98f9cfa245c58e27382f58859f8f6" url: "https://pub.dev" source: hosted - version: "5.6.3" + version: "5.5.1" multi_select_flutter: dependency: "direct main" description: @@ -884,14 +868,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.3" - native_toolchain_c: + mutex: dependency: transitive description: - name: native_toolchain_c - sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" + name: mutex + sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2" url: "https://pub.dev" source: hosted - version: "0.17.4" + version: "3.1.0" nested: dependency: transitive description: @@ -916,14 +900,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" - source: hosted - version: "9.3.0" package_config: dependency: transitive description: @@ -976,18 +952,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 url: "https://pub.dev" source: hosted - version: "2.2.22" + version: "2.2.17" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -1016,10 +992,10 @@ packages: dependency: transitive description: name: petitparser - sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" url: "https://pub.dev" source: hosted - version: "7.0.2" + version: "6.1.0" platform: dependency: transitive description: @@ -1048,10 +1024,10 @@ packages: dependency: transitive description: name: pointer_interceptor_ios - sha256: "03c5fa5896080963ab4917eeffda8d28c90f22863a496fb5ba13bc10943e40e4" + sha256: a6906772b3205b42c44614fcea28f818b1e5fdad73a4ca742a7bd49818d9c917 url: "https://pub.dev" source: hosted - version: "0.10.1+1" + version: "0.10.1" pointer_interceptor_platform_interface: dependency: transitive description: @@ -1064,34 +1040,58 @@ packages: dependency: transitive description: name: pointer_interceptor_web - sha256: "460b600e71de6fcea2b3d5f662c92293c049c4319e27f0829310e5a953b3ee2a" + sha256: "7a7087782110f8c1827170660b09f8aa893e0e9a61431dbbe2ac3fc482e8c044" url: "https://pub.dev" source: hosted - version: "0.10.3" + version: "0.10.2+1" pool: dependency: transitive description: name: pool - sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" url: "https://pub.dev" source: hosted - version: "1.5.2" + version: "1.5.1" posix: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62 url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.0.2" + powersync: + dependency: "direct main" + description: + name: powersync + sha256: "5023a9a68ea2f01f1fdf7c05c84ea7f966574a84a5ee368cde2570497ae51e0f" + url: "https://pub.dev" + source: hosted + version: "1.17.0" + powersync_core: + dependency: transitive + description: + name: powersync_core + sha256: "20ff37895eff15c8f9791c76b90364c4a1cb18c55dc50d96024e44507d435e2e" + url: "https://pub.dev" + source: hosted + version: "1.7.0" + powersync_flutter_libs: + dependency: transitive + description: + name: powersync_flutter_libs + sha256: cf039113be13ecb6a9fa9831415436526a40ac6461babcb904a759140b1776d9 + url: "https://pub.dev" + source: hosted + version: "0.4.14" process: dependency: transitive description: name: process - sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.5" + version: "5.0.3" provider: dependency: "direct main" description: @@ -1128,10 +1128,10 @@ packages: dependency: transitive description: name: rfc_6901 - sha256: "6a43b1858dca2febaf93e15639aa6b0c49ccdfd7647775f15a499f872b018154" + sha256: df1bbfa3d023009598f19636d6114c6ac1e0b7bb7bf6a260f0e6e6ce91416820 url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "0.2.0" rive: dependency: "direct main" description: @@ -1184,26 +1184,26 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" url: "https://pub.dev" source: hosted - version: "2.4.20" + version: "2.4.10" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" url: "https://pub.dev" source: hosted - version: "2.5.6" + version: "2.5.4" shared_preferences_linux: dependency: transitive description: @@ -1285,10 +1285,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "1d562a3c1f713904ebbed50d2760217fd8a51ca170ac4b05b0db490699dbac17" + sha256: ccf30b0c9fbcd79d8b6f5bfac23199fb354938436f62475e14aea0f29ee0f800 url: "https://pub.dev" source: hosted - version: "4.2.0" + version: "4.0.1" source_helper: dependency: transitive description: @@ -1317,10 +1317,18 @@ packages: dependency: transitive description: name: source_span - sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.2" + version: "1.10.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" sqlite3: dependency: transitive description: @@ -1337,6 +1345,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.41" + sqlite3_web: + dependency: transitive + description: + name: sqlite3_web + sha256: "3973adf9ee74e485d5552319e1903129f4ed999fe675aa0b4b5d35d112b2aa1c" + url: "https://pub.dev" + source: hosted + version: "0.4.1" + sqlite_async: + dependency: "direct main" + description: + name: sqlite_async + sha256: "9b47ba01bb600d4a0e44752237ea201408bd4dff57eb203356ef27df41c29421" + url: "https://pub.dev" + source: hosted + version: "0.13.1" sqlparser: dependency: transitive description: @@ -1453,34 +1477,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" url: "https://pub.dev" source: hosted - version: "6.3.28" + version: "6.3.16" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.3.3" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.5" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -1493,26 +1517,34 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.4" + uuid: + dependency: transitive + description: + name: uuid + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + url: "https://pub.dev" + source: hosted + version: "4.5.1" vector_graphics: dependency: transitive description: name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 + sha256: "44cc7104ff32563122a929e4620cf3efd584194eec6d1d913eb5ba593dbcf6de" url: "https://pub.dev" source: hosted - version: "1.1.19" + version: "1.1.18" vector_graphics_codec: dependency: transitive description: @@ -1525,10 +1557,10 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.1.16" vector_math: dependency: transitive description: @@ -1589,26 +1621,26 @@ packages: dependency: transitive description: name: video_player_web - sha256: "9f3c00be2ef9b76a95d94ac5119fb843dca6f2c69e6c9968f6f2b6c9e7afbdeb" + sha256: e8bba2e5d1e159d5048c9a491bb2a7b29c535c612bb7d10c1e21107f5bd365ba url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.3.5" vm_service: dependency: transitive description: name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "15.0.2" + version: "15.0.0" watcher: dependency: transitive description: name: watcher - sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.1.1" web: dependency: transitive description: @@ -1653,10 +1685,10 @@ packages: dependency: transitive description: name: win32 - sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" url: "https://pub.dev" source: hosted - version: "5.15.0" + version: "5.13.0" xdg_directories: dependency: transitive description: @@ -1669,10 +1701,10 @@ packages: dependency: transitive description: name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.6.1" + version: "6.5.0" yaml: dependency: transitive description: @@ -1682,5 +1714,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" + dart: ">=3.10.0 <4.0.0" + flutter: ">=3.38.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3029f42a1..7cf6befa4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,10 +59,12 @@ dependencies: package_info_plus: ^9.0.0 path: ^1.9.0 path_provider: ^2.1.5 + powersync: ^1.17.0 provider: ^6.1.5+1 rive: ^0.13.20 riverpod_annotation: ^4.0.0 shared_preferences: ^2.5.3 + sqlite_async: ^0.13.1 sqlite3_flutter_libs: ^0.5.41 table_calendar: ^3.0.8 url_launcher: ^6.3.2 diff --git a/test/core/settings_test.mocks.dart b/test/core/settings_test.mocks.dart index 583ecbb7b..28598dcd7 100644 --- a/test/core/settings_test.mocks.dart +++ b/test/core/settings_test.mocks.dart @@ -408,7 +408,7 @@ class MockExercisesProvider extends _i1.Mock implements _i17.ExercisesProvider { as _i18.Future<_i4.Exercise>); @override - _i18.Future initCacheTimesLocalPrefs({bool? forceInit = false}) => + _i18.Future initCacheTimesLocalPrefs({dynamic forceInit = false}) => (super.noSuchMethod( Invocation.method(#initCacheTimesLocalPrefs, [], { #forceInit: forceInit, @@ -609,63 +609,28 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i20.NutritionPlans ); @override - _i10.NutritionalPlan findById(int? id) => + _i18.Stream<_i10.NutritionalPlan?> watchNutritionPlan(String? id) => (super.noSuchMethod( - Invocation.method(#findById, [id]), - returnValue: _FakeNutritionalPlan_8( - this, - Invocation.method(#findById, [id]), - ), + Invocation.method(#watchNutritionPlan, [id]), + returnValue: _i18.Stream<_i10.NutritionalPlan?>.empty(), ) - as _i10.NutritionalPlan); + as _i18.Stream<_i10.NutritionalPlan?>); @override - _i11.Meal? findMealById(int? id) => - (super.noSuchMethod(Invocation.method(#findMealById, [id])) as _i11.Meal?); - - @override - _i18.Future fetchAndSetAllPlansSparse() => + _i18.Stream<_i10.NutritionalPlan> watchNutritionPlanLast() => (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansSparse, []), - returnValue: _i18.Future.value(), - returnValueForMissingStub: _i18.Future.value(), - ) - as _i18.Future); - - @override - _i18.Future fetchAndSetAllPlansFull() => - (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansFull, []), - returnValue: _i18.Future.value(), - returnValueForMissingStub: _i18.Future.value(), - ) - as _i18.Future); - - @override - _i18.Future<_i10.NutritionalPlan> fetchAndSetPlanSparse(int? planId) => - (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanSparse, [planId]), - returnValue: _i18.Future<_i10.NutritionalPlan>.value( - _FakeNutritionalPlan_8( - this, - Invocation.method(#fetchAndSetPlanSparse, [planId]), - ), - ), + Invocation.method(#watchNutritionPlanLast, []), + returnValue: _i18.Stream<_i10.NutritionalPlan>.empty(), ) - as _i18.Future<_i10.NutritionalPlan>); + as _i18.Stream<_i10.NutritionalPlan>); @override - _i18.Future<_i10.NutritionalPlan> fetchAndSetPlanFull(int? planId) => + _i18.Stream> watchNutritionPlans() => (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanFull, [planId]), - returnValue: _i18.Future<_i10.NutritionalPlan>.value( - _FakeNutritionalPlan_8( - this, - Invocation.method(#fetchAndSetPlanFull, [planId]), - ), - ), + Invocation.method(#watchNutritionPlans, []), + returnValue: _i18.Stream>.empty(), ) - as _i18.Future<_i10.NutritionalPlan>); + as _i18.Stream>); @override _i18.Future<_i10.NutritionalPlan> addPlan(_i10.NutritionalPlan? planData) => @@ -690,7 +655,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i20.NutritionPlans as _i18.Future); @override - _i18.Future deletePlan(int? id) => + _i18.Future deletePlan(String? id) => (super.noSuchMethod( Invocation.method(#deletePlan, [id]), returnValue: _i18.Future.value(), @@ -699,7 +664,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i20.NutritionPlans as _i18.Future); @override - _i18.Future<_i11.Meal> addMeal(_i11.Meal? meal, int? planId) => + _i18.Future<_i11.Meal> addMeal(_i11.Meal? meal, String? planId) => (super.noSuchMethod( Invocation.method(#addMeal, [meal, planId]), returnValue: _i18.Future<_i11.Meal>.value( @@ -761,22 +726,6 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i20.NutritionPlans ) as _i18.Future); - @override - _i18.Future cacheIngredient( - _i13.Ingredient? ingredient, { - _i9.IngredientDatabase? database, - }) => - (super.noSuchMethod( - Invocation.method( - #cacheIngredient, - [ingredient], - {#database: database}, - ), - returnValue: _i18.Future.value(), - returnValueForMissingStub: _i18.Future.value(), - ) - as _i18.Future); - @override _i18.Future<_i13.Ingredient> fetchIngredient( int? ingredientId, { @@ -848,7 +797,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i20.NutritionPlans @override _i18.Future logIngredientToDiary( _i12.MealItem? mealItem, - int? planId, [ + String? planId, [ DateTime? dateTime, ]) => (super.noSuchMethod( @@ -863,7 +812,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i20.NutritionPlans as _i18.Future); @override - _i18.Future deleteLog(int? logId, int? planId) => + _i18.Future deleteLog(String? logId, String? planId) => (super.noSuchMethod( Invocation.method(#deleteLog, [logId, planId]), returnValue: _i18.Future.value(), @@ -943,22 +892,6 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider { ) as _i14.SharedPreferencesAsync); - @override - List<_i21.DashboardWidget> get dashboardWidgets => - (super.noSuchMethod( - Invocation.getter(#dashboardWidgets), - returnValue: <_i21.DashboardWidget>[], - ) - as List<_i21.DashboardWidget>); - - @override - List<_i21.DashboardWidget> get allDashboardWidgets => - (super.noSuchMethod( - Invocation.getter(#allDashboardWidgets), - returnValue: <_i21.DashboardWidget>[], - ) - as List<_i21.DashboardWidget>); - @override set themeMode(_i22.ThemeMode? value) => super.noSuchMethod( Invocation.setter(#themeMode, value), @@ -987,35 +920,6 @@ class MockUserProvider extends _i1.Mock implements _i21.UserProvider { returnValueForMissingStub: null, ); - @override - bool isDashboardWidgetVisible(_i21.DashboardWidget? key) => - (super.noSuchMethod( - Invocation.method(#isDashboardWidgetVisible, [key]), - returnValue: false, - ) - as bool); - - @override - _i18.Future setDashboardWidgetVisible( - _i21.DashboardWidget? key, - bool? visible, - ) => - (super.noSuchMethod( - Invocation.method(#setDashboardWidgetVisible, [key, visible]), - returnValue: _i18.Future.value(), - returnValueForMissingStub: _i18.Future.value(), - ) - as _i18.Future); - - @override - _i18.Future setDashboardOrder(int? oldIndex, int? newIndex) => - (super.noSuchMethod( - Invocation.method(#setDashboardOrder, [oldIndex, newIndex]), - returnValue: _i18.Future.value(), - returnValueForMissingStub: _i18.Future.value(), - ) - as _i18.Future); - @override void setThemeMode(_i22.ThemeMode? mode) => super.noSuchMethod( Invocation.method(#setThemeMode, [mode]), @@ -1111,14 +1015,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -1149,40 +1049,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider { as Uri); @override - _i18.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i18.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i18.Future.value(), ) as _i18.Future); @override - _i18.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i18.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i18.Future>.value([]), ) as _i18.Future>); diff --git a/test/core/validators_test.mocks.dart b/test/core/validators_test.mocks.dart index b89be4522..5702e7443 100644 --- a/test/core/validators_test.mocks.dart +++ b/test/core/validators_test.mocks.dart @@ -404,17 +404,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get dashboardWidgets => - (super.noSuchMethod( - Invocation.getter(#dashboardWidgets), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#dashboardWidgets), - ), - ) - as String); - @override String get labelDashboard => (super.noSuchMethod( @@ -778,17 +767,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get trophies => - (super.noSuchMethod( - Invocation.getter(#trophies), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#trophies), - ), - ) - as String); - @override String get routines => (super.noSuchMethod( @@ -942,39 +920,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get impressionGood => - (super.noSuchMethod( - Invocation.getter(#impressionGood), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#impressionGood), - ), - ) - as String); - - @override - String get impressionNeutral => - (super.noSuchMethod( - Invocation.getter(#impressionNeutral), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#impressionNeutral), - ), - ) - as String); - - @override - String get impressionBad => - (super.noSuchMethod( - Invocation.getter(#impressionBad), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#impressionBad), - ), - ) - as String); - @override String get impression => (super.noSuchMethod( @@ -1118,17 +1063,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get personalRecords => - (super.noSuchMethod( - Invocation.getter(#personalRecords), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#personalRecords), - ), - ) - as String); - @override String get gymMode => (super.noSuchMethod( @@ -1140,127 +1074,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get gymModeShowExercises => - (super.noSuchMethod( - Invocation.getter(#gymModeShowExercises), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#gymModeShowExercises), - ), - ) - as String); - - @override - String get gymModeShowTimer => - (super.noSuchMethod( - Invocation.getter(#gymModeShowTimer), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#gymModeShowTimer), - ), - ) - as String); - - @override - String get gymModeTimerType => - (super.noSuchMethod( - Invocation.getter(#gymModeTimerType), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#gymModeTimerType), - ), - ) - as String); - - @override - String get gymModeTimerTypeHelText => - (super.noSuchMethod( - Invocation.getter(#gymModeTimerTypeHelText), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#gymModeTimerTypeHelText), - ), - ) - as String); - - @override - String get countdown => - (super.noSuchMethod( - Invocation.getter(#countdown), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#countdown), - ), - ) - as String); - - @override - String get stopwatch => - (super.noSuchMethod( - Invocation.getter(#stopwatch), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#stopwatch), - ), - ) - as String); - - @override - String get gymModeDefaultCountdownTime => - (super.noSuchMethod( - Invocation.getter(#gymModeDefaultCountdownTime), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#gymModeDefaultCountdownTime), - ), - ) - as String); - - @override - String get gymModeNotifyOnCountdownFinish => - (super.noSuchMethod( - Invocation.getter(#gymModeNotifyOnCountdownFinish), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#gymModeNotifyOnCountdownFinish), - ), - ) - as String); - - @override - String get duration => - (super.noSuchMethod( - Invocation.getter(#duration), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#duration), - ), - ) - as String); - - @override - String get volume => - (super.noSuchMethod( - Invocation.getter(#volume), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#volume), - ), - ) - as String); - - @override - String get workoutCompleted => - (super.noSuchMethod( - Invocation.getter(#workoutCompleted), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#workoutCompleted), - ), - ) - as String); - @override String get plateCalculator => (super.noSuchMethod( @@ -2207,17 +2020,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get noTrophies => - (super.noSuchMethod( - Invocation.getter(#noTrophies), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#noTrophies), - ), - ) - as String); - @override String get noWeightEntries => (super.noSuchMethod( @@ -3056,17 +2858,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String get superset => - (super.noSuchMethod( - Invocation.getter(#superset), - returnValue: _i3.dummyValue( - this, - Invocation.getter(#superset), - ), - ) - as String); - @override String get setHasProgression => (super.noSuchMethod( @@ -3854,28 +3645,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String topSet(String? value) => - (super.noSuchMethod( - Invocation.method(#topSet, [value]), - returnValue: _i3.dummyValue( - this, - Invocation.method(#topSet, [value]), - ), - ) - as String); - - @override - String durationHoursMinutes(int? hours, int? minutes) => - (super.noSuchMethod( - Invocation.method(#durationHoursMinutes, [hours, minutes]), - returnValue: _i3.dummyValue( - this, - Invocation.method(#durationHoursMinutes, [hours, minutes]), - ), - ) - as String); - @override String chartAllTimeTitle(String? name) => (super.noSuchMethod( @@ -3964,17 +3733,6 @@ class MockAppLocalizations extends _i1.Mock implements _i2.AppLocalizations { ) as String); - @override - String formMinMaxValues(int? min, int? max) => - (super.noSuchMethod( - Invocation.method(#formMinMaxValues, [min, max]), - returnValue: _i3.dummyValue( - this, - Invocation.method(#formMinMaxValues, [min, max]), - ), - ) - as String); - @override String enterMinCharacters(String? min) => (super.noSuchMethod( diff --git a/test/exercises/contribute_exercise_image_test.mocks.dart b/test/exercises/contribute_exercise_image_test.mocks.dart index 8d872c5ab..c3685ed3e 100644 --- a/test/exercises/contribute_exercise_image_test.mocks.dart +++ b/test/exercises/contribute_exercise_image_test.mocks.dart @@ -368,14 +368,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -406,40 +402,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i2.WgerBaseProvider { as Uri); @override - _i14.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i14.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i14.Future.value(), ) as _i14.Future); @override - _i14.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i14.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i14.Future>.value([]), ) as _i14.Future>); diff --git a/test/gallery/gallery_form_test.mocks.dart b/test/gallery/gallery_form_test.mocks.dart index e6ef2a82b..e14d78381 100644 --- a/test/gallery/gallery_form_test.mocks.dart +++ b/test/gallery/gallery_form_test.mocks.dart @@ -141,14 +141,10 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider { as _i6.Future); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -179,40 +175,17 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider { as Uri); @override - _i6.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i6.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i6.Future.value(), ) as _i6.Future); @override - _i6.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i6.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i6.Future>.value([]), ) as _i6.Future>); diff --git a/test/gallery/gallery_screen_test.mocks.dart b/test/gallery/gallery_screen_test.mocks.dart index a2236b776..d1ab1318c 100644 --- a/test/gallery/gallery_screen_test.mocks.dart +++ b/test/gallery/gallery_screen_test.mocks.dart @@ -141,14 +141,10 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider { as _i6.Future); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -179,40 +175,17 @@ class MockGalleryProvider extends _i1.Mock implements _i4.GalleryProvider { as Uri); @override - _i6.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i6.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i6.Future.value(), ) as _i6.Future); @override - _i6.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i6.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i6.Future>.value([]), ) as _i6.Future>); diff --git a/test/measurements/measurement_provider_test.mocks.dart b/test/measurements/measurement_provider_test.mocks.dart index 1f2cd16ee..ef362a877 100644 --- a/test/measurements/measurement_provider_test.mocks.dart +++ b/test/measurements/measurement_provider_test.mocks.dart @@ -78,14 +78,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -116,40 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { as Uri); @override - _i5.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i5.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i5.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i5.Future>.value([]), ) as _i5.Future>); diff --git a/test/nutrition/nutrition_provider_test.dart b/test/nutrition/nutrition_provider_test.dart index e7a1a75b7..6d1ecc427 100644 --- a/test/nutrition/nutrition_provider_test.dart +++ b/test/nutrition/nutrition_provider_test.dart @@ -106,7 +106,7 @@ void main() { group('fetchAndSetPlanFull', () { test('should correctly load a full nutritional plan', () async { // arrange - await nutritionProvider.fetchAndSetPlanFull(1); + // await nutritionProvider.fetchAndSetPlanFull(1); // assert expect(nutritionProvider.items.isEmpty, false); diff --git a/test/nutrition/nutritional_meal_form_test.dart b/test/nutrition/nutritional_meal_form_test.dart index 82daa7d8e..4054ab873 100644 --- a/test/nutrition/nutritional_meal_form_test.dart +++ b/test/nutrition/nutritional_meal_form_test.dart @@ -60,10 +60,8 @@ void main() { localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, navigatorKey: key, - home: Scaffold(body: MealForm(1, meal)), - routes: { - NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen(), - }, + home: Scaffold(body: MealForm("1", meal)), + routes: {NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen()}, ), ); } @@ -81,11 +79,7 @@ void main() { await tester.pumpWidget(createFormScreen(meal1)); await tester.pumpAndSettle(); - expect( - find.text('17:00'), - findsOneWidget, - reason: 'Time of existing meal is filled in', - ); + expect(find.text('17:00'), findsOneWidget, reason: 'Time of existing meal is filled in'); expect( find.text('Initial Name 1'), diff --git a/test/nutrition/nutritional_meal_form_test.mocks.dart b/test/nutrition/nutritional_meal_form_test.mocks.dart index f080cc235..7cbf17377 100644 --- a/test/nutrition/nutritional_meal_form_test.mocks.dart +++ b/test/nutrition/nutritional_meal_form_test.mocks.dart @@ -126,63 +126,28 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP ); @override - _i4.NutritionalPlan findById(int? id) => + _i9.Stream<_i4.NutritionalPlan?> watchNutritionPlan(String? id) => (super.noSuchMethod( - Invocation.method(#findById, [id]), - returnValue: _FakeNutritionalPlan_2( - this, - Invocation.method(#findById, [id]), - ), + Invocation.method(#watchNutritionPlan, [id]), + returnValue: _i9.Stream<_i4.NutritionalPlan?>.empty(), ) - as _i4.NutritionalPlan); - - @override - _i5.Meal? findMealById(int? id) => - (super.noSuchMethod(Invocation.method(#findMealById, [id])) as _i5.Meal?); - - @override - _i9.Future fetchAndSetAllPlansSparse() => - (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansSparse, []), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) - as _i9.Future); + as _i9.Stream<_i4.NutritionalPlan?>); @override - _i9.Future fetchAndSetAllPlansFull() => + _i9.Stream<_i4.NutritionalPlan> watchNutritionPlanLast() => (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansFull, []), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) - as _i9.Future); - - @override - _i9.Future<_i4.NutritionalPlan> fetchAndSetPlanSparse(int? planId) => - (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanSparse, [planId]), - returnValue: _i9.Future<_i4.NutritionalPlan>.value( - _FakeNutritionalPlan_2( - this, - Invocation.method(#fetchAndSetPlanSparse, [planId]), - ), - ), + Invocation.method(#watchNutritionPlanLast, []), + returnValue: _i9.Stream<_i4.NutritionalPlan>.empty(), ) - as _i9.Future<_i4.NutritionalPlan>); + as _i9.Stream<_i4.NutritionalPlan>); @override - _i9.Future<_i4.NutritionalPlan> fetchAndSetPlanFull(int? planId) => + _i9.Stream> watchNutritionPlans() => (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanFull, [planId]), - returnValue: _i9.Future<_i4.NutritionalPlan>.value( - _FakeNutritionalPlan_2( - this, - Invocation.method(#fetchAndSetPlanFull, [planId]), - ), - ), + Invocation.method(#watchNutritionPlans, []), + returnValue: _i9.Stream>.empty(), ) - as _i9.Future<_i4.NutritionalPlan>); + as _i9.Stream>); @override _i9.Future<_i4.NutritionalPlan> addPlan(_i4.NutritionalPlan? planData) => @@ -207,7 +172,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP as _i9.Future); @override - _i9.Future deletePlan(int? id) => + _i9.Future deletePlan(String? id) => (super.noSuchMethod( Invocation.method(#deletePlan, [id]), returnValue: _i9.Future.value(), @@ -216,7 +181,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP as _i9.Future); @override - _i9.Future<_i5.Meal> addMeal(_i5.Meal? meal, int? planId) => + _i9.Future<_i5.Meal> addMeal(_i5.Meal? meal, String? planId) => (super.noSuchMethod( Invocation.method(#addMeal, [meal, planId]), returnValue: _i9.Future<_i5.Meal>.value( @@ -278,22 +243,6 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP ) as _i9.Future); - @override - _i9.Future cacheIngredient( - _i7.Ingredient? ingredient, { - _i3.IngredientDatabase? database, - }) => - (super.noSuchMethod( - Invocation.method( - #cacheIngredient, - [ingredient], - {#database: database}, - ), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) - as _i9.Future); - @override _i9.Future<_i7.Ingredient> fetchIngredient( int? ingredientId, { @@ -365,7 +314,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP @override _i9.Future logIngredientToDiary( _i6.MealItem? mealItem, - int? planId, [ + String? planId, [ DateTime? dateTime, ]) => (super.noSuchMethod( @@ -380,7 +329,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP as _i9.Future); @override - _i9.Future deleteLog(int? logId, int? planId) => + _i9.Future deleteLog(String? logId, String? planId) => (super.noSuchMethod( Invocation.method(#deleteLog, [logId, planId]), returnValue: _i9.Future.value(), diff --git a/test/nutrition/nutritional_meal_item_form_test.dart b/test/nutrition/nutritional_meal_item_form_test.dart index 6531e1454..bbe423031 100644 --- a/test/nutrition/nutritional_meal_item_form_test.dart +++ b/test/nutrition/nutritional_meal_item_form_test.dart @@ -104,9 +104,7 @@ void main() { getMealItemForm(meal, const [], code, test), ), ), - routes: { - NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen(), - }, + routes: {NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen()}, ), ); } @@ -296,7 +294,9 @@ void main() { testWidgets( 'save complete ingredient with correct weight input type', - (WidgetTester tester) async { + ( + WidgetTester tester, + ) async { await tester.pumpWidget(createMealItemFormScreen(meal1, '123', true)); final IngredientFormState formState = tester.state(find.byType(IngredientForm)); diff --git a/test/nutrition/nutritional_plan_form_test.dart b/test/nutrition/nutritional_plan_form_test.dart index 73f26084d..489fe3eb4 100644 --- a/test/nutrition/nutritional_plan_form_test.dart +++ b/test/nutrition/nutritional_plan_form_test.dart @@ -35,7 +35,7 @@ void main() { var mockNutrition = MockNutritionPlansProvider(); final plan1 = NutritionalPlan( - id: 1, + id: 'deadbeef', creationDate: DateTime(2021, 1, 1), startDate: DateTime(2021, 1, 1), endDate: DateTime(2021, 2, 10), @@ -61,9 +61,7 @@ void main() { supportedLocales: AppLocalizations.supportedLocales, navigatorKey: key, home: Scaffold(body: PlanForm(plan)), - routes: { - NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen(), - }, + routes: {NutritionalPlanScreen.routeName: (ctx) => const NutritionalPlanScreen()}, ), ); } diff --git a/test/nutrition/nutritional_plan_form_test.mocks.dart b/test/nutrition/nutritional_plan_form_test.mocks.dart index cdcc53759..1fbf5f5d6 100644 --- a/test/nutrition/nutritional_plan_form_test.mocks.dart +++ b/test/nutrition/nutritional_plan_form_test.mocks.dart @@ -126,63 +126,28 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP ); @override - _i4.NutritionalPlan findById(int? id) => + _i9.Stream<_i4.NutritionalPlan?> watchNutritionPlan(String? id) => (super.noSuchMethod( - Invocation.method(#findById, [id]), - returnValue: _FakeNutritionalPlan_2( - this, - Invocation.method(#findById, [id]), - ), + Invocation.method(#watchNutritionPlan, [id]), + returnValue: _i9.Stream<_i4.NutritionalPlan?>.empty(), ) - as _i4.NutritionalPlan); - - @override - _i5.Meal? findMealById(int? id) => - (super.noSuchMethod(Invocation.method(#findMealById, [id])) as _i5.Meal?); - - @override - _i9.Future fetchAndSetAllPlansSparse() => - (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansSparse, []), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) - as _i9.Future); + as _i9.Stream<_i4.NutritionalPlan?>); @override - _i9.Future fetchAndSetAllPlansFull() => + _i9.Stream<_i4.NutritionalPlan> watchNutritionPlanLast() => (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansFull, []), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) - as _i9.Future); - - @override - _i9.Future<_i4.NutritionalPlan> fetchAndSetPlanSparse(int? planId) => - (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanSparse, [planId]), - returnValue: _i9.Future<_i4.NutritionalPlan>.value( - _FakeNutritionalPlan_2( - this, - Invocation.method(#fetchAndSetPlanSparse, [planId]), - ), - ), + Invocation.method(#watchNutritionPlanLast, []), + returnValue: _i9.Stream<_i4.NutritionalPlan>.empty(), ) - as _i9.Future<_i4.NutritionalPlan>); + as _i9.Stream<_i4.NutritionalPlan>); @override - _i9.Future<_i4.NutritionalPlan> fetchAndSetPlanFull(int? planId) => + _i9.Stream> watchNutritionPlans() => (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanFull, [planId]), - returnValue: _i9.Future<_i4.NutritionalPlan>.value( - _FakeNutritionalPlan_2( - this, - Invocation.method(#fetchAndSetPlanFull, [planId]), - ), - ), + Invocation.method(#watchNutritionPlans, []), + returnValue: _i9.Stream>.empty(), ) - as _i9.Future<_i4.NutritionalPlan>); + as _i9.Stream>); @override _i9.Future<_i4.NutritionalPlan> addPlan(_i4.NutritionalPlan? planData) => @@ -207,7 +172,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP as _i9.Future); @override - _i9.Future deletePlan(int? id) => + _i9.Future deletePlan(String? id) => (super.noSuchMethod( Invocation.method(#deletePlan, [id]), returnValue: _i9.Future.value(), @@ -216,7 +181,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP as _i9.Future); @override - _i9.Future<_i5.Meal> addMeal(_i5.Meal? meal, int? planId) => + _i9.Future<_i5.Meal> addMeal(_i5.Meal? meal, String? planId) => (super.noSuchMethod( Invocation.method(#addMeal, [meal, planId]), returnValue: _i9.Future<_i5.Meal>.value( @@ -278,22 +243,6 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP ) as _i9.Future); - @override - _i9.Future cacheIngredient( - _i7.Ingredient? ingredient, { - _i3.IngredientDatabase? database, - }) => - (super.noSuchMethod( - Invocation.method( - #cacheIngredient, - [ingredient], - {#database: database}, - ), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) - as _i9.Future); - @override _i9.Future<_i7.Ingredient> fetchIngredient( int? ingredientId, { @@ -365,7 +314,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP @override _i9.Future logIngredientToDiary( _i6.MealItem? mealItem, - int? planId, [ + String? planId, [ DateTime? dateTime, ]) => (super.noSuchMethod( @@ -380,7 +329,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i8.NutritionPlansP as _i9.Future); @override - _i9.Future deleteLog(int? logId, int? planId) => + _i9.Future deleteLog(String? logId, String? planId) => (super.noSuchMethod( Invocation.method(#deleteLog, [logId, planId]), returnValue: _i9.Future.value(), diff --git a/test/nutrition/nutritional_plan_screen_test.mocks.dart b/test/nutrition/nutritional_plan_screen_test.mocks.dart index 5cbdb1a0d..2fe3c4ac5 100644 --- a/test/nutrition/nutritional_plan_screen_test.mocks.dart +++ b/test/nutrition/nutritional_plan_screen_test.mocks.dart @@ -88,14 +88,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -126,40 +122,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { as Uri); @override - _i5.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i5.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i5.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i5.Future>.value([]), ) as _i5.Future>); diff --git a/test/nutrition/nutritional_plans_screen_test.mocks.dart b/test/nutrition/nutritional_plans_screen_test.mocks.dart index 18c30c3b1..c702d4015 100644 --- a/test/nutrition/nutritional_plans_screen_test.mocks.dart +++ b/test/nutrition/nutritional_plans_screen_test.mocks.dart @@ -323,14 +323,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i8.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -361,40 +357,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i8.WgerBaseProvider { as Uri); @override - _i5.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i5.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i5.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i5.Future>.value([]), ) as _i5.Future>); diff --git a/test/user/provider_test.mocks.dart b/test/user/provider_test.mocks.dart index 406eca923..08bbf6366 100644 --- a/test/user/provider_test.mocks.dart +++ b/test/user/provider_test.mocks.dart @@ -78,14 +78,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -116,40 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { as Uri); @override - _i5.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i5.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i5.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i5.Future>.value([]), ) as _i5.Future>); diff --git a/test/weight/weight_provider_test.mocks.dart b/test/weight/weight_provider_test.mocks.dart index b38902f65..4cd18bb56 100644 --- a/test/weight/weight_provider_test.mocks.dart +++ b/test/weight/weight_provider_test.mocks.dart @@ -78,14 +78,10 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { ); @override - Map getDefaultHeaders({ - bool? includeAuth = false, - String? language, - }) => + Map getDefaultHeaders({bool? includeAuth = false}) => (super.noSuchMethod( Invocation.method(#getDefaultHeaders, [], { #includeAuth: includeAuth, - #language: language, }), returnValue: {}, ) @@ -116,40 +112,17 @@ class MockWgerBaseProvider extends _i1.Mock implements _i4.WgerBaseProvider { as Uri); @override - _i5.Future fetch( - Uri? uri, { - int? maxRetries = 3, - Duration? initialDelay = const Duration(milliseconds: 250), - Duration? timeout = const Duration(seconds: 5), - String? language, - }) => + _i5.Future fetch(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetch, - [uri], - { - #maxRetries: maxRetries, - #initialDelay: initialDelay, - #timeout: timeout, - #language: language, - }, - ), + Invocation.method(#fetch, [uri]), returnValue: _i5.Future.value(), ) as _i5.Future); @override - _i5.Future> fetchPaginated( - Uri? uri, { - String? language, - Duration? timeout = const Duration(seconds: 5), - }) => + _i5.Future> fetchPaginated(Uri? uri) => (super.noSuchMethod( - Invocation.method( - #fetchPaginated, - [uri], - {#language: language, #timeout: timeout}, - ), + Invocation.method(#fetchPaginated, [uri]), returnValue: _i5.Future>.value([]), ) as _i5.Future>); diff --git a/test/weight/weight_screen_test.mocks.dart b/test/weight/weight_screen_test.mocks.dart index 0ba292b46..0ee15fab6 100644 --- a/test/weight/weight_screen_test.mocks.dart +++ b/test/weight/weight_screen_test.mocks.dart @@ -231,22 +231,6 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider { ) as _i4.SharedPreferencesAsync); - @override - List<_i13.DashboardWidget> get dashboardWidgets => - (super.noSuchMethod( - Invocation.getter(#dashboardWidgets), - returnValue: <_i13.DashboardWidget>[], - ) - as List<_i13.DashboardWidget>); - - @override - List<_i13.DashboardWidget> get allDashboardWidgets => - (super.noSuchMethod( - Invocation.getter(#allDashboardWidgets), - returnValue: <_i13.DashboardWidget>[], - ) - as List<_i13.DashboardWidget>); - @override set themeMode(_i14.ThemeMode? value) => super.noSuchMethod( Invocation.setter(#themeMode, value), @@ -275,35 +259,6 @@ class MockUserProvider extends _i1.Mock implements _i13.UserProvider { returnValueForMissingStub: null, ); - @override - bool isDashboardWidgetVisible(_i13.DashboardWidget? key) => - (super.noSuchMethod( - Invocation.method(#isDashboardWidgetVisible, [key]), - returnValue: false, - ) - as bool); - - @override - _i11.Future setDashboardWidgetVisible( - _i13.DashboardWidget? key, - bool? visible, - ) => - (super.noSuchMethod( - Invocation.method(#setDashboardWidgetVisible, [key, visible]), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) - as _i11.Future); - - @override - _i11.Future setDashboardOrder(int? oldIndex, int? newIndex) => - (super.noSuchMethod( - Invocation.method(#setDashboardOrder, [oldIndex, newIndex]), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) - as _i11.Future); - @override void setThemeMode(_i14.ThemeMode? mode) => super.noSuchMethod( Invocation.method(#setThemeMode, [mode]), @@ -431,63 +386,28 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i16.NutritionPlans ); @override - _i6.NutritionalPlan findById(int? id) => + _i11.Stream<_i6.NutritionalPlan?> watchNutritionPlan(String? id) => (super.noSuchMethod( - Invocation.method(#findById, [id]), - returnValue: _FakeNutritionalPlan_4( - this, - Invocation.method(#findById, [id]), - ), + Invocation.method(#watchNutritionPlan, [id]), + returnValue: _i11.Stream<_i6.NutritionalPlan?>.empty(), ) - as _i6.NutritionalPlan); + as _i11.Stream<_i6.NutritionalPlan?>); @override - _i7.Meal? findMealById(int? id) => - (super.noSuchMethod(Invocation.method(#findMealById, [id])) as _i7.Meal?); - - @override - _i11.Future fetchAndSetAllPlansSparse() => + _i11.Stream<_i6.NutritionalPlan> watchNutritionPlanLast() => (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansSparse, []), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), + Invocation.method(#watchNutritionPlanLast, []), + returnValue: _i11.Stream<_i6.NutritionalPlan>.empty(), ) - as _i11.Future); + as _i11.Stream<_i6.NutritionalPlan>); @override - _i11.Future fetchAndSetAllPlansFull() => + _i11.Stream> watchNutritionPlans() => (super.noSuchMethod( - Invocation.method(#fetchAndSetAllPlansFull, []), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) - as _i11.Future); - - @override - _i11.Future<_i6.NutritionalPlan> fetchAndSetPlanSparse(int? planId) => - (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanSparse, [planId]), - returnValue: _i11.Future<_i6.NutritionalPlan>.value( - _FakeNutritionalPlan_4( - this, - Invocation.method(#fetchAndSetPlanSparse, [planId]), - ), - ), + Invocation.method(#watchNutritionPlans, []), + returnValue: _i11.Stream>.empty(), ) - as _i11.Future<_i6.NutritionalPlan>); - - @override - _i11.Future<_i6.NutritionalPlan> fetchAndSetPlanFull(int? planId) => - (super.noSuchMethod( - Invocation.method(#fetchAndSetPlanFull, [planId]), - returnValue: _i11.Future<_i6.NutritionalPlan>.value( - _FakeNutritionalPlan_4( - this, - Invocation.method(#fetchAndSetPlanFull, [planId]), - ), - ), - ) - as _i11.Future<_i6.NutritionalPlan>); + as _i11.Stream>); @override _i11.Future<_i6.NutritionalPlan> addPlan(_i6.NutritionalPlan? planData) => @@ -512,7 +432,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i16.NutritionPlans as _i11.Future); @override - _i11.Future deletePlan(int? id) => + _i11.Future deletePlan(String? id) => (super.noSuchMethod( Invocation.method(#deletePlan, [id]), returnValue: _i11.Future.value(), @@ -521,7 +441,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i16.NutritionPlans as _i11.Future); @override - _i11.Future<_i7.Meal> addMeal(_i7.Meal? meal, int? planId) => + _i11.Future<_i7.Meal> addMeal(_i7.Meal? meal, String? planId) => (super.noSuchMethod( Invocation.method(#addMeal, [meal, planId]), returnValue: _i11.Future<_i7.Meal>.value( @@ -583,22 +503,6 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i16.NutritionPlans ) as _i11.Future); - @override - _i11.Future cacheIngredient( - _i9.Ingredient? ingredient, { - _i5.IngredientDatabase? database, - }) => - (super.noSuchMethod( - Invocation.method( - #cacheIngredient, - [ingredient], - {#database: database}, - ), - returnValue: _i11.Future.value(), - returnValueForMissingStub: _i11.Future.value(), - ) - as _i11.Future); - @override _i11.Future<_i9.Ingredient> fetchIngredient( int? ingredientId, { @@ -670,7 +574,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i16.NutritionPlans @override _i11.Future logIngredientToDiary( _i8.MealItem? mealItem, - int? planId, [ + String? planId, [ DateTime? dateTime, ]) => (super.noSuchMethod( @@ -685,7 +589,7 @@ class MockNutritionPlansProvider extends _i1.Mock implements _i16.NutritionPlans as _i11.Future); @override - _i11.Future deleteLog(int? logId, int? planId) => + _i11.Future deleteLog(String? logId, String? planId) => (super.noSuchMethod( Invocation.method(#deleteLog, [logId, planId]), returnValue: _i11.Future.value(), diff --git a/test_data/nutritional_plans.dart b/test_data/nutritional_plans.dart index a4fbaa218..733d259d4 100644 --- a/test_data/nutritional_plans.dart +++ b/test_data/nutritional_plans.dart @@ -156,23 +156,23 @@ NutritionalPlan getNutritionalPlan() { mealItem3.ingredient = ingredient3; final meal1 = Meal( - id: 1, - plan: 1, + id: 'deadbeefa', + plan: '1', time: const TimeOfDay(hour: 17, minute: 0), name: 'Initial Name 1', ); meal1.mealItems = [mealItem1, mealItem2]; final meal2 = Meal( - id: 2, - plan: 1, + id: 'deadbeefb', + plan: '1', time: const TimeOfDay(hour: 22, minute: 5), name: 'Initial Name 2', ); meal2.mealItems = [mealItem3]; final NutritionalPlan plan = NutritionalPlan( - id: 1, + id: 'deadbeefc', description: 'Less fat, more protein', creationDate: DateTime(2021, 5, 23), startDate: DateTime(2021, 5, 23), @@ -180,9 +180,9 @@ NutritionalPlan getNutritionalPlan() { plan.meals = [meal1, meal2]; // Add logs - plan.diaryEntries.add(Log.fromMealItem(mealItem1, 1, 1, DateTime(2021, 6, 1))); - plan.diaryEntries.add(Log.fromMealItem(mealItem2, 1, 1, DateTime(2021, 6, 1))); - plan.diaryEntries.add(Log.fromMealItem(mealItem3, 1, 1, DateTime(2021, 6, 10))); + plan.diaryEntries.add(Log.fromMealItem(mealItem1, '1', '1', DateTime(2021, 6, 1))); + plan.diaryEntries.add(Log.fromMealItem(mealItem2, '1', '1', DateTime(2021, 6, 1))); + plan.diaryEntries.add(Log.fromMealItem(mealItem3, '1', '1', DateTime(2021, 6, 10))); return plan; } @@ -195,23 +195,23 @@ NutritionalPlan getNutritionalPlanScreenshot() { final mealItem3 = MealItem(ingredientId: 3, amount: 100, ingredient: apple); final meal1 = Meal( - id: 1, - plan: 1, + id: 'deadbeefa', + plan: '1', time: const TimeOfDay(hour: 8, minute: 30), name: 'Breakfast', mealItems: [mealItem1, mealItem2], ); final meal2 = Meal( - id: 2, - plan: 1, + id: 'deadbeefb', + plan: '1', time: const TimeOfDay(hour: 11, minute: 0), name: 'Snack 1', mealItems: [mealItem3], ); final NutritionalPlan plan = NutritionalPlan( - id: 1, + id: '1', description: 'Diet', creationDate: DateTime(2021, 5, 23), startDate: DateTime(2021, 5, 23), @@ -219,9 +219,9 @@ NutritionalPlan getNutritionalPlanScreenshot() { ); // Add logs - plan.diaryEntries.add(Log.fromMealItem(mealItem1, 1, 1, DateTime.now())); - plan.diaryEntries.add(Log.fromMealItem(mealItem2, 1, 1, DateTime.now())); - plan.diaryEntries.add(Log.fromMealItem(mealItem3, 1, 1, DateTime.now())); + plan.diaryEntries.add(Log.fromMealItem(mealItem1, '1', '1', DateTime.now())); + plan.diaryEntries.add(Log.fromMealItem(mealItem2, '1', '1', DateTime.now())); + plan.diaryEntries.add(Log.fromMealItem(mealItem3, '1', '1', DateTime.now())); for (final i in plan.diaryEntries) { i.datetime = DateTime.now(); diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 3a31fc83a..943344bce 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -14,6 +15,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); + PowersyncFlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PowersyncFlutterLibsPlugin")); RivePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("RivePlugin")); Sqlite3FlutterLibsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index fa00096b1..63ed6d140 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows + powersync_flutter_libs rive_common sqlite3_flutter_libs url_launcher_windows