224 lines
7.2 KiB
Dart
224 lines
7.2 KiB
Dart
/// 用户 Domain 实体
|
||
///
|
||
/// 全局共享实体,被 auth / chat / contact 等多个 Feature 共用。
|
||
/// 纯 Dart 类,零 Flutter / 零网络 / 零 DB 依赖。
|
||
///
|
||
/// ## 数据流
|
||
/// ```
|
||
/// 服务端 JSON
|
||
/// → User.fromJson() ← 直接从网络创建
|
||
/// → ★ User ★ ← 你在这里
|
||
/// → userRepo.saveUser(user) ← 可选持久化
|
||
/// → ViewModel.state
|
||
/// → View 渲染
|
||
/// ```
|
||
class User {
|
||
final int uid;
|
||
final String? uuid;
|
||
final int? lastOnline;
|
||
final String? profilePic;
|
||
final String? profilePicGaussian;
|
||
final String? nickname;
|
||
final String? depositName;
|
||
final int? hasSetDepositName;
|
||
final String? contact;
|
||
final String? countryCode;
|
||
final String? username;
|
||
final int? role;
|
||
final int? relationship;
|
||
final int? friendStatus;
|
||
final String? bio;
|
||
final String? userAlias;
|
||
final int? requestAt;
|
||
final int? deletedAt;
|
||
final String? email;
|
||
final String? recoveryEmail;
|
||
final String? remark;
|
||
final String? source;
|
||
final int? addIndex;
|
||
final int? incomingSoundId;
|
||
final int? outgoingSoundId;
|
||
final int? notificationSoundId;
|
||
final int? sendMessageSoundId;
|
||
final int? groupNotificationSoundId;
|
||
final String? groupTags;
|
||
final String? friendTags;
|
||
final String? publicKey;
|
||
final int? configBits;
|
||
final String? hint;
|
||
|
||
/// 标记此用户数据是否为部分数据,需要 upsert 而非全字段覆盖。
|
||
///
|
||
/// 由响应解析层设置,Repository 据此决定写入策略:
|
||
/// - true → [UserRepository.upsertUser],仅更新非 null 字段,保留本地已有数据
|
||
/// - false → [UserRepository.insertOrReplaceUser],全字段覆盖(默认)
|
||
///
|
||
/// 注意:此字段仅用于内存传递,不会被持久化到 DB。
|
||
final bool requireUpsert;
|
||
|
||
/// TODO(contacts): 添加 localName / localPhoneNumbers,关联本地通讯录。
|
||
/// 这两个字段是设备侧数据,不应持久化到服务端 payload。
|
||
///
|
||
/// TODO(history): status 和 created_at 仅出现在历史用户记录中(如审计日志)。
|
||
/// 建议用独立的 UserHistory 实体承载,避免污染此 Domain 模型。
|
||
///
|
||
/// TODO(online): objectMgr.onlineMgr.updateOnlineTime() 原先在 fromJson() 内
|
||
/// 作为副作用调用。不要在此处复现——副作用应在 Repository 或 UseCase 层处理。
|
||
|
||
const User({
|
||
required this.uid,
|
||
this.uuid,
|
||
this.lastOnline,
|
||
this.profilePic,
|
||
this.profilePicGaussian,
|
||
this.nickname,
|
||
this.depositName,
|
||
this.hasSetDepositName,
|
||
this.contact,
|
||
this.countryCode,
|
||
this.username,
|
||
this.role,
|
||
this.relationship,
|
||
this.friendStatus,
|
||
this.bio,
|
||
this.userAlias,
|
||
this.requestAt,
|
||
this.deletedAt,
|
||
this.email,
|
||
this.recoveryEmail,
|
||
this.remark,
|
||
this.source,
|
||
this.addIndex,
|
||
this.incomingSoundId,
|
||
this.outgoingSoundId,
|
||
this.notificationSoundId,
|
||
this.sendMessageSoundId,
|
||
this.groupNotificationSoundId,
|
||
this.groupTags,
|
||
this.friendTags,
|
||
this.publicKey,
|
||
this.configBits,
|
||
this.hint,
|
||
this.requireUpsert = false,
|
||
});
|
||
|
||
/// 直接从网络 JSON 创建 Domain 实体。
|
||
///
|
||
/// [requireUpsert] 默认 false,如响应解析层判断为部分数据,
|
||
/// 可在调用后通过 copyWith(requireUpsert: true) 标记。
|
||
factory User.fromJson(Map<String, dynamic> json) => User(
|
||
uid: json['uid'] as int,
|
||
uuid: json['uuid'],
|
||
lastOnline: json['last_online'],
|
||
profilePic: json['profile_pic'],
|
||
profilePicGaussian: json['profile_pic_gaussian'],
|
||
nickname: json['nickname'],
|
||
depositName: json['deposit_name'],
|
||
hasSetDepositName: json['has_set_deposit_name'],
|
||
contact: json['contact'],
|
||
countryCode: json['country_code'],
|
||
username: json['username'],
|
||
role: json['role'],
|
||
relationship: json['relationship'],
|
||
friendStatus: json['friend_status'],
|
||
bio: json['bio'],
|
||
userAlias: json['user_alias'],
|
||
requestAt: json['request_at'],
|
||
deletedAt: json['deleted_at'],
|
||
email: json['email'],
|
||
recoveryEmail: json['recovery_email'],
|
||
remark: json['remark'],
|
||
source: json['source'],
|
||
addIndex: json['__add_index'],
|
||
incomingSoundId: json['incoming_sound_id'],
|
||
outgoingSoundId: json['outgoing_sound_id'],
|
||
notificationSoundId: json['notification_sound_id'],
|
||
sendMessageSoundId: json['send_message_sound_id'],
|
||
groupNotificationSoundId: json['group_notification_sound_id'],
|
||
groupTags: json['group_tags'],
|
||
friendTags: json['friend_tags'],
|
||
publicKey: json['public_key'],
|
||
configBits: json['config_bits'],
|
||
hint: json['hint'],
|
||
);
|
||
|
||
/// 仅更新部分字段,其余保持不变。
|
||
///
|
||
/// 注意:[requireUpsert] 不会随其他字段自动继承,
|
||
/// 需要显式传入以避免意外的写入策略变更。
|
||
User copyWith({
|
||
int? uid,
|
||
String? uuid,
|
||
int? lastOnline,
|
||
String? profilePic,
|
||
String? profilePicGaussian,
|
||
String? nickname,
|
||
String? depositName,
|
||
int? hasSetDepositName,
|
||
String? contact,
|
||
String? countryCode,
|
||
String? username,
|
||
int? role,
|
||
int? relationship,
|
||
int? friendStatus,
|
||
String? bio,
|
||
String? userAlias,
|
||
int? requestAt,
|
||
int? deletedAt,
|
||
String? email,
|
||
String? recoveryEmail,
|
||
String? remark,
|
||
String? source,
|
||
int? addIndex,
|
||
int? incomingSoundId,
|
||
int? outgoingSoundId,
|
||
int? notificationSoundId,
|
||
int? sendMessageSoundId,
|
||
int? groupNotificationSoundId,
|
||
String? groupTags,
|
||
String? friendTags,
|
||
String? publicKey,
|
||
int? configBits,
|
||
String? hint,
|
||
bool? requireUpsert,
|
||
}) {
|
||
return User(
|
||
uid: uid ?? this.uid,
|
||
uuid: uuid ?? this.uuid,
|
||
lastOnline: lastOnline ?? this.lastOnline,
|
||
profilePic: profilePic ?? this.profilePic,
|
||
profilePicGaussian: profilePicGaussian ?? this.profilePicGaussian,
|
||
nickname: nickname ?? this.nickname,
|
||
depositName: depositName ?? this.depositName,
|
||
hasSetDepositName: hasSetDepositName ?? this.hasSetDepositName,
|
||
contact: contact ?? this.contact,
|
||
countryCode: countryCode ?? this.countryCode,
|
||
username: username ?? this.username,
|
||
role: role ?? this.role,
|
||
relationship: relationship ?? this.relationship,
|
||
friendStatus: friendStatus ?? this.friendStatus,
|
||
bio: bio ?? this.bio,
|
||
userAlias: userAlias ?? this.userAlias,
|
||
requestAt: requestAt ?? this.requestAt,
|
||
deletedAt: deletedAt ?? this.deletedAt,
|
||
email: email ?? this.email,
|
||
recoveryEmail: recoveryEmail ?? this.recoveryEmail,
|
||
remark: remark ?? this.remark,
|
||
source: source ?? this.source,
|
||
addIndex: addIndex ?? this.addIndex,
|
||
incomingSoundId: incomingSoundId ?? this.incomingSoundId,
|
||
outgoingSoundId: outgoingSoundId ?? this.outgoingSoundId,
|
||
notificationSoundId: notificationSoundId ?? this.notificationSoundId,
|
||
sendMessageSoundId: sendMessageSoundId ?? this.sendMessageSoundId,
|
||
groupNotificationSoundId:
|
||
groupNotificationSoundId ?? this.groupNotificationSoundId,
|
||
groupTags: groupTags ?? this.groupTags,
|
||
friendTags: friendTags ?? this.friendTags,
|
||
publicKey: publicKey ?? this.publicKey,
|
||
configBits: configBits ?? this.configBits,
|
||
hint: hint ?? this.hint,
|
||
requireUpsert: requireUpsert ?? this.requireUpsert,
|
||
);
|
||
}
|
||
}
|