Skip to content

Commit

Permalink
local storage: update objectbox to v4.1.0 and add sync fields to models
Browse files Browse the repository at this point in the history
Updated objectbox and objectbox_generator to version 4.1.0.
Preparing models for syncing by adding necessary fields `isDeleted`, `isSynced`, `updatedAt`, and `createdAt` fields to the `UserProfile`, `WaterPreferences`, `Medication`, and `AppUser` models for synchronization purposes.
Also updated the user local service to throw the right exception.
Also improved logging on catching an app exception.
  • Loading branch information
nuilewis committed Feb 17, 2025
1 parent abf5a5b commit 816b9eb
Show file tree
Hide file tree
Showing 14 changed files with 515 additions and 56 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ dependencies {
// e.g. check https://github.com/objectbox/objectbox-dart/releases
// Warning: when ObjectBox for Dart updates check if <version>
// needs to be updated.
debugImplementation "io.objectbox:objectbox-android-objectbrowser:4.0.3"
debugImplementation "io.objectbox:objectbox-android-objectbrowser:4.1.0"
}

// Tell Gradle to exclude the objectbox-android dependency
Expand Down
17 changes: 16 additions & 1 deletion lib/core/utils/method_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ FutureEither<T> futureHandler<T>(Future<T> Function() function) async {
stackTrace: stackTrace,
name: "Method Handler",
);

