Skip to content

Commit 5a1da39

Browse files
authored
Merge pull request #453 from wger-project/feat/data-persistence
feat(drift-database): Shifted from shared prefs to drift for Exercises
2 parents b9b51db + 8224d52 commit 5a1da39

File tree

99 files changed

+5486
-1142
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+5486
-1142
lines changed

flatpak/scripts/flatpak_shared.dart

Lines changed: 22 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ class Icon {
4444
_fileExtension = path.split('.').last;
4545
}
4646

47-
String getFilename(String appId) => (type == _symbolicType)
48-
? '$appId-symbolic.$_fileExtension'
49-
: '$appId.$_fileExtension';
47+
String getFilename(String appId) =>
48+
(type == _symbolicType) ? '$appId-symbolic.$_fileExtension' : '$appId.$_fileExtension';
5049
}
5150

5251
class GithubReleases {
@@ -75,8 +74,7 @@ class GithubReleases {
7574
final releaseJsonContent = (await http.get(Uri(
7675
scheme: 'https',
7776
host: 'api.github.com',
78-
path:
79-
'/repos/$githubReleaseOrganization/$githubReleaseProject/releases')))
77+
path: '/repos/$githubReleaseOrganization/$githubReleaseProject/releases')))
8078
.body;
8179
final decodedJson = jsonDecode(releaseJsonContent) as List;
8280

