diff --git a/.gitignore b/.gitignore
index a901f0a..90407e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,7 @@ UNTRANSLATED.txt
# Generated code
*.g.dart
*.freezed.dart
+# All except the generated code for the realm classes
+# Realm and riverpod code generation does not work nicely together.
+# Keep the one file from Realm to avoid ongoing code generation issues.
+!lib/src/data/book/realm/realm_book.g.dart
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index c64ec3c..ed1b987 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -37,8 +37,7 @@ android {
}
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId "at.shockbytes.dantex"
+ applicationId "at.shockbytes.dante"
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 9625e10..7c56964 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 11.0
+ 12.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index f2de4d8..14021d4 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -24,26 +24,26 @@ PODS:
- Firebase/Storage (10.18.0):
- Firebase/CoreOnly
- FirebaseStorage (~> 10.18.0)
- - firebase_analytics (10.7.2):
+ - firebase_analytics (10.8.0):
- Firebase/Analytics (= 10.18.0)
- firebase_core
- Flutter
- - firebase_auth (4.15.0):
+ - firebase_auth (4.16.0):
- Firebase/Auth (= 10.18.0)
- firebase_core
- Flutter
- - firebase_core (2.24.0):
+ - firebase_core (2.24.2):
- Firebase/CoreOnly (= 10.18.0)
- Flutter
- - firebase_crashlytics (3.4.6):
+ - firebase_crashlytics (3.4.9):
- Firebase/Crashlytics (= 10.18.0)
- firebase_core
- Flutter
- - firebase_database (10.3.6):
+ - firebase_database (10.4.0):
- Firebase/Database (= 10.18.0)
- firebase_core
- Flutter
- - firebase_storage (11.5.3):
+ - firebase_storage (11.6.0):
- Firebase/Storage (= 10.18.0)
- firebase_core
- Flutter
@@ -123,7 +123,8 @@ PODS:
- FMDB/standard (2.7.5)
- google_sign_in_ios (0.0.1):
- Flutter
- - GoogleSignIn (~> 6.2)
+ - FlutterMacOS
+ - GoogleSignIn (~> 7.0)
- GoogleAppMeasurement (10.18.0):
- GoogleAppMeasurement/AdIdSupport (= 10.18.0)
- GoogleUtilities/AppDelegateSwizzler (~> 7.11)
@@ -148,10 +149,10 @@ PODS:
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30910.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- - GoogleSignIn (6.2.4):
+ - GoogleSignIn (7.0.0):
- AppAuth (~> 1.5)
- - GTMAppAuth (~> 1.3)
- - GTMSessionFetcher/Core (< 3.0, >= 1.1)
+ - GTMAppAuth (< 3.0, >= 1.3)
+ - GTMSessionFetcher/Core (< 4.0, >= 1.1)
- GoogleUtilities/AppDelegateSwizzler (7.12.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
@@ -171,9 +172,9 @@ PODS:
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (7.12.0):
- GoogleUtilities/Logger
- - GTMAppAuth (1.3.1):
+ - GTMAppAuth (2.0.0):
- AppAuth/Core (~> 1.6)
- - GTMSessionFetcher/Core (< 3.0, >= 1.5)
+ - GTMSessionFetcher/Core (< 4.0, >= 1.5)
- GTMSessionFetcher/Core (2.3.0)
- leveldb-library (1.22.2)
- nanopb (2.30909.1):
@@ -187,6 +188,8 @@ PODS:
- PromisesObjC (2.3.1)
- PromisesSwift (2.3.1):
- PromisesObjC (= 2.3.1)
+ - realm (1.6.1):
+ - Flutter
- RecaptchaInterop (100.0.0)
- shared_preferences_foundation (0.0.1):
- Flutter
@@ -206,8 +209,9 @@ DEPENDENCIES:
- firebase_storage (from `.symlinks/plugins/firebase_storage/ios`)
- Flutter (from `Flutter`)
- flutter_barcode_scanner (from `.symlinks/plugins/flutter_barcode_scanner/ios`)
- - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/ios`)
+ - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
+ - realm (from `.symlinks/plugins/realm/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@@ -260,9 +264,11 @@ EXTERNAL SOURCES:
flutter_barcode_scanner:
:path: ".symlinks/plugins/flutter_barcode_scanner/ios"
google_sign_in_ios:
- :path: ".symlinks/plugins/google_sign_in_ios/ios"
+ :path: ".symlinks/plugins/google_sign_in_ios/darwin"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
+ realm:
+ :path: ".symlinks/plugins/realm/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite:
@@ -273,12 +279,12 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
AppAuth: 3bb1d1cd9340bd09f5ed189fb00b1cc28e1e8570
Firebase: 414ad272f8d02dfbf12662a9d43f4bba9bec2a06
- firebase_analytics: a8c0d8ba83f213c9b775b5f61d36dadaafb1b239
- firebase_auth: 02d1a6340f81020cc302fb8fea8518908c546cec
- firebase_core: f802c5c1f6caff9b8d38b591a36e7b25f8878936
- firebase_crashlytics: 0db78a5b6badc630f21a833d0c9ab20ab5d81948
- firebase_database: 18b34a683c878f836ac5a403ce29242065d5acd0
- firebase_storage: 95b470ab32351049dfd3d97b595460ce7a189971
+ firebase_analytics: b3d6dd14c61549a29abb10e9843446a4d8bb53eb
+ firebase_auth: 8e9ec02991ca4659111cc671c84d0c010b6bfb26
+ firebase_core: 0af4a2b24f62071f9bf283691c0ee41556dcb3f5
+ firebase_crashlytics: 4b91b8ad60ee7c168fe88979f84c9573a729de7a
+ firebase_database: 5d420ac53c48f3394445c8b83c530a42d149c3d4
+ firebase_storage: 2b932fa5461f4efac36a2dcfbe240898b190b5b1
FirebaseAnalytics: 4d310b35c48eaa4a058ddc04bdca6bdb5dc0fe80
FirebaseAppCheckInterop: 3cd914842ba46f4304050874cd284de82f154ffd
FirebaseAuth: 12314b438fa76048540c8fb86d6cfc9e08595176
@@ -292,25 +298,26 @@ SPEC CHECKSUMS:
FirebaseSessions: f90fe9212ee2818641eda051c0835c9c4e30d9ae
FirebaseSharedSwift: 62e248642c0582324d0390706cadd314687c116b
FirebaseStorage: 8333c4b183764cdd170d9539a61322b71c23adff
- Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
+ Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_barcode_scanner: 7a1144744c28dc0c57a8de7218ffe5ec59a9e4bf
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
- google_sign_in_ios: 1256ff9d941db546373826966720b0c24804bcdd
+ google_sign_in_ios: 1bfaf6607b44cd1b24c4d4bc39719870440f9ce1
GoogleAppMeasurement: 70ce9aa438cff1cfb31ea3e660bcc67734cb716e
GoogleDataTransport: 57c22343ab29bc686febbf7cbb13bad167c2d8fe
- GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a
+ GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842
GoogleUtilities: 0759d1a57ebb953965c2dfe0ba4c82e95ccc2e34
- GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd
+ GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2
leveldb-library: f03246171cce0484482ec291f88b6d563699ee06
nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5
- path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
+ path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265
+ realm: d2cda90107b12761cef58f16a606f4d14333b071
RecaptchaInterop: 7d1a4a01a6b2cb1610a47ef3f85f0c411434cb21
- shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
+ shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
- url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
+ url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
PODFILE CHECKSUM: 7adbc9d59f05e1b01f554ea99b6c79e97f2214a2
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 6e65f1a..a95464c 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -146,6 +146,7 @@
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
2E18E51AD90C59402E14BDEC /* [CP] Embed Pods Frameworks */,
BE07253FC1FD406B03000781 /* [firebase_crashlytics] Crashlytics Upload Symbols */,
+ D826D48A3F0835A21664F0B1 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -296,6 +297,23 @@
shellPath = /bin/sh;
shellScript = "\"$PODS_ROOT/FirebaseCrashlytics/upload-symbols\" --flutter-project \"$PROJECT_DIR/firebase_app_id_file.json\" ";
};
+ D826D48A3F0835A21664F0B1 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
diff --git a/lib/src/data/authentication/firebase_authentication_repository.dart b/lib/src/data/authentication/firebase_authentication_repository.dart
index 1104065..150f9c5 100644
--- a/lib/src/data/authentication/firebase_authentication_repository.dart
+++ b/lib/src/data/authentication/firebase_authentication_repository.dart
@@ -1,13 +1,18 @@
import 'package:collection/collection.dart';
import 'package:dantex/src/data/authentication/authentication_repository.dart';
import 'package:dantex/src/data/authentication/entity/dante_user.dart';
+import 'package:dantex/src/data/authentication/on_user_authenticated_plugin.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
class FirebaseAuthenticationRepository implements AuthenticationRepository {
final FirebaseAuth _fbAuth;
+ final List _onUserAuthenticatedPlugins;
- FirebaseAuthenticationRepository(this._fbAuth);
+ FirebaseAuthenticationRepository(
+ this._fbAuth,
+ this._onUserAuthenticatedPlugins,
+ );
@override
Stream get authStateChanges =>
@@ -35,7 +40,7 @@ class FirebaseAuthenticationRepository implements AuthenticationRepository {
return null;
}
- return DanteUser(
+ final DanteUser user = DanteUser(
givenName: fbUser.displayName,
displayName: fbUser.displayName,
email: fbUser.email,
@@ -44,6 +49,10 @@ class FirebaseAuthenticationRepository implements AuthenticationRepository {
userId: fbUser.uid,
source: _retrieveAuthenticationSource(fbUser),
);
+
+ _callOnUserAuthenticatedPlugins(user);
+
+ return user;
}
AuthenticationSource _retrieveAuthenticationSource(User user) {
@@ -58,6 +67,12 @@ class FirebaseAuthenticationRepository implements AuthenticationRepository {
}
}
+ void _callOnUserAuthenticatedPlugins(DanteUser user) {
+ for (var plugin in _onUserAuthenticatedPlugins) {
+ plugin.onUserAuthenticated(user);
+ }
+ }
+
bool _isAnonymous(User user) => user.isAnonymous;
bool _isGoogleUser(User user) =>
diff --git a/lib/src/data/authentication/on_user_authenticated_plugin.dart b/lib/src/data/authentication/on_user_authenticated_plugin.dart
new file mode 100644
index 0000000..7135da6
--- /dev/null
+++ b/lib/src/data/authentication/on_user_authenticated_plugin.dart
@@ -0,0 +1,8 @@
+
+
+import 'package:dantex/src/data/authentication/entity/dante_user.dart';
+
+abstract class OnUserAuthenticatedPlugin {
+
+ void onUserAuthenticated(DanteUser user);
+}
\ No newline at end of file
diff --git a/lib/src/data/authentication/plugin/realm_migration_on_user_authenticated_plugin.dart b/lib/src/data/authentication/plugin/realm_migration_on_user_authenticated_plugin.dart
new file mode 100644
index 0000000..36a03fc
--- /dev/null
+++ b/lib/src/data/authentication/plugin/realm_migration_on_user_authenticated_plugin.dart
@@ -0,0 +1,21 @@
+import 'dart:async';
+
+import 'package:dantex/src/data/authentication/entity/dante_user.dart';
+import 'package:dantex/src/data/authentication/on_user_authenticated_plugin.dart';
+import 'package:dantex/src/data/book/migration/migration_runner.dart';
+
+class RealmMigrationOnUserAuthenticatedPlugin
+ implements OnUserAuthenticatedPlugin {
+ final MigrationRunner _migrationRunner;
+
+ RealmMigrationOnUserAuthenticatedPlugin(
+ this._migrationRunner,
+ );
+
+ @override
+ void onUserAuthenticated(DanteUser user) {
+ unawaited(
+ _migrationRunner.migrateIfRequired(),
+ );
+ }
+}
diff --git a/lib/src/data/book/entity/page_record.dart b/lib/src/data/book/entity/page_record.dart
new file mode 100644
index 0000000..1ef4641
--- /dev/null
+++ b/lib/src/data/book/entity/page_record.dart
@@ -0,0 +1,23 @@
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+part 'page_record.freezed.dart';
+part 'page_record.g.dart';
+
+@freezed
+class PageRecord with _$PageRecord {
+
+ const PageRecord._();
+
+ const factory PageRecord({
+ required String id,
+ required String bookId,
+ required int fromPage,
+ required int toPage,
+ required DateTime dateTime,
+ }) = _PageRecord;
+
+ int get diffPages => toPage - fromPage;
+
+ factory PageRecord.fromJson(Map json) =>
+ _$PageRecordFromJson(json);
+}
diff --git a/lib/src/data/book/firebase_book_label_repository.dart b/lib/src/data/book/firebase_book_label_repository.dart
index 27e7a39..0d716af 100644
--- a/lib/src/data/book/firebase_book_label_repository.dart
+++ b/lib/src/data/book/firebase_book_label_repository.dart
@@ -1,5 +1,6 @@
import 'package:dantex/src/data/book/book_label_repository.dart';
import 'package:dantex/src/data/book/entity/book_label.dart';
+import 'package:dantex/src/data/book/firebase_utils.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
@@ -49,10 +50,4 @@ class FirebaseBookLabelRepository implements BookLabelRepository {
final user = _fbAuth.currentUser!.uid;
return _fbDb.ref('users/$user/labels/');
}
-}
-
-extension DataSnapshotExtension on DataSnapshot {
- Map? toMap() {
- return (value != null) ? (value as Map).cast() : null;
- }
-}
+}
\ No newline at end of file
diff --git a/lib/src/data/book/firebase_book_repository.dart b/lib/src/data/book/firebase_book_repository.dart
index e6b8f8e..836ccdd 100644
--- a/lib/src/data/book/firebase_book_repository.dart
+++ b/lib/src/data/book/firebase_book_repository.dart
@@ -2,6 +2,7 @@ import 'package:dantex/src/data/book/book_repository.dart';
import 'package:dantex/src/data/book/entity/book.dart';
import 'package:dantex/src/data/book/entity/book_label.dart';
import 'package:dantex/src/data/book/entity/book_state.dart';
+import 'package:dantex/src/data/book/firebase_utils.dart';
import 'package:dantex/src/data/book/search_criteria.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
@@ -217,9 +218,3 @@ class FirebaseBookRepository implements BookRepository {
}
}
}
-
-extension DataSnapshotExtension on DataSnapshot {
- Map? toMap() {
- return (value != null) ? (value as Map).cast() : null;
- }
-}
diff --git a/lib/src/data/book/firebase_page_record_repository.dart b/lib/src/data/book/firebase_page_record_repository.dart
new file mode 100644
index 0000000..cd57fcf
--- /dev/null
+++ b/lib/src/data/book/firebase_page_record_repository.dart
@@ -0,0 +1,99 @@
+import 'package:dantex/src/data/book/entity/page_record.dart';
+import 'package:dantex/src/data/book/firebase_utils.dart';
+import 'package:dantex/src/data/book/page_record_repository.dart';
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:firebase_database/firebase_database.dart';
+
+class FirebasePageRecordRepository implements PageRecordRepository {
+ final FirebaseAuth _fbAuth;
+ final FirebaseDatabase _fbDb;
+
+ FirebasePageRecordRepository(this._fbAuth, this._fbDb);
+
+ @override
+ Future> allPageRecords() {
+ return _rootRef().get().then(_fromDataSnapshot);
+ }
+
+ @override
+ Future deleteAllPageRecordsForBookId(String bookId) async {
+ final List records = await pageRecordsForBook(bookId);
+ records.forEach(deletePageRecord);
+ }
+
+ @override
+ Future deletePageRecord(PageRecord pageRecord) async {
+ await _rootRef().child(pageRecord.id).remove();
+ }
+
+ @override
+ Future insertPageRecordForBookId(
+ String bookId,
+ int fromPage,
+ int toPage,
+ DateTime now,
+ ) async {
+ final DatabaseReference newRef = _rootRef().push();
+
+ final Map data = PageRecord(
+ id: newRef.key!,
+ bookId: bookId,
+ fromPage: fromPage,
+ toPage: toPage,
+ dateTime: now,
+ ).toJson();
+
+ return newRef.set(data);
+ }
+
+ @override
+ Future> pageRecordsForBook(String bookId) async {
+ return _rootRef()
+ .equalTo('bookId', key: bookId)
+ .get()
+ .then(_fromDataSnapshot);
+ }
+
+ @override
+ Future updatePageRecord(
+ PageRecord pageRecord,
+ int? fromPage,
+ int? toPage,
+ ) {
+ return _rootRef().child(pageRecord.id).set(
+ pageRecord.copyWith(
+ // Use currently set values, if values are null.
+ fromPage: fromPage ?? pageRecord.fromPage,
+ toPage: toPage ?? pageRecord.toPage,
+ ),
+ );
+ }
+
+ List _fromDataSnapshot(DataSnapshot snapshot) {
+ final Map? data = snapshot.toMap();
+
+ if (data == null) {
+ return [];
+ }
+
+ return data
+ .map(
+ (key, value) {
+ final Map pageRecordMap =
+ (value as Map).cast();
+ final PageRecord pageRecord = PageRecord.fromJson(pageRecordMap);
+ return MapEntry(key, pageRecord);
+ },
+ )
+ .values
+ .toList();
+ }
+
+ DatabaseReference _rootRef() {
+ // At this point we can assume that the customer is already logged in,
+ // even as anonymous user
+ final user = _fbAuth.currentUser!.uid;
+ return _fbDb.ref('users/$user/page-records');
+ }
+}
+
diff --git a/lib/src/data/book/firebase_utils.dart b/lib/src/data/book/firebase_utils.dart
new file mode 100644
index 0000000..21e17c1
--- /dev/null
+++ b/lib/src/data/book/firebase_utils.dart
@@ -0,0 +1,7 @@
+import 'package:firebase_database/firebase_database.dart';
+
+extension DataSnapshotExtension on DataSnapshot {
+ Map? toMap() {
+ return (value != null) ? (value as Map).cast() : null;
+ }
+}
diff --git a/lib/src/data/book/migration/migration_result.dart b/lib/src/data/book/migration/migration_result.dart
new file mode 100644
index 0000000..5a3e8df
--- /dev/null
+++ b/lib/src/data/book/migration/migration_result.dart
@@ -0,0 +1,29 @@
+class MigrationResult {
+ final int booksToMigrate;
+ final int migratedBooks;
+ final int pageRecordsToMigrate;
+ final int migratedPageRecords;
+
+ MigrationResult({
+ required this.booksToMigrate,
+ required this.migratedBooks,
+ required this.pageRecordsToMigrate,
+ required this.migratedPageRecords,
+ });
+
+ bool isSuccessful() {
+ return booksToMigrate == migratedBooks &&
+ pageRecordsToMigrate == migratedPageRecords;
+ }
+
+ MigrationStatus statusFromScore() {
+ return isSuccessful() ? MigrationStatus.migrated : MigrationStatus.failed;
+ }
+}
+
+enum MigrationStatus {
+ required, // A migration needs to run
+ migrated, // A migration has been executed
+ failed, // The migration failed
+ unsupportedPlatform, // Migrations will only run on Android
+}
diff --git a/lib/src/data/book/migration/migration_runner.dart b/lib/src/data/book/migration/migration_runner.dart
new file mode 100644
index 0000000..6b32aac
--- /dev/null
+++ b/lib/src/data/book/migration/migration_runner.dart
@@ -0,0 +1,143 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:dantex/src/data/book/book_repository.dart';
+import 'package:dantex/src/data/book/entity/book.dart';
+import 'package:dantex/src/data/book/entity/page_record.dart';
+import 'package:dantex/src/data/book/migration/migration_result.dart';
+import 'package:dantex/src/data/book/page_record_repository.dart';
+import 'package:dantex/src/data/settings/settings_repository.dart';
+import 'package:logger/logger.dart';
+
+/// Runs the migration from the old Android app to the new cross platform app.
+/// The runner essentially fetches all data from Realm and pipes it to Firebase.
+class MigrationRunner {
+ final BookRepository _bookTarget;
+ final BookRepository _bookSource;
+ final PageRecordRepository _pageRecordTarget;
+ final PageRecordRepository _pageRecordSource;
+ final Logger _logger;
+ final SettingsRepository _settingsRepository;
+
+ MigrationRunner(
+ this._logger,
+ this._settingsRepository,
+ BookRepository bookTarget,
+ BookRepository bookSource,
+ PageRecordRepository pageRecordTarget,
+ PageRecordRepository pageRecordSource,
+ ) : _bookTarget = bookTarget,
+ _bookSource = bookSource,
+ _pageRecordTarget = pageRecordTarget,
+ _pageRecordSource = pageRecordSource;
+
+ Future migrateIfRequired() async {
+ if (!Platform.isAndroid) {
+ _logger.i(
+ 'No migration will run, as the underlying platform is not Android.',
+ );
+ return MigrationStatus.unsupportedPlatform;
+ }
+
+ final MigrationStatus status = await _migrationStatus();
+
+ // If status is not required, return the current status.
+ if (status != MigrationStatus.required) {
+ return status;
+ }
+
+ final MigrationResult result = await _migrate();
+ final MigrationStatus newStatus = result.statusFromScore();
+ _logResult(result);
+ _updateMigrationStatus(newStatus);
+
+ return newStatus;
+ }
+
+ /// Load migration status from settings. If nothing is saved, return required.
+ Future _migrationStatus() async {
+ return _settingsRepository.getRealmMigrationStatus() ??
+ MigrationStatus.required;
+ }
+
+ Future _migrate() async {
+ final ({int migratedBooks, int booksToMigrate}) booksStat =
+ await _migrateBooks();
+
+ final ({
+ int migratedPageRecords,
+ int pageRecordsToMigrate
+ }) pageRecordsStats = await _migratePageRecords();
+
+ return MigrationResult(
+ booksToMigrate: booksStat.booksToMigrate,
+ migratedBooks: booksStat.migratedBooks,
+ pageRecordsToMigrate: pageRecordsStats.pageRecordsToMigrate,
+ migratedPageRecords: pageRecordsStats.migratedPageRecords,
+ );
+ }
+
+ /// Returns no. of migrated instances and potential no. of migrations
+ Future<({int migratedBooks, int booksToMigrate})> _migrateBooks() async {
+ final List booksToMigrate = await _bookSource.getAllBooks().first;
+
+ int migratedBooks = 0;
+ for (int i = 0; i < booksToMigrate.length; i++) {
+ final Book book = booksToMigrate[i];
+
+ try {
+ await _bookTarget.create(book);
+ migratedBooks++;
+ } catch (e) {
+ _logger.f(e);
+ }
+ }
+
+ return (
+ migratedBooks: migratedBooks,
+ booksToMigrate: booksToMigrate.length,
+ );
+ }
+
+ /// Returns no. of migrated instances and potential no. of migrations
+ Future<({int migratedPageRecords, int pageRecordsToMigrate})>
+ _migratePageRecords() async {
+ final List pageRecordsToMigrate =
+ await _pageRecordSource.allPageRecords();
+
+ int migratedPageRecords = 0;
+ for (int i = 0; i < pageRecordsToMigrate.length; i++) {
+ final PageRecord record = pageRecordsToMigrate[i];
+
+ try {
+ await _pageRecordTarget.insertPageRecordForBookId(
+ record.bookId,
+ record.fromPage,
+ record.toPage,
+ record.dateTime,
+ );
+ migratedPageRecords++;
+ } catch (e) {
+ _logger.f(e);
+ }
+ }
+
+ return (
+ migratedPageRecords: migratedPageRecords,
+ pageRecordsToMigrate: pageRecordsToMigrate.length,
+ );
+ }
+
+ void _logResult(MigrationResult r) {
+ _logger.i(
+ 'Migration result status: ${r.statusFromScore().name}\n'
+ '----------------------\n'
+ 'Migrated books: ${r.migratedBooks} / ${r.booksToMigrate}\n'
+ 'Migrated pages: ${r.migratedPageRecords} / ${r.pageRecordsToMigrate}\n',
+ );
+ }
+
+ void _updateMigrationStatus(MigrationStatus newStatus) {
+ unawaited(_settingsRepository.setRealmMigrationStatus(newStatus));
+ }
+}
diff --git a/lib/src/data/book/page_record_repository.dart b/lib/src/data/book/page_record_repository.dart
new file mode 100644
index 0000000..d68e58c
--- /dev/null
+++ b/lib/src/data/book/page_record_repository.dart
@@ -0,0 +1,24 @@
+import 'package:dantex/src/data/book/entity/page_record.dart';
+
+abstract class PageRecordRepository {
+ Future insertPageRecordForBookId(
+ String bookId,
+ int fromPage,
+ int toPage,
+ DateTime now,
+ );
+
+ Future updatePageRecord(
+ PageRecord pageRecord,
+ int? fromPage,
+ int? toPage,
+ );
+
+ Future deletePageRecord(PageRecord pageRecord);
+
+ Future deleteAllPageRecordsForBookId(String bookId);
+
+ Future> pageRecordsForBook(String bookId);
+
+ Future> allPageRecords();
+}
diff --git a/lib/src/data/book/realm/realm_book.dart b/lib/src/data/book/realm/realm_book.dart
new file mode 100644
index 0000000..a33f0c3
--- /dev/null
+++ b/lib/src/data/book/realm/realm_book.dart
@@ -0,0 +1,49 @@
+
+
+import 'package:realm/realm.dart';
+
+part 'realm_book.g.dart';
+
+@RealmModel()
+class _RealmBook {
+
+ @PrimaryKey()
+ late int id;
+ late String? title = '';
+ late String? subTitle = '';
+ late String? author = '';
+ late int pageCount = 0;
+ late String? publishedDate = '';
+ late int position= 0;
+ late String? isbn = '';
+ late String? thumbnailAddress = '';
+ late String? googleBooksLink = '';
+ late int startDate = 0;
+ late int endDate = 0;
+ late int ordinalState = 0;
+ late int wishlistDate = 0;
+ late String? language = 'NA';
+ late int rating = 0;
+ late int currentPage = 0;
+ late String? notes = '';
+ late String? summary = '';
+ late List<_RealmBookLabel> labels = [];
+}
+
+@RealmModel()
+class _RealmBookLabel {
+ late int bookId = -1;
+ late String? title = '';
+ late String? hexColor = '';
+}
+
+@RealmModel()
+class _RealmPageRecord {
+
+ @PrimaryKey()
+ late String? recordId = ''; // of type "bookId-timestamp"
+ late int bookId = -1;
+ late int fromPage = 0;
+ late int toPage = 0;
+ late int timestamp = 0;
+}
\ No newline at end of file
diff --git a/lib/src/data/book/realm/realm_book.g.dart b/lib/src/data/book/realm/realm_book.g.dart
new file mode 100644
index 0000000..15ea08a
--- /dev/null
+++ b/lib/src/data/book/realm/realm_book.g.dart
@@ -0,0 +1,373 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'realm_book.dart';
+
+// **************************************************************************
+// RealmObjectGenerator
+// **************************************************************************
+
+// ignore_for_file: type=lint
+class RealmBook extends _RealmBook
+ with RealmEntity, RealmObjectBase, RealmObject {
+ static var _defaultsSet = false;
+
+ RealmBook(
+ int id, {
+ String? title = '',
+ String? subTitle = '',
+ String? author = '',
+ int pageCount = 0,
+ String? publishedDate = '',
+ int position = 0,
+ String? isbn = '',
+ String? thumbnailAddress = '',
+ String? googleBooksLink = '',
+ int startDate = 0,
+ int endDate = 0,
+ int ordinalState = 0,
+ int wishlistDate = 0,
+ String? language = 'NA',
+ int rating = 0,
+ int currentPage = 0,
+ String? notes = '',
+ String? summary = '',
+ Iterable labels = const [],
+ }) {
+ if (!_defaultsSet) {
+ _defaultsSet = RealmObjectBase.setDefaults({
+ 'title': '',
+ 'subTitle': '',
+ 'author': '',
+ 'pageCount': 0,
+ 'publishedDate': '',
+ 'position': 0,
+ 'isbn': '',
+ 'thumbnailAddress': '',
+ 'googleBooksLink': '',
+ 'startDate': 0,
+ 'endDate': 0,
+ 'ordinalState': 0,
+ 'wishlistDate': 0,
+ 'language': 'NA',
+ 'rating': 0,
+ 'currentPage': 0,
+ 'notes': '',
+ 'summary': '',
+ });
+ }
+ RealmObjectBase.set(this, 'id', id);
+ RealmObjectBase.set(this, 'title', title);
+ RealmObjectBase.set(this, 'subTitle', subTitle);
+ RealmObjectBase.set(this, 'author', author);
+ RealmObjectBase.set(this, 'pageCount', pageCount);
+ RealmObjectBase.set(this, 'publishedDate', publishedDate);
+ RealmObjectBase.set(this, 'position', position);
+ RealmObjectBase.set(this, 'isbn', isbn);
+ RealmObjectBase.set(this, 'thumbnailAddress', thumbnailAddress);
+ RealmObjectBase.set(this, 'googleBooksLink', googleBooksLink);
+ RealmObjectBase.set(this, 'startDate', startDate);
+ RealmObjectBase.set(this, 'endDate', endDate);
+ RealmObjectBase.set(this, 'ordinalState', ordinalState);
+ RealmObjectBase.set(this, 'wishlistDate', wishlistDate);
+ RealmObjectBase.set(this, 'language', language);
+ RealmObjectBase.set(this, 'rating', rating);
+ RealmObjectBase.set(this, 'currentPage', currentPage);
+ RealmObjectBase.set(this, 'notes', notes);
+ RealmObjectBase.set(this, 'summary', summary);
+ RealmObjectBase.set>(
+ this, 'labels', RealmList(labels));
+ }
+
+ RealmBook._();
+
+ @override
+ int get id => RealmObjectBase.get(this, 'id') as int;
+ @override
+ set id(int value) => RealmObjectBase.set(this, 'id', value);
+
+ @override
+ String? get title => RealmObjectBase.get(this, 'title') as String?;
+ @override
+ set title(String? value) => RealmObjectBase.set(this, 'title', value);
+
+ @override
+ String? get subTitle =>
+ RealmObjectBase.get(this, 'subTitle') as String?;
+ @override
+ set subTitle(String? value) => RealmObjectBase.set(this, 'subTitle', value);
+
+ @override
+ String? get author => RealmObjectBase.get(this, 'author') as String?;
+ @override
+ set author(String? value) => RealmObjectBase.set(this, 'author', value);
+
+ @override
+ int get pageCount => RealmObjectBase.get(this, 'pageCount') as int;
+ @override
+ set pageCount(int value) => RealmObjectBase.set(this, 'pageCount', value);
+
+ @override
+ String? get publishedDate =>
+ RealmObjectBase.get(this, 'publishedDate') as String?;
+ @override
+ set publishedDate(String? value) =>
+ RealmObjectBase.set(this, 'publishedDate', value);
+
+ @override
+ int get position => RealmObjectBase.get(this, 'position') as int;
+ @override
+ set position(int value) => RealmObjectBase.set(this, 'position', value);
+
+ @override
+ String? get isbn => RealmObjectBase.get(this, 'isbn') as String?;
+ @override
+ set isbn(String? value) => RealmObjectBase.set(this, 'isbn', value);
+
+ @override
+ String? get thumbnailAddress =>
+ RealmObjectBase.get(this, 'thumbnailAddress') as String?;
+ @override
+ set thumbnailAddress(String? value) =>
+ RealmObjectBase.set(this, 'thumbnailAddress', value);
+
+ @override
+ String? get googleBooksLink =>
+ RealmObjectBase.get(this, 'googleBooksLink') as String?;
+ @override
+ set googleBooksLink(String? value) =>
+ RealmObjectBase.set(this, 'googleBooksLink', value);
+
+ @override
+ int get startDate => RealmObjectBase.get(this, 'startDate') as int;
+ @override
+ set startDate(int value) => RealmObjectBase.set(this, 'startDate', value);
+
+ @override
+ int get endDate => RealmObjectBase.get(this, 'endDate') as int;
+ @override
+ set endDate(int value) => RealmObjectBase.set(this, 'endDate', value);
+
+ @override
+ int get ordinalState => RealmObjectBase.get(this, 'ordinalState') as int;
+ @override
+ set ordinalState(int value) =>
+ RealmObjectBase.set(this, 'ordinalState', value);
+
+ @override
+ int get wishlistDate => RealmObjectBase.get(this, 'wishlistDate') as int;
+ @override
+ set wishlistDate(int value) =>
+ RealmObjectBase.set(this, 'wishlistDate', value);
+
+ @override
+ String? get language =>
+ RealmObjectBase.get(this, 'language') as String?;
+ @override
+ set language(String? value) => RealmObjectBase.set(this, 'language', value);
+
+ @override
+ int get rating => RealmObjectBase.get(this, 'rating') as int;
+ @override
+ set rating(int value) => RealmObjectBase.set(this, 'rating', value);
+
+ @override
+ int get currentPage => RealmObjectBase.get(this, 'currentPage') as int;
+ @override
+ set currentPage(int value) => RealmObjectBase.set(this, 'currentPage', value);
+
+ @override
+ String? get notes => RealmObjectBase.get(this, 'notes') as String?;
+ @override
+ set notes(String? value) => RealmObjectBase.set(this, 'notes', value);
+
+ @override
+ String? get summary =>
+ RealmObjectBase.get(this, 'summary') as String?;
+ @override
+ set summary(String? value) => RealmObjectBase.set(this, 'summary', value);
+
+ @override
+ RealmList get labels =>
+ RealmObjectBase.get(this, 'labels')
+ as RealmList;
+ @override
+ set labels(covariant RealmList value) =>
+ throw RealmUnsupportedSetError();
+
+ @override
+ Stream> get changes =>
+ RealmObjectBase.getChanges(this);
+
+ @override
+ RealmBook freeze() => RealmObjectBase.freezeObject(this);
+
+ static SchemaObject get schema => _schema ??= _initSchema();
+ static SchemaObject? _schema;
+ static SchemaObject _initSchema() {
+ RealmObjectBase.registerFactory(RealmBook._);
+ return const SchemaObject(ObjectType.realmObject, RealmBook, 'RealmBook', [
+ SchemaProperty('id', RealmPropertyType.int, primaryKey: true),
+ SchemaProperty('title', RealmPropertyType.string, optional: true),
+ SchemaProperty('subTitle', RealmPropertyType.string, optional: true),
+ SchemaProperty('author', RealmPropertyType.string, optional: true),
+ SchemaProperty('pageCount', RealmPropertyType.int),
+ SchemaProperty('publishedDate', RealmPropertyType.string, optional: true),
+ SchemaProperty('position', RealmPropertyType.int),
+ SchemaProperty('isbn', RealmPropertyType.string, optional: true),
+ SchemaProperty('thumbnailAddress', RealmPropertyType.string,
+ optional: true),
+ SchemaProperty('googleBooksLink', RealmPropertyType.string,
+ optional: true),
+ SchemaProperty('startDate', RealmPropertyType.int),
+ SchemaProperty('endDate', RealmPropertyType.int),
+ SchemaProperty('ordinalState', RealmPropertyType.int),
+ SchemaProperty('wishlistDate', RealmPropertyType.int),
+ SchemaProperty('language', RealmPropertyType.string, optional: true),
+ SchemaProperty('rating', RealmPropertyType.int),
+ SchemaProperty('currentPage', RealmPropertyType.int),
+ SchemaProperty('notes', RealmPropertyType.string, optional: true),
+ SchemaProperty('summary', RealmPropertyType.string, optional: true),
+ SchemaProperty('labels', RealmPropertyType.object,
+ linkTarget: 'RealmBookLabel',
+ collectionType: RealmCollectionType.list),
+ ]);
+ }
+}
+
+class RealmBookLabel extends _RealmBookLabel
+ with RealmEntity, RealmObjectBase, RealmObject {
+ static var _defaultsSet = false;
+
+ RealmBookLabel({
+ int bookId = -1,
+ String? title = '',
+ String? hexColor = '',
+ }) {
+ if (!_defaultsSet) {
+ _defaultsSet = RealmObjectBase.setDefaults({
+ 'bookId': -1,
+ 'title': '',
+ 'hexColor': '',
+ });
+ }
+ RealmObjectBase.set(this, 'bookId', bookId);
+ RealmObjectBase.set(this, 'title', title);
+ RealmObjectBase.set(this, 'hexColor', hexColor);
+ }
+
+ RealmBookLabel._();
+
+ @override
+ int get bookId => RealmObjectBase.get(this, 'bookId') as int;
+ @override
+ set bookId(int value) => RealmObjectBase.set(this, 'bookId', value);
+
+ @override
+ String? get title => RealmObjectBase.get(this, 'title') as String?;
+ @override
+ set title(String? value) => RealmObjectBase.set(this, 'title', value);
+
+ @override
+ String? get hexColor =>
+ RealmObjectBase.get(this, 'hexColor') as String?;
+ @override
+ set hexColor(String? value) => RealmObjectBase.set(this, 'hexColor', value);
+
+ @override
+ Stream> get changes =>
+ RealmObjectBase.getChanges(this);
+
+ @override
+ RealmBookLabel freeze() => RealmObjectBase.freezeObject(this);
+
+ static SchemaObject get schema => _schema ??= _initSchema();
+ static SchemaObject? _schema;
+ static SchemaObject _initSchema() {
+ RealmObjectBase.registerFactory(RealmBookLabel._);
+ return const SchemaObject(
+ ObjectType.realmObject, RealmBookLabel, 'RealmBookLabel', [
+ SchemaProperty('bookId', RealmPropertyType.int),
+ SchemaProperty('title', RealmPropertyType.string, optional: true),
+ SchemaProperty('hexColor', RealmPropertyType.string, optional: true),
+ ]);
+ }
+}
+
+class RealmPageRecord extends _RealmPageRecord
+ with RealmEntity, RealmObjectBase, RealmObject {
+ static var _defaultsSet = false;
+
+ RealmPageRecord(
+ String? recordId, {
+ int bookId = -1,
+ int fromPage = 0,
+ int toPage = 0,
+ int timestamp = 0,
+ }) {
+ if (!_defaultsSet) {
+ _defaultsSet = RealmObjectBase.setDefaults({
+ 'recordId': '',
+ 'bookId': -1,
+ 'fromPage': 0,
+ 'toPage': 0,
+ 'timestamp': 0,
+ });
+ }
+ RealmObjectBase.set(this, 'recordId', recordId);
+ RealmObjectBase.set(this, 'bookId', bookId);
+ RealmObjectBase.set(this, 'fromPage', fromPage);
+ RealmObjectBase.set(this, 'toPage', toPage);
+ RealmObjectBase.set(this, 'timestamp', timestamp);
+ }
+
+ RealmPageRecord._();
+
+ @override
+ String? get recordId =>
+ RealmObjectBase.get(this, 'recordId') as String?;
+ @override
+ set recordId(String? value) => RealmObjectBase.set(this, 'recordId', value);
+
+ @override
+ int get bookId => RealmObjectBase.get(this, 'bookId') as int;
+ @override
+ set bookId(int value) => RealmObjectBase.set(this, 'bookId', value);
+
+ @override
+ int get fromPage => RealmObjectBase.get(this, 'fromPage') as int;
+ @override
+ set fromPage(int value) => RealmObjectBase.set(this, 'fromPage', value);
+
+ @override
+ int get toPage => RealmObjectBase.get(this, 'toPage') as int;
+ @override
+ set toPage(int value) => RealmObjectBase.set(this, 'toPage', value);
+
+ @override
+ int get timestamp => RealmObjectBase.get(this, 'timestamp') as int;
+ @override
+ set timestamp(int value) => RealmObjectBase.set(this, 'timestamp', value);
+
+ @override
+ Stream> get changes =>
+ RealmObjectBase.getChanges(this);
+
+ @override
+ RealmPageRecord freeze() =>
+ RealmObjectBase.freezeObject(this);
+
+ static SchemaObject get schema => _schema ??= _initSchema();
+ static SchemaObject? _schema;
+ static SchemaObject _initSchema() {
+ RealmObjectBase.registerFactory(RealmPageRecord._);
+ return const SchemaObject(
+ ObjectType.realmObject, RealmPageRecord, 'RealmPageRecord', [
+ SchemaProperty('recordId', RealmPropertyType.string,
+ optional: true, primaryKey: true),
+ SchemaProperty('bookId', RealmPropertyType.int),
+ SchemaProperty('fromPage', RealmPropertyType.int),
+ SchemaProperty('toPage', RealmPropertyType.int),
+ SchemaProperty('timestamp', RealmPropertyType.int),
+ ]);
+ }
+}
diff --git a/lib/src/data/book/realm/realm_book_repository.dart b/lib/src/data/book/realm/realm_book_repository.dart
new file mode 100644
index 0000000..3066657
--- /dev/null
+++ b/lib/src/data/book/realm/realm_book_repository.dart
@@ -0,0 +1,159 @@
+import 'package:dantex/src/data/book/book_repository.dart';
+import 'package:dantex/src/data/book/entity/book.dart';
+import 'package:dantex/src/data/book/entity/book_label.dart';
+import 'package:dantex/src/data/book/entity/book_state.dart';
+import 'package:dantex/src/data/book/realm/realm_book.dart';
+import 'package:dantex/src/data/book/search_criteria.dart';
+import 'package:realm/realm.dart';
+
+
+class RealmBookRepository implements BookRepository {
+ final Realm _realm;
+
+ RealmBookRepository(this._realm);
+
+ @override
+ Future create(Book book) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future delete(String id) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Stream getBook(String id) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Stream> getAllBooks() {
+ return Stream.value(
+ _realm
+ .all()
+ .where(_hasRealmBookRequiredData)
+ .map(
+ (rb) => Book(
+ id: rb.id.toString(),
+ title: rb.title!,
+ subTitle: rb.subTitle!,
+ author: rb.author!,
+ state: BookState.values[rb.ordinalState],
+ pageCount: rb.pageCount,
+ currentPage: rb.currentPage,
+ publishedDate: rb.publishedDate!,
+ position: rb.position,
+ isbn: rb.isbn!,
+ thumbnailAddress: rb.thumbnailAddress,
+ startDate: DateTime.fromMillisecondsSinceEpoch(rb.startDate),
+ endDate: DateTime.fromMillisecondsSinceEpoch(rb.endDate),
+ forLaterDate: DateTime.fromMillisecondsSinceEpoch(rb.wishlistDate),
+ language: rb.language!,
+ rating: rb.rating,
+ notes: rb.notes,
+ summary: rb.summary,
+ labels: rb.labels
+ .where(_hasRealmBookLabelRequiredData)
+ .map(
+ (rbl) => BookLabel(
+ id: rbl.bookId.toString(),
+ title: rbl.title!,
+ hexColor: rbl.hexColor!,
+ ),
+ )
+ .toList(),
+ ),
+ )
+ .toList(),
+ );
+ }
+
+ bool _hasRealmBookRequiredData(RealmBook book) {
+ return book.id > -1 &&
+ book.title != null &&
+ book.subTitle != null &&
+ book.author != null &&
+ book.publishedDate != null &&
+ book.language != null;
+ }
+
+ bool _hasRealmBookLabelRequiredData(RealmBookLabel bookLabel) {
+ return bookLabel.bookId > -1 &&
+ bookLabel.title?.isNotEmpty == true &&
+ bookLabel.hexColor?.isNotEmpty == true;
+ }
+
+ @override
+ Stream> getBooksForState(BookState state) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Stream> search(SearchCriteria criteria) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future update(Book book) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future updateCurrentPage(String bookId, int currentPage) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future addLabelToBook(String bookId, BookLabel label) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future addToForLater(Book book) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future addToRead(Book book) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future addToReading(Book book) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future addToWishlist(Book book) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future removeLabelFromBook(String bookId, String labelId) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future mergeBooks(List books) {
+ throw UnimplementedError();
+ }
+
+ @override
+ Future overwriteBooks(List books) {
+ throw UnimplementedError();
+ }
+}
diff --git a/lib/src/data/book/realm/realm_page_record_repository.dart b/lib/src/data/book/realm/realm_page_record_repository.dart
new file mode 100644
index 0000000..4e39e37
--- /dev/null
+++ b/lib/src/data/book/realm/realm_page_record_repository.dart
@@ -0,0 +1,70 @@
+import 'package:dantex/src/data/book/entity/page_record.dart';
+import 'package:dantex/src/data/book/page_record_repository.dart';
+import 'package:dantex/src/data/book/realm/realm_book.dart';
+import 'package:realm/realm.dart';
+
+class RealmPageRecordRepository implements PageRecordRepository {
+ final Realm _realm;
+
+ RealmPageRecordRepository(this._realm);
+
+ @override
+ Future> allPageRecords() async {
+ return _realm
+ .all()
+ .where(_hasPageRecordRequiredData)
+ .map(
+ (rpg) => PageRecord(
+ id: rpg.recordId ?? 'not-available',
+ bookId: rpg.bookId.toString(),
+ fromPage: rpg.fromPage,
+ toPage: rpg.toPage,
+ dateTime: DateTime.fromMillisecondsSinceEpoch(rpg.timestamp),
+ ),
+ )
+ .toList();
+ }
+
+ bool _hasPageRecordRequiredData(RealmPageRecord pageRecord) {
+ return pageRecord.bookId != -1 && pageRecord.timestamp != 0;
+ }
+
+ @override
+ Future deleteAllPageRecordsForBookId(String bookId) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future deletePageRecord(PageRecord pageRecord) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future insertPageRecordForBookId(
+ String bookId,
+ int fromPage,
+ int toPage,
+ DateTime now,
+ ) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future> pageRecordsForBook(String bookId) {
+ // Not required.
+ throw UnimplementedError();
+ }
+
+ @override
+ Future updatePageRecord(
+ PageRecord pageRecord,
+ int? fromPage,
+ int? toPage,
+ ) {
+ // Not required.
+ throw UnimplementedError();
+ }
+}
diff --git a/lib/src/data/settings/settings_repository.dart b/lib/src/data/settings/settings_repository.dart
index b289312..e09b1a5 100644
--- a/lib/src/data/settings/settings_repository.dart
+++ b/lib/src/data/settings/settings_repository.dart
@@ -1,21 +1,25 @@
import 'package:dantex/src/data/book/book_sort_strategy.dart';
import 'package:dantex/src/ui/timeline/timeline_sort.dart';
+import 'package:dantex/src/data/book/migration/migration_result.dart';
import 'package:flutter/material.dart';
abstract class SettingsRepository {
- void setThemeMode(ThemeMode mode);
+ Future setThemeMode(ThemeMode mode);
ThemeMode getThemeMode();
Stream observeThemeMode();
- void setSortingStrategy(BookSortStrategy strategy);
+ Future setSortingStrategy(BookSortStrategy strategy);
BookSortStrategy getSortingStrategy();
- void setIsTrackingEnabled({required bool isTrackingEnabled});
+ Future setIsTrackingEnabled({required bool isTrackingEnabled});
bool isTrackingEnabled();
- void setIsRandomBooksEnabled({required bool isRandomBooksEnabled});
+ Future setIsRandomBooksEnabled({required bool isRandomBooksEnabled});
bool isRandomBooksEnabled();
void setTimelineSortStrategy(TimelineSortStrategy sort);
TimelineSortStrategy getTimelineSortStrategy();
+
+ Future setRealmMigrationStatus(MigrationStatus newStatus);
+ MigrationStatus? getRealmMigrationStatus();
}
diff --git a/lib/src/data/settings/shared_preferences_settings_repository.dart b/lib/src/data/settings/shared_preferences_settings_repository.dart
index f88e411..a5c72cd 100644
--- a/lib/src/data/settings/shared_preferences_settings_repository.dart
+++ b/lib/src/data/settings/shared_preferences_settings_repository.dart
@@ -1,4 +1,5 @@
import 'package:dantex/src/data/book/book_sort_strategy.dart';
+import 'package:dantex/src/data/book/migration/migration_result.dart';
import 'package:dantex/src/data/settings/settings_repository.dart';
import 'package:dantex/src/ui/timeline/timeline_sort.dart';
import 'package:flutter/material.dart';
@@ -13,6 +14,7 @@ class SharedPreferencesSettingsRepository implements SettingsRepository {
static const _keyThemeMode = 'key_theme_mode';
static const _keySortStrategy = 'key_sort_strategy';
static const _keyTimelineSortStrategy = 'key_timeline_sort_strategy';
+ static const _keyRealmMigrationStatus = 'key_realm_migration';
final BehaviorSubject _themeModeSubject = BehaviorSubject();
@@ -89,4 +91,23 @@ class SharedPreferencesSettingsRepository implements SettingsRepository {
) async {
await _sp.setInt(_keyTimelineSortStrategy, sortStrategy.index);
}
+
+ @override
+ MigrationStatus? getRealmMigrationStatus() {
+ final String? rawRealmMigrationStatus = _sp.getString(
+ _keyRealmMigrationStatus,
+ );
+ if (rawRealmMigrationStatus == null) {
+ return null;
+ }
+
+ return MigrationStatus.values.firstWhere(
+ (element) => element.name == rawRealmMigrationStatus,
+ );
+ }
+
+ @override
+ Future setRealmMigrationStatus(MigrationStatus newStatus) async {
+ await _sp.setString(_keyRealmMigrationStatus, newStatus.name);
+ }
}
diff --git a/lib/src/providers/authentication.dart b/lib/src/providers/authentication.dart
index 5d63fa7..204ae0d 100644
--- a/lib/src/providers/authentication.dart
+++ b/lib/src/providers/authentication.dart
@@ -1,6 +1,9 @@
import 'package:dantex/src/data/authentication/authentication_repository.dart';
import 'package:dantex/src/data/authentication/entity/dante_user.dart';
import 'package:dantex/src/data/authentication/firebase_authentication_repository.dart';
+import 'package:dantex/src/data/authentication/on_user_authenticated_plugin.dart';
+import 'package:dantex/src/data/authentication/plugin/realm_migration_on_user_authenticated_plugin.dart';
+import 'package:dantex/src/providers/migration.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_database/firebase_database.dart';
@@ -33,8 +36,18 @@ AuthenticationRepository authenticationRepository(
) =>
FirebaseAuthenticationRepository(
ref.watch(firebaseAuthProvider),
+ _provideOnUserAuthenticatedPlugins(ref),
);
+List _provideOnUserAuthenticatedPlugins(
+ AuthenticationRepositoryRef ref,
+) =>
+ [
+ RealmMigrationOnUserAuthenticatedPlugin(
+ ref.read(migrationRunnerProvider),
+ ),
+ ];
+
@riverpod
Future user(UserRef ref) {
// Rebuild this provider when there is an auth state change.
diff --git a/lib/src/providers/migration.dart b/lib/src/providers/migration.dart
new file mode 100644
index 0000000..b116606
--- /dev/null
+++ b/lib/src/providers/migration.dart
@@ -0,0 +1,49 @@
+import 'package:dantex/src/data/book/book_repository.dart';
+import 'package:dantex/src/data/book/migration/migration_runner.dart';
+import 'package:dantex/src/data/book/page_record_repository.dart';
+import 'package:dantex/src/data/book/realm/realm_book.dart';
+import 'package:dantex/src/data/book/realm/realm_book_repository.dart';
+import 'package:dantex/src/data/book/realm/realm_page_record_repository.dart';
+import 'package:dantex/src/providers/repository.dart';
+import 'package:dantex/src/providers/service.dart';
+import 'package:realm/realm.dart';
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+
+part 'migration.g.dart';
+
+@riverpod
+MigrationRunner migrationRunner(MigrationRunnerRef ref) => MigrationRunner(
+ ref.watch(loggerProvider),
+ ref.watch(settingsRepositoryProvider),
+ ref.watch(bookRepositoryProvider),
+ ref.watch(_legacyBookRepositoryProvider),
+ ref.watch(pageRecordRepositoryProvider),
+ ref.watch(_legacyPageRecordRepositoryProvider),
+ );
+
+@riverpod
+BookRepository _legacyBookRepository(_LegacyBookRepositoryRef ref) =>
+ RealmBookRepository(
+ ref.watch(_realmProvider),
+ );
+
+@riverpod
+PageRecordRepository _legacyPageRecordRepository(
+ _LegacyPageRecordRepositoryRef ref,
+) =>
+ RealmPageRecordRepository(
+ ref.watch(_realmProvider),
+ );
+
+@riverpod
+Realm _realm(_RealmRef ref) => Realm(
+ Configuration.local(
+ [
+ RealmBook.schema,
+ RealmBookLabel.schema,
+ RealmPageRecord.schema,
+ ],
+ // 9 is the current schema version of the old app.
+ schemaVersion: 9,
+ ),
+ );
diff --git a/lib/src/providers/repository.dart b/lib/src/providers/repository.dart
index 698feb4..af5ed0d 100644
--- a/lib/src/providers/repository.dart
+++ b/lib/src/providers/repository.dart
@@ -4,6 +4,8 @@ import 'package:dantex/src/data/book/firebase_book_label_repository.dart';
import 'package:dantex/src/data/book/firebase_book_repository.dart';
import 'package:dantex/src/data/recommendations/default_recommendations_repository.dart';
import 'package:dantex/src/data/recommendations/recommendations_repository.dart';
+import 'package:dantex/src/data/book/firebase_page_record_repository.dart';
+import 'package:dantex/src/data/book/page_record_repository.dart';
import 'package:dantex/src/data/settings/settings_repository.dart';
import 'package:dantex/src/data/settings/shared_preferences_settings_repository.dart';
import 'package:dantex/src/providers/api.dart';
@@ -34,6 +36,15 @@ BookLabelRepository bookLabelRepository(BookLabelRepositoryRef ref) =>
ref.watch(firebaseDatabaseProvider),
);
+@riverpod
+PageRecordRepository pageRecordRepository(
+ PageRecordRepositoryRef ref,
+) =>
+ FirebasePageRecordRepository(
+ ref.watch(firebaseAuthProvider),
+ ref.watch(firebaseDatabaseProvider),
+ );
+
@riverpod
SettingsRepository settingsRepository(SettingsRepositoryRef ref) =>
SharedPreferencesSettingsRepository(
diff --git a/pubspec.lock b/pubspec.lock
index 7878921..b653531 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: _flutterfire_internals
- sha256: eb0ac20f704799b986049fbb3c1c16421eca319a1b872378d669513e12452ba5
+ sha256: f5628cd9c92ed11083f425fd1f8f1bc60ecdda458c81d73b143aeda036c35fe7
url: "https://pub.dev"
source: hosted
- version: "1.3.14"
+ version: "1.3.16"
analyzer:
dependency: transitive
description:
@@ -45,10 +45,10 @@ packages:
dependency: transitive
description:
name: archive
- sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
+ sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
url: "https://pub.dev"
source: hosted
- version: "3.4.9"
+ version: "3.4.10"
args:
dependency: transitive
description:
@@ -81,6 +81,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.1"
+ build_cli_annotations:
+ dependency: transitive
+ description:
+ name: build_cli_annotations
+ sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
build_config:
dependency: transitive
description:
@@ -101,18 +109,18 @@ packages:
dependency: transitive
description:
name: build_resolvers
- sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8"
+ sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
url: "https://pub.dev"
source: hosted
- version: "2.4.1"
+ version: "2.4.2"
build_runner:
dependency: "direct dev"
description:
name: build_runner
- sha256: "67d591d602906ef9201caf93452495ad1812bea2074f04e25dbd7c133785821b"
+ sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21"
url: "https://pub.dev"
source: hosted
- version: "2.4.7"
+ version: "2.4.8"
build_runner_core:
dependency: transitive
description:
@@ -133,34 +141,42 @@ packages:
dependency: transitive
description:
name: built_value
- sha256: "69acb7007eb2a31dc901512bfe0f7b767168be34cb734835d54c070bfa74c1b2"
+ sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309
url: "https://pub.dev"
source: hosted
- version: "8.8.0"
+ version: "8.8.1"
cached_network_image:
dependency: "direct main"
description:
name: cached_network_image
- sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f
+ sha256: "28ea9690a8207179c319965c13cd8df184d5ee721ae2ce60f398ced1219cea1f"
url: "https://pub.dev"
source: hosted
- version: "3.3.0"
+ version: "3.3.1"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
- sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613"
+ sha256: "9e90e78ae72caa874a323d78fa6301b3fb8fa7ea76a8f96dc5b5bf79f283bf2f"
url: "https://pub.dev"
source: hosted
- version: "3.0.0"
+ version: "4.0.0"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
- sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257"
+ sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316"
url: "https://pub.dev"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
+ cancellation_token:
+ dependency: transitive
+ description:
+ name: cancellation_token
+ sha256: ad95acf9d4b2f3563e25dc937f63587e46a70ce534e910b65d10e115490f1027
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.1"
carousel_slider:
dependency: "direct main"
description:
@@ -197,10 +213,10 @@ packages:
dependency: transitive
description:
name: cli_util
- sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
+ sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
url: "https://pub.dev"
source: hosted
- version: "0.4.0"
+ version: "0.4.1"
clock:
dependency: transitive
description:
@@ -213,10 +229,10 @@ packages:
dependency: transitive
description:
name: code_builder
- sha256: b2151ce26a06171005b379ecff6e08d34c470180ffe16b8e14b6d52be292b55f
+ sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
url: "https://pub.dev"
source: hosted
- version: "4.8.0"
+ version: "4.10.0"
collection:
dependency: "direct main"
description:
@@ -253,26 +269,26 @@ packages:
dependency: "direct dev"
description:
name: custom_lint
- sha256: "198ec6b8e084d22f508a76556c9afcfb71706ad3f42b083fe0ee923351a96d90"
+ sha256: dfb893ff17c83cf08676c6b64df11d3e53d80590978d7c1fb242afff3ba6dedb
url: "https://pub.dev"
source: hosted
- version: "0.5.7"
+ version: "0.5.8"
custom_lint_builder:
dependency: transitive
description:
name: custom_lint_builder
- sha256: dfcfa987d2bd9d0ba751ef4bdef0f6c1aa0062f2a67fe716fd5f3f8b709d6418
+ sha256: "8df6634b38a36a6c6cb74a9c0eb02e9ba0b0ab89b29e38e6daa86e8ed2c6288d"
url: "https://pub.dev"
source: hosted
- version: "0.5.7"
+ version: "0.5.8"
custom_lint_core:
dependency: transitive
description:
name: custom_lint_core
- sha256: f84c3fe2f27ef3b8831953e477e59d4a29c2952623f9eac450d7b40d9cdd94cc
+ sha256: "2b235be098d157e244f18ea905a15a18c16a205e30553888fac6544bbf52f03f"
url: "https://pub.dev"
source: hosted
- version: "0.5.7"
+ version: "0.5.8"
dart_style:
dependency: transitive
description:
@@ -333,10 +349,10 @@ packages:
dependency: "direct main"
description:
name: extension_google_sign_in_as_googleapis_auth
- sha256: c56c934a50670358721e50852b223fca9bd54eb03004e5af160431d79acbba3f
+ sha256: bcf4f8dedcc1e66ce5fe98fbd98cc86ed25ad7fce0511e8d6cdc46ccbf421e8e
url: "https://pub.dev"
source: hosted
- version: "2.0.11"
+ version: "2.0.12"
fake_async:
dependency: transitive
description:
@@ -365,58 +381,58 @@ packages:
dependency: "direct main"
description:
name: firebase_analytics
- sha256: "6325991042226a515406b4fc9204d3102e54a514b72fffb945b625d9f69c5196"
+ sha256: "0240076090d77045d757aecb090616066d23b343840d4c21074094d6fe40a184"
url: "https://pub.dev"
source: hosted
- version: "10.7.2"
+ version: "10.8.0"
firebase_analytics_platform_interface:
dependency: transitive
description:
name: firebase_analytics_platform_interface
- sha256: "38ad4bec1fa0fe16577e6f178e4c4280f029181b18e16bf68782c527c7d82bfe"
+ sha256: "6d9baa077d16b47ef5f19d982c4fc475597991aa53b0c601216faa3e1cdab45f"
url: "https://pub.dev"
source: hosted
- version: "3.8.2"
+ version: "3.9.0"
firebase_analytics_web:
dependency: transitive
description:
name: firebase_analytics_web
- sha256: "6c0deb691a26db2006ded65fd8999a204dcfe8ef67d7d75b7f55ebc08e1d89a4"
+ sha256: "89a740249bce9d52a99db4e501be6087ca6749c73c47cff2b174802be10abd81"
url: "https://pub.dev"
source: hosted
- version: "0.5.5+9"
+ version: "0.5.5+12"
firebase_auth:
dependency: "direct main"
description:
name: firebase_auth
- sha256: "869ff488c7b467e273d7be223f52d3d026576b6e1da92dcd136ff627ae0a8c67"
+ sha256: "279b2773ff61afd9763202cb5582e2b995ee57419d826b9af6517302a59b672f"
url: "https://pub.dev"
source: hosted
- version: "4.15.0"
+ version: "4.16.0"
firebase_auth_platform_interface:
dependency: transitive
description:
name: firebase_auth_platform_interface
- sha256: ecf9f78ae1a7a1297de01ec975e9e2cfe5b543589b27cc5969849d9a8dc46999
+ sha256: "3c9cfaccb7549492edf5b0c67c6dd1c6727c7830891aa6727f2fb225f0226626"
url: "https://pub.dev"
source: hosted
- version: "7.0.6"
+ version: "7.0.9"
firebase_auth_web:
dependency: transitive
description:
name: firebase_auth_web
- sha256: "96f89e2340cdf373109cb29afec401c170aa2d98fb0833687793c8017e36f435"
+ sha256: c7b1379ccef7abf4b6816eede67a868c44142198e42350f51c01d8fc03f95a7d
url: "https://pub.dev"
source: hosted
- version: "5.8.9"
+ version: "5.8.13"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
- sha256: d301561d614487688d797717bef013a264c517d1d09e4c5c1325c3a64c835efb
+ sha256: "96607c0e829a581c2a483c658f04e8b159964c3bae2730f73297070bc85d40bb"
url: "https://pub.dev"
source: hosted
- version: "2.24.0"
+ version: "2.24.2"
firebase_core_platform_interface:
dependency: transitive
description:
@@ -429,74 +445,74 @@ packages:
dependency: transitive
description:
name: firebase_core_web
- sha256: "10159d9ee42c79f4548971d92f3f0fcd5791f6738cda3583a4e3b2c8b244c018"
+ sha256: d585bdf3c656c3f7821ba1bd44da5f13365d22fcecaf5eb75c4295246aaa83c0
url: "https://pub.dev"
source: hosted
- version: "2.9.0"
+ version: "2.10.0"
firebase_crashlytics:
dependency: "direct main"
description:
name: firebase_crashlytics
- sha256: "60ef0016c0c2a7d16bf02468e3b27cd0ad4606f6d35535998dde3150cc0bc771"
+ sha256: "5125b7f3fcef2bfdd7e071afe7edcefd9597968003e44e073456c773d91694ee"
url: "https://pub.dev"
source: hosted
- version: "3.4.6"
+ version: "3.4.9"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
- sha256: d185100facc6f7c43c5718103111488d008c52df8c19cbc5e5f9d2115d734909
+ sha256: "359197344def001589c84f8d1d57c05f6e2e773f559205610ce58c25e2045a57"
url: "https://pub.dev"
source: hosted
- version: "3.6.14"
+ version: "3.6.16"
firebase_database:
dependency: "direct main"
description:
name: firebase_database
- sha256: "373b54cc0a890f4f1547380d31232a718aa5e4ded1a8819e6c4709d7df8286e6"
+ sha256: "8568ad41f9312ab1f162f70c1e3e7cb7420b8bc8d07e4d543e575bb0cb41f8a5"
url: "https://pub.dev"
source: hosted
- version: "10.3.6"
+ version: "10.4.0"
firebase_database_platform_interface:
dependency: transitive
description:
name: firebase_database_platform_interface
- sha256: "2e3edb4552848585aa0031c0d493699305b40da756ebe507686ca6bbe96369eb"
+ sha256: "4366ade2390f8799a317bb13af29c2a1fdfc84f4d04372094756b86a6cbfd305"
url: "https://pub.dev"
source: hosted
- version: "0.2.5+14"
+ version: "0.2.5+16"
firebase_database_web:
dependency: transitive
description:
name: firebase_database_web
- sha256: "55ec085db984291668c232d8760b82c86c33f5e4a459721a2df0438c2ece5859"
+ sha256: "4920a83b917493b37fd408cbb01c289ef8a422d9ed48982f908a9850290262f9"
url: "https://pub.dev"
source: hosted
- version: "0.2.3+14"
+ version: "0.2.3+16"
firebase_storage:
dependency: "direct main"
description:
name: firebase_storage
- sha256: ef1974043d48b0aa081ad055944ec74cad3a665545849cc6232f8ac1691fd901
+ sha256: "75e6cb6bed65138b5bbd86bfd7cf9bc9a175fb0c31aacc400e9203df117ffbe6"
url: "https://pub.dev"
source: hosted
- version: "11.5.3"
+ version: "11.6.0"
firebase_storage_platform_interface:
dependency: transitive
description:
name: firebase_storage_platform_interface
- sha256: "7b5aa0bf53de4a983aa3df57ab2bc0509d75fe2d269a0029a814aa84484798d5"
+ sha256: "545a3a8edf337850403bb0fa03c8074a53deb87c0107d19755c77a82ce07919e"
url: "https://pub.dev"
source: hosted
- version: "5.1.1"
+ version: "5.1.3"
firebase_storage_web:
dependency: transitive
description:
name: firebase_storage_web
- sha256: bc5ede7fd6dfe7e23821cce007cd551cf77f47f44f8c3ea4f270dea0372051dc
+ sha256: ee6870ff79aa304b8996ba18a4aefe1e8b3fc31fd385eab6574180267aa8d393
url: "https://pub.dev"
source: hosted
- version: "3.6.15"
+ version: "3.6.17"
fixnum:
dependency: transitive
description:
@@ -625,10 +641,10 @@ packages:
dependency: "direct dev"
description:
name: freezed
- sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a"
+ sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba"
url: "https://pub.dev"
source: hosted
- version: "2.4.5"
+ version: "2.4.6"
freezed_annotation:
dependency: "direct main"
description:
@@ -657,10 +673,10 @@ packages:
dependency: "direct main"
description:
name: go_router
- sha256: c247a4f76071c3b97bb5ae8912968870d5565644801c5e09f3bc961b4d874895
+ sha256: c5fa45fa502ee880839e3b2152d987c44abae26d064a2376d4aad434cf0f7b15
url: "https://pub.dev"
source: hosted
- version: "12.1.1"
+ version: "12.1.3"
google_fonts:
dependency: "direct main"
description:
@@ -673,50 +689,50 @@ packages:
dependency: transitive
description:
name: google_identity_services_web
- sha256: "000b7a31e1fa17ee04b6c0553a2b2ea18f9f9352e4dcc0c9fcc785cf10f2484e"
+ sha256: "0c56c2c5d60d6dfaf9725f5ad4699f04749fb196ee5a70487a46ef184837ccf6"
url: "https://pub.dev"
source: hosted
- version: "0.2.2"
+ version: "0.3.0+2"
google_sign_in:
dependency: "direct main"
description:
name: google_sign_in
- sha256: "8f8b94880f2753ccb796744259da529674e49b9af2e372abf6978c590c0ebfef"
+ sha256: "0b8787cb9c1a68ad398e8010e8c8766bfa33556d2ab97c439fb4137756d7308f"
url: "https://pub.dev"
source: hosted
- version: "6.1.6"
+ version: "6.2.1"
google_sign_in_android:
dependency: transitive
description:
name: google_sign_in_android
- sha256: "6031f59074a337fdd81be821aba84cee3a41338c6e958499a5cd34d3e1db80ef"
+ sha256: bfd42c81c30c6faba16e0f62968d5505a87504aaa672b3155ee931461abb0a49
url: "https://pub.dev"
source: hosted
- version: "6.1.20"
+ version: "6.1.21"
google_sign_in_ios:
dependency: transitive
description:
name: google_sign_in_ios
- sha256: "8edfde9698b5951f3d02632eceb39cc283865c3cff0b03216bf951089f10345b"
+ sha256: f3336d9e44d4d28063ac90271f6db5caf99f0480cb07281330e7a432edb95226
url: "https://pub.dev"
source: hosted
- version: "5.6.3"
+ version: "5.7.3"
google_sign_in_platform_interface:
dependency: transitive
description:
name: google_sign_in_platform_interface
- sha256: "35ceee5f0eadc1c07b0b4af7553246e315c901facbb7d3dadf734ba2693ceec4"
+ sha256: "1f6e5787d7a120cc0359ddf315c92309069171306242e181c09472d1b00a2971"
url: "https://pub.dev"
source: hosted
- version: "2.4.2"
+ version: "2.4.5"
google_sign_in_web:
dependency: transitive
description:
name: google_sign_in_web
- sha256: "794f5494a945d6dd2654c52f979594ecd2558e5c82ce8272295ba371c93015e6"
+ sha256: a278ea2d01013faf341cbb093da880d0f2a552bbd1cb6ee90b5bebac9ba69d77
url: "https://pub.dev"
source: hosted
- version: "0.12.2+1"
+ version: "0.12.3+2"
googleapis:
dependency: "direct main"
description:
@@ -777,10 +793,10 @@ packages:
dependency: transitive
description:
name: image
- sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
+ sha256: "004a2e90ce080f8627b5a04aecb4cdfac87d2c3f3b520aa291260be5a32c033d"
url: "https://pub.dev"
source: hosted
- version: "4.1.3"
+ version: "4.1.4"
intl:
dependency: "direct main"
description:
@@ -889,10 +905,18 @@ packages:
dependency: "direct dev"
description:
name: mockito
- sha256: "4b693867cee1853c9d1d7ecc1871f27f39b2ef2c13c0d8d8507dfe5bebd8aaf1"
+ sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.4.4"
+ objectid:
+ dependency: transitive
+ description:
+ name: objectid
+ sha256: fd4a0b9fe07df25c446948b786e7ab2f363b2f461afa78632cab179d7613b9b3
url: "https://pub.dev"
source: hosted
- version: "5.4.3"
+ version: "3.0.0"
octo_image:
dependency: transitive
description:
@@ -929,26 +953,26 @@ packages:
dependency: transitive
description:
name: path_provider
- sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+ sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.1.2"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
- sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+ sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
url: "https://pub.dev"
source: hosted
- version: "2.2.1"
+ version: "2.2.2"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
- sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+ sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
url: "https://pub.dev"
source: hosted
- version: "2.3.1"
+ version: "2.3.2"
path_provider_linux:
dependency: transitive
description:
@@ -961,10 +985,10 @@ packages:
dependency: transitive
description:
name: path_provider_platform_interface
- sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
+ sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
@@ -993,18 +1017,18 @@ packages:
dependency: transitive
description:
name: platform
- sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
+ sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
url: "https://pub.dev"
source: hosted
- version: "3.1.3"
+ version: "3.1.4"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
- sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
+ sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
- version: "2.1.7"
+ version: "2.1.8"
pointycastle:
dependency: transitive
description:
@@ -1045,14 +1069,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.3"
- quiver:
+ realm:
+ dependency: "direct main"
+ description:
+ name: realm
+ sha256: "9381e73a045487876b39e291f7c96ac2c553fe1cbeb7ca1c1c960fd93353b6b6"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.6.1"
+ realm_common:
dependency: transitive
description:
- name: quiver
- sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
+ name: realm_common
+ sha256: c1ca3cf5cf1d143684c313b7faa82699442e41d943bf9818a04b72987fd365d3
url: "https://pub.dev"
source: hosted
- version: "3.2.1"
+ version: "1.6.1"
+ realm_generator:
+ dependency: transitive
+ description:
+ name: realm_generator
+ sha256: c0886b4abb269f5241da289f7a74441f5d93113532270b986d6c3bc4b4f5958f
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.6.1"
riverpod:
dependency: transitive
description:
@@ -1101,6 +1141,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.27.7"
+ sane_uuid:
+ dependency: transitive
+ description:
+ name: sane_uuid
+ sha256: "5e83f796a7d19d38d3ba3a940642998fdd8c4a4049be135ed25404e37f76a18c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.0-alpha.5"
settings_ui:
dependency: "direct main"
description:
@@ -1129,10 +1177,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_foundation
- sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
+ sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
url: "https://pub.dev"
source: hosted
- version: "2.3.4"
+ version: "2.3.5"
shared_preferences_linux:
dependency: transitive
description:
@@ -1145,10 +1193,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_platform_interface
- sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
+ sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
url: "https://pub.dev"
source: hosted
- version: "2.3.1"
+ version: "2.3.2"
shared_preferences_web:
dependency: transitive
description:
@@ -1190,10 +1238,10 @@ packages:
dependency: transitive
description:
name: source_gen
- sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16
+ sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
url: "https://pub.dev"
source: hosted
- version: "1.4.0"
+ version: "1.5.0"
source_helper:
dependency: transitive
description:
@@ -1278,10 +1326,18 @@ packages:
dependency: transitive
description:
name: synchronized
- sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
+ sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
url: "https://pub.dev"
source: hosted
- version: "3.1.0"
+ version: "3.1.0+1"
+ tar:
+ dependency: transitive
+ description:
+ name: tar
+ sha256: "1680219f82dfa81c8d0e76e849b7b34ea969c721f55a8ebd294a9a95e740dd42"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.3"
term_glyph:
dependency: transitive
description:
@@ -1326,34 +1382,34 @@ packages:
dependency: "direct main"
description:
name: url_launcher
- sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba
+ sha256: d25bb0ca00432a5e1ee40e69c36c85863addf7cc45e433769d61bed3fe81fd96
url: "https://pub.dev"
source: hosted
- version: "6.2.1"
+ version: "6.2.3"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
- sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
+ sha256: "507dc655b1d9cb5ebc756032eb785f114e415f91557b73bf60b7e201dfedeb2f"
url: "https://pub.dev"
source: hosted
- version: "6.2.0"
+ version: "6.2.2"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
- sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
+ sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
url: "https://pub.dev"
source: hosted
- version: "6.2.1"
+ version: "6.2.4"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
- sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd"
+ sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811
url: "https://pub.dev"
source: hosted
- version: "3.1.0"
+ version: "3.1.1"
url_launcher_macos:
dependency: transitive
description:
@@ -1366,58 +1422,58 @@ packages:
dependency: transitive
description:
name: url_launcher_platform_interface
- sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
+ sha256: a932c3a8082e118f80a475ce692fde89dc20fddb24c57360b96bc56f7035de1f
url: "https://pub.dev"
source: hosted
- version: "2.2.0"
+ version: "2.3.1"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
- sha256: "138bd45b3a456dcfafc46d1a146787424f8d2edfbf2809c9324361e58f851cf7"
+ sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
url: "https://pub.dev"
source: hosted
- version: "2.2.1"
+ version: "2.2.3"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
- sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc"
+ sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7
url: "https://pub.dev"
source: hosted
- version: "3.1.0"
+ version: "3.1.1"
uuid:
dependency: "direct main"
description:
name: uuid
- sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921
+ sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8
url: "https://pub.dev"
source: hosted
- version: "4.2.1"
+ version: "4.3.3"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
- sha256: "0f0c746dd2d6254a0057218ff980fc7f5670fd0fcf5e4db38a490d31eed4ad43"
+ sha256: "18f6690295af52d081f6808f2f7c69f0eed6d7e23a71539d75f4aeb8f0062172"
url: "https://pub.dev"
source: hosted
- version: "1.1.9+1"
+ version: "1.1.9+2"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
- sha256: "0edf6d630d1bfd5589114138ed8fada3234deacc37966bec033d3047c29248b7"
+ sha256: "531d20465c10dfac7f5cd90b60bbe4dd9921f1ec4ca54c83ebb176dbacb7bb2d"
url: "https://pub.dev"
source: hosted
- version: "1.1.9+1"
+ version: "1.1.9+2"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
- sha256: d24333727332d9bd20990f1483af4e09abdb9b1fc7c3db940b56ab5c42790c26
+ sha256: "03012b0a33775c5530576b70240308080e1d5050f0faf000118c20e6463bc0ad"
url: "https://pub.dev"
source: hosted
- version: "1.1.9+1"
+ version: "1.1.9+2"
vector_math:
dependency: transitive
description:
@@ -1462,18 +1518,18 @@ packages:
dependency: transitive
description:
name: win32
- sha256: b0f37db61ba2f2e9b7a78a1caece0052564d1bc70668156cf3a29d676fe4e574
+ sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
url: "https://pub.dev"
source: hosted
- version: "5.1.1"
+ version: "5.2.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
- sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
+ sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
- version: "1.0.3"
+ version: "1.0.4"
xml:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index aaa583a..55830fe 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: Dante - Book Tracker Cross Platform implementation.
publish_to: 'none'
-version: 1.0.0
+version: 5.0.0+52
environment:
sdk: '>=3.0.6 <4.0.0'
@@ -53,6 +53,7 @@ dependencies:
extension_google_sign_in_as_googleapis_auth: ^2.0.11
fl_chart: ^0.65.0
flutter_staggered_grid_view: ^0.7.0
+ realm: ^1.5.0
dev_dependencies:
flutter_test:
@@ -61,7 +62,7 @@ dev_dependencies:
flutter_lints: ^3.0.0
mockito: ^5.4.2
build_runner: ^2.4.6
- riverpod_generator: ^2.3.2
+ riverpod_generator: ^2.3.3
riverpod_lint: ^2.0.1
custom_lint: ^0.5.3
freezed: ^2.4.5
diff --git a/test/data/authentication/firebase_authentication_repository_test.dart b/test/data/authentication/firebase_authentication_repository_test.dart
index fa0b04d..d07bafc 100644
--- a/test/data/authentication/firebase_authentication_repository_test.dart
+++ b/test/data/authentication/firebase_authentication_repository_test.dart
@@ -2,6 +2,7 @@
import 'package:dantex/src/data/authentication/entity/dante_user.dart';
import 'package:dantex/src/data/authentication/firebase_authentication_repository.dart';
+import 'package:dantex/src/data/authentication/on_user_authenticated_plugin.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
@@ -18,10 +19,11 @@ import 'firebase_authentication_repository_test.mocks.dart';
void main() {
const String testEmail = 'test@mail.com';
const String testPassword = 'password';
+ const List onAuthPlugins = [];
test('Get account returns DanteUser', () async {
final fbAuth = MockFirebaseAuth();
- final fbAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final fbAuthRepo = FirebaseAuthenticationRepository(fbAuth, onAuthPlugins);
final User user = MockUser();
final UserInfo userInfo = MockUserInfo();
final DanteUser danteUser = DanteUser(
@@ -56,7 +58,10 @@ void main() {
group('Login', () {
test('Login with Google returns user credential on success', () async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final userCred = MockUserCredential();
when(fbAuth.signInWithProvider(any)).thenAnswer((_) async => userCred);
@@ -67,7 +72,10 @@ void main() {
test('Login anonymously returns User Credential on success', () async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final userCred = MockUserCredential();
when(fbAuth.signInAnonymously()).thenAnswer((_) async => userCred);
@@ -78,7 +86,10 @@ void main() {
test('Login with email returns User Credential on success', () async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final userCred = MockUserCredential();
when(
@@ -106,7 +117,10 @@ void main() {
test('logout returns void on success', () async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
when(fbAuth.signOut()).thenAnswer((_) async => Future);
@@ -118,7 +132,10 @@ void main() {
'fetchSignInMethodsForEmail maps sign in methods to AuthenticationSource',
() async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
when(fbAuth.fetchSignInMethodsForEmail(testEmail))
.thenAnswer((_) async => ['google.com', 'password', 'apple.com']);
@@ -137,7 +154,10 @@ void main() {
test('Create mail account returns User Credential on success', () async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final userCred = MockUserCredential();
when(
@@ -165,7 +185,10 @@ void main() {
test('Upgrade anonymous account returns User Credential on success',
() async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final user = MockUser();
final userCred = MockUserCredential();
@@ -190,7 +213,10 @@ void main() {
'Upgrade anonymous account throws FirebaseAuthException error when user not found',
() async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
when(
fbAuth.currentUser,
@@ -207,7 +233,10 @@ void main() {
test('Update user password returns void on success', () {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final user = MockUser();
when(fbAuth.currentUser).thenReturn(user);
@@ -223,7 +252,10 @@ void main() {
'Upgrade password throws FirebaseAuthException error when user not found',
() async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
when(
fbAuth.currentUser,
@@ -239,7 +271,10 @@ void main() {
test('Send password reset request returns void on success', () {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
when(fbAuth.sendPasswordResetEmail(email: testEmail))
.thenAnswer((_) async => Future);
@@ -250,7 +285,10 @@ void main() {
test('Delete user returns void on success', () async {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final User user = MockUser();
when(fbAuth.currentUser).thenReturn(user);
@@ -263,7 +301,10 @@ void main() {
test('Auth state changes returns DanteUser', () {
final fbAuth = MockFirebaseAuth();
- final firebaseAuthRepo = FirebaseAuthenticationRepository(fbAuth);
+ final firebaseAuthRepo = FirebaseAuthenticationRepository(
+ fbAuth,
+ onAuthPlugins,
+ );
final User user = MockUser();
final UserInfo userInfo = MockUserInfo();
final DanteUser danteUser = DanteUser(
diff --git a/test/data/authentication/firebase_authentication_repository_test.mocks.dart b/test/data/authentication/firebase_authentication_repository_test.mocks.dart
index bc01842..5fa1a5d 100644
--- a/test/data/authentication/firebase_authentication_repository_test.mocks.dart
+++ b/test/data/authentication/firebase_authentication_repository_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.4.3 from annotations
+// Mocks generated by Mockito 5.4.4 from annotations
// in dantex/test/data/authentication/firebase_authentication_repository_test.dart.
// Do not manually edit this file.
@@ -162,8 +162,9 @@ class MockFirebaseAuth extends _i1.Mock implements _i4.FirebaseAuth {
@override
_i5.Future useAuthEmulator(
String? host,
- int? port,
- ) =>
+ int? port, {
+ bool? automaticHostMapping = true,
+ }) =>
(super.noSuchMethod(
Invocation.method(
#useAuthEmulator,
@@ -171,6 +172,7 @@ class MockFirebaseAuth extends _i1.Mock implements _i4.FirebaseAuth {
host,
port,
],
+ {#automaticHostMapping: automaticHostMapping},
),
returnValue: _i5.Future.value(),
returnValueForMissingStub: _i5.Future.value(),
diff --git a/test/data/book/firebase_book_repository_test.mocks.dart b/test/data/book/firebase_book_repository_test.mocks.dart
index 84623b4..69d9918 100644
--- a/test/data/book/firebase_book_repository_test.mocks.dart
+++ b/test/data/book/firebase_book_repository_test.mocks.dart
@@ -1,4 +1,4 @@
-// Mocks generated by Mockito 5.4.3 from annotations
+// Mocks generated by Mockito 5.4.4 from annotations
// in dantex/test/data/book/firebase_book_repository_test.dart.
// Do not manually edit this file.
@@ -227,8 +227,9 @@ class MockFirebaseAuth extends _i1.Mock implements _i4.FirebaseAuth {
@override
_i6.Future useAuthEmulator(
String? host,
- int? port,
- ) =>
+ int? port, {
+ bool? automaticHostMapping = true,
+ }) =>
(super.noSuchMethod(
Invocation.method(
#useAuthEmulator,
@@ -236,6 +237,7 @@ class MockFirebaseAuth extends _i1.Mock implements _i4.FirebaseAuth {
host,
port,
],
+ {#automaticHostMapping: automaticHostMapping},
),
returnValue: _i6.Future.value(),
returnValueForMissingStub: _i6.Future.value(),
@@ -761,8 +763,9 @@ class MockFirebaseDatabase extends _i1.Mock implements _i5.FirebaseDatabase {
@override
void useDatabaseEmulator(
String? host,
- int? port,
- ) =>
+ int? port, {
+ bool? automaticHostMapping = true,
+ }) =>
super.noSuchMethod(
Invocation.method(
#useDatabaseEmulator,
@@ -770,6 +773,7 @@ class MockFirebaseDatabase extends _i1.Mock implements _i5.FirebaseDatabase {
host,
port,
],
+ {#automaticHostMapping: automaticHostMapping},
),
returnValueForMissingStub: null,
);