// Log this caught exception to Crashlytics
CrashlyticsService.recordError(
error: e,
stack: stackTrace,
reason: "An App exception has occurred",
information: [
"Future Handler",
e.type.name,
e.type,
e.code?? "code: unknown",
e.message,
e.stackTrace ?? "",
],
);
switch (e.type) {
case ExceptionType.api:
return Left(Failure.fromApi(e));
Expand Down Expand Up @@ -118,7 +133,7 @@ FutureEither<T> futureHandler<T>(Future<T> Function() function) async {
CrashlyticsService.recordError(
error: e,
stack: stackTrace,
reason: "An exception exception has occurred",
reason: "An exception has occurred",
information: ["Future Handler", "Generic Error", e.toString()],
);

Expand Down
27 changes: 23 additions & 4 deletions lib/features/auth/models/user/app_user.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,20 @@ class AppUser extends Equatable {
@Transient()
UserPreferences? preferences;

/// Sync Related Fields
final bool isDeleted;
final bool isSynced;
@Property(type: PropertyType.date)
final DateTime? updatedAt;
@Property(type: PropertyType.date)
final DateTime? createdAt;


/// ----- OBJECTBOX TYPE CONVERTERS ----- ///
///
/// Encodes user preferences into a JSON string for storage.
String get dbPreferences => jsonEncode(preferences?.toMap());
String? get dbPreferences =>
preferences?.toMap() != null ? jsonEncode(preferences!.toMap()) : null;

/// Decodes a JSON string into user preferences.
set dbPreferences(String? jsonString) {
Expand All @@ -72,7 +81,10 @@ class AppUser extends Equatable {
this.isPhoneVerified,
this.photoUrl,
this.preferences,
});
this.isDeleted = false,
this.isSynced = false,
this.updatedAt,
}) : createdAt = DateTime.now().toUtc();

/// Creates a copy of the current `AppUser` instance with updated values.
AppUser copyWith({
Expand All @@ -84,6 +96,9 @@ class AppUser extends Equatable {
bool? isPhoneVerified,
UserProfile? profile,
UserPreferences? preferences,
bool? isDeleted,
bool? isSynced,
DateTime? updatedAt,
}) {
AppUser user = AppUser(
id: id,
Expand All @@ -109,7 +124,8 @@ class AppUser extends Equatable {
"isEmailVerified": isEmailVerified,
"isPhoneVerified": isPhoneVerified,
"profile": profile.target?.toMap(),
"preferences": preferences?.toMap() ?? const UnitPreferences.metric().toMap(),
"preferences":
preferences?.toMap() ?? const UnitPreferences.metric().toMap(),
};
}

Expand Down Expand Up @@ -227,7 +243,6 @@ class AppUser extends Equatable {
@Transient()
bool? get stringify => true;


/// Enables stringification for easier debugging.
@override
String toString() {
Expand All @@ -250,5 +265,9 @@ class AppUser extends Equatable {
isPhoneVerified,
profile,
preferences,
isDeleted,
isSynced,
updatedAt,
createdAt,
];
}
36 changes: 28 additions & 8 deletions lib/features/auth/models/user/user_preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,42 @@ class UserPreferences extends Equatable {
/// Stores the theme mode preferred by the user (e.g., light, dark, or system default).
final ThemeMode? themeMode;

/// The last time the user preferences were updated.
final DateTime? lastUpdated;
/// Sync Related Fields
final bool isDeleted;
final bool isSynced;
final DateTime? updatedAt;
final DateTime? createdAt;

/// Creates an instance of [UserPreferences].
const UserPreferences({
required this.isFirstTime,
required this.isOnboarded,
this.lastUpdated,
this.themeMode = ThemeMode.system,
this.unitPreferences,
this.isDeleted = false,
this.isSynced = false,
this.updatedAt,
this.createdAt,
});

/// Creates a copy of [UserPreferences] with updated properties.
UserPreferences copyWith({
final bool? isFirstTime,
final bool? isOnboarded,
final ThemeMode? themeMode,
final DateTime? lastUpdated,
final UnitPreferences? unitPreferences,
final bool? isDeleted,
final bool? isSynced,
final DateTime? updatedAt,
}) {

return UserPreferences(
isFirstTime: isFirstTime ?? this.isFirstTime,
isOnboarded: isOnboarded ?? this.isOnboarded,
themeMode: themeMode ?? this.themeMode,
lastUpdated: lastUpdated ?? this.lastUpdated,
isDeleted: isDeleted ?? this.isDeleted,
isSynced: isSynced ?? this.isSynced,
updatedAt: updatedAt ?? this.updatedAt,
unitPreferences: unitPreferences ?? this.unitPreferences,
);
}
Expand All @@ -53,7 +64,10 @@ class UserPreferences extends Equatable {
"isFirstTime": isFirstTime,
"isOnboarded": isOnboarded,
"themeMode": themeMode?.name,
"lastUpdated": lastUpdated?.toIso8601String() ?? DateTime.now().toIso8601String(),
"isDeleted": isDeleted,
"isSynced": isSynced,
"updatedAt": updatedAt?.toIso8601String() ?? DateTime.now().toIso8601String(),
"createdAt": createdAt?.toIso8601String() ?? DateTime.now().toIso8601String(),
"unitPreferences": unitPreferences?.toMap() ?? const UnitPreferences.metric().toMap(),
};
}
Expand All @@ -66,7 +80,10 @@ class UserPreferences extends Equatable {
themeMode: data["themeMode"] != null
? ThemeMode.values.byName(data["themeMode"] as String)
: null,
lastUpdated: data["lastUpdated"] != null ? DateTime.parse(data["lastUpdated"]) : null,
isDeleted: data["isDeleted"] as bool,
isSynced: data["isSynced"] as bool,
updatedAt: data["updatedAt"] != null ? DateTime.parse(data["updatedAt"]) : null,
createdAt: data["createdAt"] != null ? DateTime.parse(data["createdAt"]) : null,
unitPreferences: data["unitPreferences"] != null
? UnitPreferences.fromMap(data: data["unitPreferences"])
: null,
Expand Down Expand Up @@ -101,7 +118,10 @@ class UserPreferences extends Equatable {
themeMode,
isFirstTime,
isOnboarded,
lastUpdated,
isDeleted,
isSynced,
updatedAt,
createdAt,
unitPreferences,
];
}
Expand Down
52 changes: 49 additions & 3 deletions lib/features/auth/models/user/user_profile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,16 @@ class UserProfile extends Equatable {
/// List of medical conditions the user has reported.
List<String>? medicalConditions;

// ObjectBox Type Converters
// Sync Related Fields
final bool isDeleted;
final bool isSynced;
@Property(type: PropertyType.date)
final DateTime? updatedAt;
@Property(type: PropertyType.date)
final DateTime? createdAt;

/// ----- OBJECTBOX TYPE CONVERTERS ----- ///
///
/// Converts the gender enum to a string for database persistence.
String? get dbGender => gender?.name;

Expand Down Expand Up @@ -126,6 +135,12 @@ class UserProfile extends Equatable {
this.bloodGroup,
this.allergies,
this.medicalConditions,

// Sync Related Fields
this.isDeleted = false,
this.isSynced = false,
this.updatedAt,
this.createdAt,
});

/// Creates a copy of this [UserProfile] with optional modifications.
Expand All @@ -147,6 +162,11 @@ class UserProfile extends Equatable {
String? bloodGroup,
List<String>? allergies,
List<String>? medicalConditions,

// Sync Related Fields
bool? isDeleted,
bool? isSynced,
DateTime? updatedAt,
}) {
return UserProfile(
id: id,
Expand All @@ -167,6 +187,11 @@ class UserProfile extends Equatable {
bloodGroup: bloodGroup ?? this.bloodGroup,
allergies: allergies ?? this.allergies,
medicalConditions: medicalConditions ?? this.medicalConditions,

// Sync Related Fields
isDeleted: isDeleted ?? this.isDeleted,
isSynced: isSynced ?? this.isSynced,
updatedAt: updatedAt ?? this.updatedAt,
);
}

Expand Down Expand Up @@ -194,6 +219,12 @@ class UserProfile extends Equatable {
"allergies": allergies,
"medicalConditions": medicalConditions,
},
"sync": {
"isDeleted": isDeleted,
"isSynced": isSynced,
"updatedAt": updatedAt?.toUtc().toIso8601String(),
"createdAt": createdAt?.toUtc().toIso8601String(),
},
};
}

Expand All @@ -213,7 +244,13 @@ class UserProfile extends Equatable {
bmi: data["health"]["bmi"] as double?,
bloodGroup: data["health"]["bloodGroup"] as String?,
allergies: List<String>.from(data["health"]["allergies"] as List),
medicalConditions: List<String>.from(data["health"]["medicalConditions"] as List),
medicalConditions: List<String>.from(
data["health"]["medicalConditions"] as List,
),
isDeleted: data["sync"]["isDeleted"] as bool,
isSynced: data["sync"]["isSynced"] as bool,
updatedAt: DateTime.parse(data["sync"]["updatedAt"] as String),
createdAt: DateTime.parse(data["sync"]["createdAt"] as String),
);
}

Expand All @@ -225,6 +262,10 @@ class UserProfile extends Equatable {
phone: user?.phoneNumber,
email: user?.email,
displayName: user?.displayName,
createdAt: DateTime.now(), // If I am signing in, then should I overide this??
updatedAt: DateTime.now(),
isDeleted: false,
isSynced: false,
);
}