@@ -87,23 +85,19 @@ class GithubReleases {
8785
await Future.forEach<dynamic>(decodedJson, (dynamic releaseDynamic) async {
8886
final releaseMap = releaseDynamic as Map;
8987

90-
final releaseDateAndTime =
91-
DateTime.parse(releaseMap['published_at'] as String);
92-
final releaseDateString =
93-
releaseDateAndTime.toIso8601String().split('T').first;
88+
final releaseDateAndTime = DateTime.parse(releaseMap['published_at'] as String);
89+
final releaseDateString = releaseDateAndTime.toIso8601String().split('T').first;
9490

9591
if (latestReleaseAssetDate == null ||
9692
(latestReleaseAssetDate?.compareTo(releaseDateAndTime) == -1)) {
97-
final assets =
98-
await _parseGithubReleaseAssets(releaseMap['assets'] as List);
93+
final assets = await _parseGithubReleaseAssets(releaseMap['assets'] as List);
9994
if (assets != null) {
10095
_latestReleaseAssets = assets;
10196
latestReleaseAssetDate = releaseDateAndTime;
10297
}
10398
}
10499

105-
releases.add(Release(
106-
version: releaseMap['name'] as String, date: releaseDateString));
100+
releases.add(Release(version: releaseMap['name'] as String, date: releaseDateString));
107101
});
108102

109103
if (releases.isNotEmpty || canBeEmpty) {
@@ -124,8 +118,7 @@ class GithubReleases {
124118
final downloadUrl = amMap['browser_download_url'] as String;
125119
final filename = amMap['name'] as String;
126120
final fileExtension = filename.substring(filename.indexOf('.') + 1);
127-
final filenameWithoutExtension =
128-
filename.substring(0, filename.indexOf('.'));
121+
final filenameWithoutExtension = filename.substring(0, filename.indexOf('.'));
129122

130123
final arch = filenameWithoutExtension.endsWith('aarch64')
131124
? CPUArchitecture.aarch64
@@ -221,8 +214,7 @@ class FlatpakMeta {
221214
: _localReleases = localReleases,
222215
_localReleaseAssets = localReleaseAssets {
223216
if (githubReleaseOrganization != null && githubReleaseProject != null) {
224-
_githubReleases =
225-
GithubReleases(githubReleaseOrganization!, githubReleaseProject!);
217+
_githubReleases = GithubReleases(githubReleaseOrganization!, githubReleaseProject!);
226218
}
227219
}
228220

@@ -231,20 +223,17 @@ class FlatpakMeta {
231223
final releases = List<Release>.empty(growable: true);
232224
if (addedTodaysVersion != null) {
233225
releases.add(Release(
234-
version: addedTodaysVersion,
235-
date: DateTime.now().toIso8601String().split("T").first));
226+
version: addedTodaysVersion, date: DateTime.now().toIso8601String().split("T").first));
236227
}
237228
if (fetchReleasesFromGithub) {
238229
if (_githubReleases == null) {
239230
throw Exception(
240231
'Metadata must include Github repository info if fetching releases from Github.');
241232
}
242-
releases.addAll(
243-
await _githubReleases!.getReleases(addedTodaysVersion != null));
233+
releases.addAll(await _githubReleases!.getReleases(addedTodaysVersion != null));
244234
} else {
245235
if (_localReleases == null && addedTodaysVersion == null) {
246-
throw Exception(
247-
'Metadata must include releases if not fetching releases from Github.');
236+
throw Exception('Metadata must include releases if not fetching releases from Github.');
248237
}
249238
if (_localReleases?.isNotEmpty ?? false) {
250239
releases.addAll(_localReleases!);
@@ -253,8 +242,7 @@ class FlatpakMeta {
253242
return releases;
254243
}
255244

256-
Future<List<ReleaseAsset>?> getLatestReleaseAssets(
257-
bool fetchReleasesFromGithub) async {
245+
Future<List<ReleaseAsset>?> getLatestReleaseAssets(bool fetchReleasesFromGithub) async {
258246
if (fetchReleasesFromGithub) {
259247
if (_githubReleases == null) {
260248
throw Exception(
@@ -263,8 +251,7 @@ class FlatpakMeta {
263251
return await _githubReleases!.getLatestReleaseAssets();
264252
} else {
265253
if (_localReleases == null) {
266-
throw Exception(
267-
'Metadata must include releases if not fetching releases from Github.');
254+
throw Exception('Metadata must include releases if not fetching releases from Github.');
268255
}
269256
return _localReleaseAssets;
270257
}
@@ -276,24 +263,20 @@ class FlatpakMeta {
276263
return FlatpakMeta(
277264
appId: json['appId'] as String,
278265
lowercaseAppName: json['lowercaseAppName'] as String,
279-
githubReleaseOrganization:
280-
json['githubReleaseOrganization'] as String?,
266+
githubReleaseOrganization: json['githubReleaseOrganization'] as String?,
281267
githubReleaseProject: json['githubReleaseProject'] as String?,
282268
localReleases: skipLocalReleases
283269
? null
284270
: (json['localReleases'] as List?)?.map((dynamic r) {
285271
final rMap = r as Map;
286-
return Release(
287-
version: rMap['version'] as String,
288-
date: rMap['date'] as String);
272+
return Release(version: rMap['version'] as String, date: rMap['date'] as String);
289273
}).toList(),
290274
localReleaseAssets: skipLocalReleases
291275
? null
292276
: (json['localReleaseAssets'] as List?)?.map((dynamic ra) {
293277
final raMap = ra as Map;
294278
final archString = raMap['arch'] as String;
295-
final arch = (archString ==
296-
CPUArchitecture.x86_64.flatpakArchCode)
279+
final arch = (archString == CPUArchitecture.x86_64.flatpakArchCode)
297280
? CPUArchitecture.x86_64
298281
: (archString == CPUArchitecture.aarch64.flatpakArchCode)
299282
? CPUArchitecture.aarch64
@@ -302,11 +285,10 @@ class FlatpakMeta {
302285
throw Exception(
303286
'Architecture must be either "${CPUArchitecture.x86_64.flatpakArchCode}" or "${CPUArchitecture.aarch64.flatpakArchCode}"');
304287
}
305-
final tarballFile = File(
306-
'${jsonFile.parent.path}/${raMap['tarballPath'] as String}');
288+
final tarballFile =
289+
File('${jsonFile.parent.path}/${raMap['tarballPath'] as String}');
307290
final tarballPath = tarballFile.absolute.path;
308-
final preShasum =
309-
Process.runSync('shasum', ['-a', '256', tarballPath]);
291+
final preShasum = Process.runSync('shasum', ['-a', '256', tarballPath]);
310292
final shasum = preShasum.stdout.toString().split(' ').first;
311293
if (preShasum.exitCode != 0) {
312294
throw Exception(preShasum.stderr);
@@ -321,17 +303,14 @@ class FlatpakMeta {
321303
appStreamPath: json['appStreamPath'] as String,
322304
desktopPath: json['desktopPath'] as String,
323305
icons: (json['icons'] as Map).entries.map((mapEntry) {
324-
return Icon(
325-
type: mapEntry.key as String, path: mapEntry.value as String);
306+
return Icon(type: mapEntry.key as String, path: mapEntry.value as String);
326307
}).toList(),
327308
freedesktopRuntime: json['freedesktopRuntime'] as String,
328309
buildCommandsAfterUnpack: (json['buildCommandsAfterUnpack'] as List?)
329310
?.map((dynamic bc) => bc as String)
330311
.toList(),
331312
extraModules: json['extraModules'] as List?,
332-
finishArgs: (json['finishArgs'] as List)
333-
.map((dynamic fa) => fa as String)
334-
.toList());
313+
finishArgs: (json['finishArgs'] as List).map((dynamic fa) => fa as String).toList());
335314
} catch (e) {
336315
throw Exception('Could not parse JSON file, due to this error:\n$e');
337316
}

flatpak/scripts/manifest_generator.dart

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ void main(List<String> arguments) async {
2626
'You must run this script with a metadata file argument, using the --meta flag.');
2727
}
2828
if (arguments.length == metaIndex + 1) {
29-
throw Exception(
30-
'The --meta flag must be followed by the path to the metadata file.');
29+
throw Exception('The --meta flag must be followed by the path to the metadata file.');
3130
}
3231

3332
final metaFile = File(arguments[metaIndex + 1]);
@@ -37,23 +36,19 @@ void main(List<String> arguments) async {
3736

3837
final fetchFromGithub = arguments.contains('--github');
3938

40-
final meta =
41-
FlatpakMeta.fromJson(metaFile, skipLocalReleases: fetchFromGithub);
39+
final meta = FlatpakMeta.fromJson(metaFile, skipLocalReleases: fetchFromGithub);
4240

43-
final outputDir =
44-
Directory('${Directory.current.path}/flatpak_generator_exports');
41+
final outputDir = Directory('${Directory.current.path}/flatpak_generator_exports');
4542
outputDir.createSync();
4643

4744
final manifestGenerator = FlatpakManifestGenerator(meta);
48-
final manifestContent =
49-
await manifestGenerator.generateFlatpakManifest(fetchFromGithub);
45+
final manifestContent = await manifestGenerator.generateFlatpakManifest(fetchFromGithub);
5046
final manifestPath = '${outputDir.path}/${meta.appId}.json';
5147
final manifestFile = File(manifestPath);
5248
manifestFile.writeAsStringSync(manifestContent);
5349
print('Generated $manifestPath');
5450

55-
final flathubJsonContent =
56-
await manifestGenerator.generateFlathubJson(fetchFromGithub);
51+
final flathubJsonContent = await manifestGenerator.generateFlathubJson(fetchFromGithub);
5752
if (flathubJsonContent != null) {
5853
final flathubJsonPath = '${outputDir.path}/flathub.json';
5954
final flathubJsonFile = File(flathubJsonPath);
@@ -132,8 +127,7 @@ class FlatpakManifestGenerator {
132127

133128
const encoder = JsonEncoder.withIndent(' ');
134129

135-
final onlyArchListInput =
136-
fetchFromGithub ? _githubArchSupport! : _localArchSupport!;
130+
final onlyArchListInput = fetchFromGithub ? _githubArchSupport! : _localArchSupport!;
137131

138132
final onlyArchList = List<String>.empty(growable: true);
139133
for (final e in onlyArchListInput.entries) {
@@ -149,8 +143,7 @@ class FlatpakManifestGenerator {
149143
}
150144
}
151145

152-
void _lazyGenerateArchSupportMap(
153-
bool fetchFromGithub, List<ReleaseAsset> assets) {
146+
void _lazyGenerateArchSupportMap(bool fetchFromGithub, List<ReleaseAsset> assets) {
154147
if (fetchFromGithub) {
155148
if (_githubArchSupport == null) {
156149
_githubArchSupport = <CPUArchitecture, bool>{

integration_test/3_gym_mode.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ Widget createGymModeScreen({locale = 'en'}) {
2020

2121
final mockExerciseProvider = MockExercisesProvider();
2222

23-
when(mockExerciseProvider.findExerciseBaseById(1)).thenReturn(bases[0]); // bench press
24-
when(mockExerciseProvider.findExerciseBaseById(6)).thenReturn(bases[5]); // side raises
23+
when(mockExerciseProvider.findExerciseById(1)).thenReturn(bases[0]); // bench press
24+
when(mockExerciseProvider.findExerciseById(6)).thenReturn(bases[5]); // side raises
2525
//when(mockExerciseProvider.findExerciseBaseById(2)).thenReturn(bases[1]); // crunches
2626
//when(mockExerciseProvider.findExerciseBaseById(3)).thenReturn(bases[2]); // dead lift
2727

lib/core/locator.dart

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import 'dart:developer';
2+
import 'dart:io';
3+
4+
import 'package:drift/native.dart';
5+
import 'package:get_it/get_it.dart';
6+
import 'package:wger/database/exercises/exercise_database.dart';
7+
import 'package:wger/database/ingredients/ingredients_database.dart';
8+
9+
final locator = GetIt.asNewInstance();
10+
11+
class ServiceLocator {
12+
factory ServiceLocator() => _singleton;
13+
14+
ServiceLocator._internal();
15+
16+
static final ServiceLocator _singleton = ServiceLocator._internal();
17+
18+
Future<void> _initDB() async {
19+
ExerciseDatabase exerciseDB;
20+
IngredientDatabase ingredientDB;
21+
// final exerciseDB = ExerciseDatabase();
22+
// final ingredientDB = IngredientDatabase();
23+
24+
if (Platform.environment.containsKey('FLUTTER_TEST')) {
25+
exerciseDB = ExerciseDatabase.inMemory(NativeDatabase.memory());
26+
ingredientDB = IngredientDatabase.inMemory(NativeDatabase.memory());
27+
} else {
28+
exerciseDB = ExerciseDatabase();
29+
ingredientDB = IngredientDatabase();
30+
}
31+
32+
locator.registerSingleton<ExerciseDatabase>(exerciseDB);
33+
locator.registerSingleton<IngredientDatabase>(ingredientDB);
34+
}
35+
36+
Future<void> configure() async {
37+
try {
38+
await _initDB();
39+
} catch (e, _) {
40+
log(e.toString());
41+
rethrow;
42+
}
43+
}
44+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import 'dart:io';
2+
3+
import 'package:drift/drift.dart';
4+
import 'package:drift/native.dart';
5+
import 'package:path/path.dart' as p;
6+
import 'package:path_provider/path_provider.dart';
7+
import 'package:wger/database/exercises/type_converters.dart';
8+
import 'package:wger/models/exercises/category.dart';
9+
import 'package:wger/models/exercises/equipment.dart';
10+
import 'package:wger/models/exercises/language.dart';
11+
import 'package:wger/models/exercises/muscle.dart';
12+
13+
part 'exercise_database.g.dart';
14+
15+
@DataClassName('ExerciseTable')
16+
class Exercises extends Table {
17+
IntColumn get id => integer()();
18+
19+
TextColumn get data => text()();
20+
21+
// TextColumn get data => text().map(const ExerciseBaseConverter())();
22+
23+
DateTimeColumn get lastUpdate => dateTime()();
24+
25+
/// The date when the exercise was last fetched from the API. While we know
26+
/// when the exercise itself was last updated in `lastUpdate`, we can save
27+
/// ourselves a lot of requests if we don't check too often
28+
DateTimeColumn get lastFetched => dateTime()();
29+
}
30+
31+
@DataClassName('MuscleTable')
32+
class Muscles extends Table {
33+
IntColumn get id => integer()();
34+
35+
TextColumn get data => text().map(const MuscleConverter())();
36+
}
37+
38+
@DataClassName('CategoryTable')
39+
class Categories extends Table {
40+
IntColumn get id => integer()();
41+
42+
TextColumn get data => text().map(const ExerciseCategoryConverter())();
43+
}
44+
45+
@DataClassName('LanguagesTable')
46+
class Languages extends Table {
47+
IntColumn get id => integer()();
48+
49+
TextColumn get data => text().map(const LanguageConverter())();
50+
}
51+
52+
@DataClassName('EquipmentTable')
53+
class Equipments extends Table {
54+
IntColumn get id => integer()();
55+
56+
TextColumn get data => text().map(const EquipmentConverter())();
57+
}
58+
59+
@DriftDatabase(tables: [Exercises, Muscles, Equipments, Categories, Languages])
60+
class ExerciseDatabase extends _$ExerciseDatabase {
61+
ExerciseDatabase() : super(_openConnection());
62+
63+
// Named constructor for creating in-memory database
64+
ExerciseDatabase.inMemory(super.e);
65+
66+
@override
67+
// TODO: implement schemaVersion
68+
int get schemaVersion => 1;
69+
70+
Future<void> deleteEverything() {
71+
return transaction(() async {
72+
for (final table in allTables) {
73+
await delete(table).go();
74+
}
75+
});
76+
}
77+
}
78+
79+
LazyDatabase _openConnection() {
80+
return LazyDatabase(() async {
81+
final dbFolder = await getApplicationCacheDirectory();
82+
final file = File(p.join(dbFolder.path, 'exercises.sqlite'));
83+
return NativeDatabase.createInBackground(file);
84+
});
85+
}

0 commit comments

Comments
 (0)