124 lines
3.5 KiB
Dart
124 lines
3.5 KiB
Dart
/// App-owned user profile synced between local Drift storage and Postgres.
|
|
class UserProfile {
|
|
const UserProfile({
|
|
required this.firebaseUid,
|
|
this.email,
|
|
this.displayName,
|
|
this.photoUrl,
|
|
this.locale = 'en',
|
|
this.timezone,
|
|
this.onboardingCompleted = false,
|
|
this.revision = 1,
|
|
required this.updatedAt,
|
|
this.lastSyncedAt,
|
|
this.dirty = false,
|
|
});
|
|
|
|
final String firebaseUid;
|
|
final String? email;
|
|
final String? displayName;
|
|
final String? photoUrl;
|
|
final String locale;
|
|
final String? timezone;
|
|
final bool onboardingCompleted;
|
|
final int revision;
|
|
final DateTime updatedAt;
|
|
final DateTime? lastSyncedAt;
|
|
final bool dirty;
|
|
|
|
UserProfile copyWith({
|
|
String? email,
|
|
String? displayName,
|
|
String? photoUrl,
|
|
String? locale,
|
|
String? timezone,
|
|
bool? onboardingCompleted,
|
|
int? revision,
|
|
DateTime? updatedAt,
|
|
DateTime? lastSyncedAt,
|
|
bool? dirty,
|
|
bool clearLastSyncedAt = false,
|
|
}) {
|
|
return UserProfile(
|
|
firebaseUid: firebaseUid,
|
|
email: email ?? this.email,
|
|
displayName: displayName ?? this.displayName,
|
|
photoUrl: photoUrl ?? this.photoUrl,
|
|
locale: locale ?? this.locale,
|
|
timezone: timezone ?? this.timezone,
|
|
onboardingCompleted: onboardingCompleted ?? this.onboardingCompleted,
|
|
revision: revision ?? this.revision,
|
|
updatedAt: updatedAt ?? this.updatedAt,
|
|
lastSyncedAt: clearLastSyncedAt
|
|
? null
|
|
: (lastSyncedAt ?? this.lastSyncedAt),
|
|
dirty: dirty ?? this.dirty,
|
|
);
|
|
}
|
|
|
|
factory UserProfile.fromAuth({
|
|
required String firebaseUid,
|
|
String? email,
|
|
String? displayName,
|
|
String? photoUrl,
|
|
}) {
|
|
return UserProfile(
|
|
firebaseUid: firebaseUid,
|
|
email: email,
|
|
displayName: displayName,
|
|
photoUrl: photoUrl,
|
|
updatedAt: DateTime.now().toUtc(),
|
|
dirty: true,
|
|
);
|
|
}
|
|
|
|
factory UserProfile.fromJson(Map<String, dynamic> json) {
|
|
return UserProfile(
|
|
firebaseUid: json['firebaseUid'] as String,
|
|
email: json['email'] as String?,
|
|
displayName: json['displayName'] as String?,
|
|
photoUrl: json['photoUrl'] as String?,
|
|
locale: json['locale'] as String? ?? 'en',
|
|
timezone: json['timezone'] as String?,
|
|
onboardingCompleted: json['onboardingCompleted'] as bool? ?? false,
|
|
revision: (json['revision'] as num?)?.toInt() ?? 1,
|
|
updatedAt: DateTime.parse(json['updatedAt'] as String).toUtc(),
|
|
lastSyncedAt: json['lastSyncedAt'] == null
|
|
? null
|
|
: DateTime.parse(json['lastSyncedAt'] as String).toUtc(),
|
|
dirty: json['dirty'] as bool? ?? false,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return <String, dynamic>{
|
|
'firebaseUid': firebaseUid,
|
|
'email': email,
|
|
'displayName': displayName,
|
|
'photoUrl': photoUrl,
|
|
'locale': locale,
|
|
'timezone': timezone,
|
|
'onboardingCompleted': onboardingCompleted,
|
|
'revision': revision,
|
|
'updatedAt': updatedAt.toUtc().toIso8601String(),
|
|
if (lastSyncedAt != null)
|
|
'lastSyncedAt': lastSyncedAt!.toUtc().toIso8601String(),
|
|
'dirty': dirty,
|
|
};
|
|
}
|
|
|
|
/// Payload sent to the API (server assigns authoritative revision on conflict).
|
|
Map<String, dynamic> toApiJson() {
|
|
return <String, dynamic>{
|
|
'email': email,
|
|
'displayName': displayName,
|
|
'photoUrl': photoUrl,
|
|
'locale': locale,
|
|
'timezone': timezone,
|
|
'onboardingCompleted': onboardingCompleted,
|
|
'revision': revision,
|
|
'updatedAt': updatedAt.toUtc().toIso8601String(),
|
|
};
|
|
}
|
|
}
|