Expand Down Expand Up @@ -277,5 +318,10 @@ class UserProfile extends Equatable {
bloodGroup,
allergies,
medicalConditions,
isDeleted,
isSynced,
updatedAt,
createdAt,

];
}
}
10 changes: 7 additions & 3 deletions lib/features/auth/services/user/local/user_local_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,28 @@ class UserLocalService {
}

/// Attempts to get a user with this uid, returns null if a user doesn't exits
/// Throws an exception if the query fails for any other reason
AppUser? getUserByUid(String uid) {
print("trying to get the firbase user of this user id from local db: $uid");
// Build the query to find the user with the specified UID
late final Query<AppUser> query;
late final Query<AppUser> query;
try {
// Find the first user matching the query
query = _userBox.query(AppUser_.uid.equals(uid)).build();
print("printing the query ${query.toString()}");
final List<AppUser> results = query.find();
print("list of returned users $results");
return results.isNotEmpty ? results.first : null;
} catch (e, stackTrace) {
// Throws app exception
log(
"Failed to get user by uid",
"An exception occurred while trying to get the user by uid",
error: e,
stackTrace: stackTrace,
name: "User Local Service",
);
throw AppException(
message: "Failed to get user by uid",
message: "An exception occurred while trying to get the user by uid",
debugMessage: e.toString(),
stackTrace: stackTrace,
type: ExceptionType.localStorage,
Expand Down
Loading

0 comments on commit 816b9eb

Please sign in to comment.