mirror of
https://github.com/wger-project/flutter.git
synced 2026-02-18 00:17:48 +01:00
Start migrating the ingredient cache to a local sqlite database
This commit is contained in:
@@ -18,8 +18,6 @@ class ServiceLocator {
|
|||||||
Future<void> _initDB() async {
|
Future<void> _initDB() async {
|
||||||
ExerciseDatabase exerciseDB;
|
ExerciseDatabase exerciseDB;
|
||||||
IngredientDatabase ingredientDB;
|
IngredientDatabase ingredientDB;
|
||||||
// final exerciseDB = ExerciseDatabase();
|
|
||||||
// final ingredientDB = IngredientDatabase();
|
|
||||||
|
|
||||||
if (Platform.environment.containsKey('FLUTTER_TEST')) {
|
if (Platform.environment.containsKey('FLUTTER_TEST')) {
|
||||||
exerciseDB = ExerciseDatabase.inMemory(NativeDatabase.memory());
|
exerciseDB = ExerciseDatabase.inMemory(NativeDatabase.memory());
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ part 'ingredients_database.g.dart';
|
|||||||
@DataClassName('IngredientTable')
|
@DataClassName('IngredientTable')
|
||||||
class Ingredients extends Table {
|
class Ingredients extends Table {
|
||||||
const Ingredients();
|
const Ingredients();
|
||||||
|
|
||||||
IntColumn get id => integer()();
|
IntColumn get id => integer()();
|
||||||
|
|
||||||
TextColumn get data => text()();
|
TextColumn get data => text()();
|
||||||
@@ -27,6 +28,14 @@ class IngredientDatabase extends _$IngredientDatabase {
|
|||||||
@override
|
@override
|
||||||
// TODO: implement schemaVersion
|
// TODO: implement schemaVersion
|
||||||
int get schemaVersion => 1;
|
int get schemaVersion => 1;
|
||||||
|
|
||||||
|
Future<void> deleteEverything() {
|
||||||
|
return transaction(() async {
|
||||||
|
for (final table in allTables) {
|
||||||
|
await delete(table).go();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyDatabase _openConnection() {
|
LazyDatabase _openConnection() {
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ import 'dart:convert';
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:wger/core/locator.dart';
|
||||||
|
import 'package:wger/database/ingredients/ingredients_database.dart';
|
||||||
import 'package:wger/exceptions/http_exception.dart';
|
import 'package:wger/exceptions/http_exception.dart';
|
||||||
import 'package:wger/exceptions/no_such_entry_exception.dart';
|
import 'package:wger/exceptions/no_such_entry_exception.dart';
|
||||||
import 'package:wger/helpers/consts.dart';
|
import 'package:wger/helpers/consts.dart';
|
||||||
@@ -43,10 +44,15 @@ class NutritionPlansProvider with ChangeNotifier {
|
|||||||
static const _nutritionDiaryPath = 'nutritiondiary';
|
static const _nutritionDiaryPath = 'nutritiondiary';
|
||||||
|
|
||||||
final WgerBaseProvider baseProvider;
|
final WgerBaseProvider baseProvider;
|
||||||
|
late IngredientDatabase database;
|
||||||
List<NutritionalPlan> _plans = [];
|
List<NutritionalPlan> _plans = [];
|
||||||
List<Ingredient> _ingredients = [];
|
List<Ingredient> _ingredients = [];
|
||||||
|
|
||||||
NutritionPlansProvider(this.baseProvider, List<NutritionalPlan> entries) : _plans = entries;
|
NutritionPlansProvider(this.baseProvider, List<NutritionalPlan> entries,
|
||||||
|
{IngredientDatabase? database})
|
||||||
|
: _plans = entries {
|
||||||
|
this.database = database ?? locator<IngredientDatabase>();
|
||||||
|
}
|
||||||
|
|
||||||
List<NutritionalPlan> get items {
|
List<NutritionalPlan> get items {
|
||||||
return [..._plans];
|
return [..._plans];
|
||||||
@@ -286,6 +292,10 @@ class NutritionPlansProvider with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> clearIngredientCaches() async {
|
||||||
|
await database.deleteEverything();
|
||||||
|
}
|
||||||
|
|
||||||
/// Fetch and return an ingredient
|
/// Fetch and return an ingredient
|
||||||
///
|
///
|
||||||
/// If the ingredient is not known locally, it is fetched from the server
|
/// If the ingredient is not known locally, it is fetched from the server
|
||||||
@@ -294,46 +304,48 @@ class NutritionPlansProvider with ChangeNotifier {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
ingredient = _ingredients.firstWhere((e) => e.id == ingredientId);
|
ingredient = _ingredients.firstWhere((e) => e.id == ingredientId);
|
||||||
return ingredient;
|
|
||||||
|
|
||||||
// Get ingredient from the server and save to cache
|
|
||||||
} on StateError {
|
} on StateError {
|
||||||
final data = await baseProvider.fetch(
|
final ingredientDb = await (database.select(database.ingredients)
|
||||||
baseProvider.makeUrl(_ingredientInfoPath, id: ingredientId),
|
..where((e) => e.id.equals(ingredientId)))
|
||||||
);
|
.getSingleOrNull();
|
||||||
ingredient = Ingredient.fromJson(data);
|
|
||||||
_ingredients.add(ingredient);
|
|
||||||
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
// Try to fetch from local db
|
||||||
final ingredientData = json.decode(prefs.getString(PREFS_INGREDIENTS)!);
|
if (ingredientDb != null) {
|
||||||
ingredientData['ingredients'].add(ingredient.toJson());
|
ingredient = Ingredient.fromJson(jsonDecode(ingredientDb.data));
|
||||||
prefs.setString(PREFS_INGREDIENTS, json.encode(ingredientData));
|
|
||||||
log("Saved ingredient '${ingredient.name}' to cache.");
|
|
||||||
|
|
||||||
return ingredient;
|
// Prune old entries
|
||||||
}
|
if (DateTime.now()
|
||||||
}
|
.isAfter(ingredientDb.lastUpdate.add(const Duration(days: DAYS_TO_CACHE)))) {
|
||||||
|
(database.delete(database.ingredients)..where((i) => i.id.isValue(ingredientId))).go();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final data = await baseProvider.fetch(
|
||||||
|
baseProvider.makeUrl(_ingredientInfoPath, id: ingredientId),
|
||||||
|
);
|
||||||
|
ingredient = Ingredient.fromJson(data);
|
||||||
|
_ingredients.add(ingredient);
|
||||||
|
|
||||||
/// Loads the available ingredients from the local storage
|
database.into(database.ingredients).insert(
|
||||||
Future<void> fetchIngredientsFromCache() async {
|
IngredientsCompanion.insert(
|
||||||
// Load exercises from cache, if available
|
id: ingredientId,
|
||||||
final prefs = await SharedPreferences.getInstance();
|
data: jsonEncode(data),
|
||||||
if (prefs.containsKey(PREFS_INGREDIENTS)) {
|
lastUpdate: DateTime.now(),
|
||||||
final ingredientData = json.decode(prefs.getString(PREFS_INGREDIENTS)!);
|
),
|
||||||
if (DateTime.parse(ingredientData['expiresIn']).isAfter(DateTime.now())) {
|
);
|
||||||
ingredientData['ingredients'].forEach((e) => _ingredients.add(Ingredient.fromJson(e)));
|
log("Saved ingredient '${ingredient.name}' to db cache");
|
||||||
log("Read ${ingredientData['ingredients'].length} ingredients from cache. Valid till ${ingredientData['expiresIn']}");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise an empty cache
|
return ingredient;
|
||||||
final ingredientData = {
|
}
|
||||||
'date': DateTime.now().toIso8601String(),
|
|
||||||
'expiresIn': DateTime.now().add(const Duration(days: DAYS_TO_CACHE)).toIso8601String(),
|
/// Loads the available ingredients from the local cache
|
||||||
'ingredients': [],
|
Future<void> fetchIngredientsFromCache() async {
|
||||||
};
|
final ingredientDb = await database.select(database.ingredients).get();
|
||||||
prefs.setString(PREFS_INGREDIENTS, json.encode(ingredientData));
|
log("Read ${ingredientDb.length} ingredients from db cache");
|
||||||
|
if (ingredientDb.isNotEmpty) {
|
||||||
|
ingredients = ingredientDb.map((e) => Ingredient.fromJson(jsonDecode(e.data))).toList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches for an ingredient
|
/// Searches for an ingredient
|
||||||
@@ -432,7 +444,7 @@ class NutritionPlansProvider with ChangeNotifier {
|
|||||||
baseProvider.makeUrl(
|
baseProvider.makeUrl(
|
||||||
_nutritionDiaryPath,
|
_nutritionDiaryPath,
|
||||||
query: {
|
query: {
|
||||||
'plan': plan.id.toString(),
|
'plan': plan.id?.toString(),
|
||||||
'limit': '999',
|
'limit': '999',
|
||||||
'ordering': 'datetime',
|
'ordering': 'datetime',
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user