Skip to content

Commit 8ce9029

Browse files
committed
Start migrating the ingredient cache to a local sqlite database
1 parent 15b6eb1 commit 8ce9029

File tree

3 files changed

+58
-39
lines changed

3 files changed

+58
-39
lines changed

lib/core/locator.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ class ServiceLocator {
1818
Future<void> _initDB() async {
1919
ExerciseDatabase exerciseDB;
2020
IngredientDatabase ingredientDB;
21-
// final exerciseDB = ExerciseDatabase();
22-
// final ingredientDB = IngredientDatabase();
2321

2422
if (Platform.environment.containsKey('FLUTTER_TEST')) {
2523
exerciseDB = ExerciseDatabase.inMemory(NativeDatabase.memory());

lib/database/ingredients/ingredients_database.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ part 'ingredients_database.g.dart';
1010
@DataClassName('IngredientTable')
1111
class Ingredients extends Table {
1212
const Ingredients();
13+
1314
IntColumn get id => integer()();
1415

1516
TextColumn get data => text()();
@@ -27,6 +28,14 @@ class IngredientDatabase extends _$IngredientDatabase {
2728
@override
2829
// TODO: implement schemaVersion
2930
int get schemaVersion => 1;
31+
32+
Future<void> deleteEverything() {
33+
return transaction(() async {
34+
for (final table in allTables) {
35+
await delete(table).go();
36+
}
37+
});
38+
}
3039
}
3140

3241
LazyDatabase _openConnection() {

lib/providers/nutrition.dart

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ import 'dart:convert';
2020
import 'dart:developer';
2121

2222
import 'package:flutter/material.dart';
23-
import 'package:shared_preferences/shared_preferences.dart';
23+
import 'package:wger/core/locator.dart';
24+
import 'package:wger/database/ingredients/ingredients_database.dart';
2425
import 'package:wger/exceptions/http_exception.dart';
2526
import 'package:wger/exceptions/no_such_entry_exception.dart';
2627
import 'package:wger/helpers/consts.dart';
@@ -43,10 +44,15 @@ class NutritionPlansProvider with ChangeNotifier {
4344
static const _nutritionDiaryPath = 'nutritiondiary';
4445

4546
final WgerBaseProvider baseProvider;
47+
late IngredientDatabase database;
4648
List<NutritionalPlan> _plans = [];
4749
List<Ingredient> _ingredients = [];
4850

49-
NutritionPlansProvider(this.baseProvider, List<NutritionalPlan> entries) : _plans = entries;
51+
NutritionPlansProvider(this.baseProvider, List<NutritionalPlan> entries,
52+
{IngredientDatabase? database})
53+
: _plans = entries {
54+
this.database = database ?? locator<IngredientDatabase>();
55+
}
5056

5157
List<NutritionalPlan> get items {
5258
return [..._plans];
@@ -286,6 +292,10 @@ class NutritionPlansProvider with ChangeNotifier {
286292
}
287293
}
288294

295+
Future<void> clearIngredientCaches() async {
296+
await database.deleteEverything();
297+
}
298+
289299
/// Fetch and return an ingredient
290300
///
291301
/// If the ingredient is not known locally, it is fetched from the server
@@ -294,46 +304,48 @@ class NutritionPlansProvider with ChangeNotifier {
294304

295305
try {
296306
ingredient = _ingredients.firstWhere((e) => e.id == ingredientId);
297-
return ingredient;
298-
299-
// Get ingredient from the server and save to cache
300307
} on StateError {
301-
final data = await baseProvider.fetch(
302-
baseProvider.makeUrl(_ingredientInfoPath, id: ingredientId),
303-
);
304-
ingredient = Ingredient.fromJson(data);
305-
_ingredients.add(ingredient);
306-
307-
final prefs = await SharedPreferences.getInstance();
308-
final ingredientData = json.decode(prefs.getString(PREFS_INGREDIENTS)!);
309-
ingredientData['ingredients'].add(ingredient.toJson());
310-
prefs.setString(PREFS_INGREDIENTS, json.encode(ingredientData));
311-
log("Saved ingredient '${ingredient.name}' to cache.");
312-
313-
return ingredient;
308+
final ingredientDb = await (database.select(database.ingredients)
309+
..where((e) => e.id.equals(ingredientId)))
310+
.getSingleOrNull();
311+
312+
// Try to fetch from local db
313+
if (ingredientDb != null) {
314+
ingredient = Ingredient.fromJson(jsonDecode(ingredientDb.data));
315+
316+
// Prune old entries
317+
if (DateTime.now()
318+
.isAfter(ingredientDb.lastUpdate.add(const Duration(days: DAYS_TO_CACHE)))) {
319+
(database.delete(database.ingredients)..where((i) => i.id.isValue(ingredientId))).go();
320+
}
321+
} else {
322+
final data = await baseProvider.fetch(
323+
baseProvider.makeUrl(_ingredientInfoPath, id: ingredientId),
324+
);
325+
ingredient = Ingredient.fromJson(data);
326+
_ingredients.add(ingredient);
327+
328+
database.into(database.ingredients).insert(
329+
IngredientsCompanion.insert(
330+
id: ingredientId,
331+
data: jsonEncode(data),
332+
lastUpdate: DateTime.now(),
333+
),
334+
);
335+
log("Saved ingredient '${ingredient.name}' to db cache");
336+
}
314337
}
338+
339+
return ingredient;
315340
}
316341

317-
/// Loads the available ingredients from the local storage
342+
/// Loads the available ingredients from the local cache
318343
Future<void> fetchIngredientsFromCache() async {
319-
// Load exercises from cache, if available
320-
final prefs = await SharedPreferences.getInstance();
321-
if (prefs.containsKey(PREFS_INGREDIENTS)) {
322-
final ingredientData = json.decode(prefs.getString(PREFS_INGREDIENTS)!);
323-
if (DateTime.parse(ingredientData['expiresIn']).isAfter(DateTime.now())) {
324-
ingredientData['ingredients'].forEach((e) => _ingredients.add(Ingredient.fromJson(e)));
325-
log("Read ${ingredientData['ingredients'].length} ingredients from cache. Valid till ${ingredientData['expiresIn']}");
326-
return;
327-
}
344+
final ingredientDb = await database.select(database.ingredients).get();
345+
log("Read ${ingredientDb.length} ingredients from db cache");
346+
if (ingredientDb.isNotEmpty) {
347+
ingredients = ingredientDb.map((e) => Ingredient.fromJson(jsonDecode(e.data))).toList();
328348
}
329-
330-
// Initialise an empty cache
331-
final ingredientData = {
332-
'date': DateTime.now().toIso8601String(),
333-
'expiresIn': DateTime.now().add(const Duration(days: DAYS_TO_CACHE)).toIso8601String(),
334-
'ingredients': [],
335-
};
336-
prefs.setString(PREFS_INGREDIENTS, json.encode(ingredientData));
337349
}
338350

339351
/// Searches for an ingredient
@@ -432,7 +444,7 @@ class NutritionPlansProvider with ChangeNotifier {
432444
baseProvider.makeUrl(
433445
_nutritionDiaryPath,
434446
query: {
435-
'plan': plan.id.toString(),
447+
'plan': plan.id?.toString(),
436448
'limit': '999',
437449
'ordering': 'datetime',
438450
},

0 commit comments

Comments
 (0)