Merge pull request 'dto/业务数据分离,替换' (#5) from happi/dev/database-update into dev

Reviewed-on: https://gitea.winwayinfo.com/CUS-IM/customer-im-client/pulls/5
This commit is contained in:
wangfeng
2026-03-08 16:30:32 +08:00
66 changed files with 4369 additions and 208 deletions
+31
View File
@@ -0,0 +1,31 @@
{
"code": 0,
"message": "OK",
"data": {
"account_id": "1713925030yFMUBu",
"profile": {
"uid": 2137067,
"uuid": "1713925030yFMUBu",
"last_online": 1772819822,
"profile_pic": "Image/7e/f5/7ef5b60dd83a34a74c164a21fbd1f098/7ef5b60dd83a34a74c164a21fbd1f098.jpg",
"profile_pic_gaussian": "",
"nickname": "Happi(哈比)",
"contact": "86552205",
"country_code": "+65",
"email": "happi@winwayinfo.com",
"recovery_email": "",
"username": "happi",
"bio": "",
"relationship": 2,
"user_alias": null,
"channel_id": 1,
"channel_group_id": 1,
"hint": "1111"
},
"nonce": "",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIxMzcwNjcsInVkaWQiOjI2NjI2MzcsInNpZCI6IjE3NzI4NjU0NDc0Z1c2VWc9PSIsImlzcyI6ImFiYy5jb20iLCJhdWQiOlsidXNlciJdLCJleHAiOjE3NzQxNjE0NDcsIm5iZiI6MTc3Mjg2NTQ0NywiaWF0IjoxNzcyODY1NDQ3fQ.gUL6hyKgyPP8Tw9y7kRSq-ndNKfV9uGFhU4YKiQzg0I",
"refresh_token": "ps0FF3XayvnJB_P8Cnfu7w-uD781b1-vfmUjbrONZxI=",
"device_id": "SP1A.210812",
"login_data": ""
}
}
@@ -29,25 +29,25 @@ class AppDatabase extends _$AppDatabase {
return {};
}
return {
Favourite: database.favourites,
Sound: database.sounds,
Tag: database.tags,
PendingFriendRequestHistory: database.pendingFriendRequestHistories,
Message: database.messages,
RecentMiniApp: database.recentMiniApps,
Retry: database.retries,
Group: database.groups,
FavoriteMiniApp: database.favoriteMiniApps,
DiscoverMiniApp: database.discoverMiniApps,
ChatCategory: database.chatCategories,
ChatBot: database.chatBots,
FavouriteDetail: database.favouriteDetails,
UserRequestHistory: database.userRequestHistories,
Workspace: database.workspaces,
User: database.users,
ExploreMiniApp: database.exploreMiniApps,
CallLog: database.callLogs,
Chat: database.chats,
DriftFavourite: database.favourites,
DriftSound: database.sounds,
DriftTag: database.tags,
DriftPendingFriendRequestHistory: database.pendingFriendRequestHistories,
DriftMessage: database.messages,
DriftRecentMiniApp: database.recentMiniApps,
DriftRetry: database.retries,
DriftGroup: database.groups,
DriftFavoriteMiniApp: database.favoriteMiniApps,
DriftDiscoverMiniApp: database.discoverMiniApps,
DriftChatCategory: database.chatCategories,
DriftChatBot: database.chatBots,
DriftFavouriteDetail: database.favouriteDetails,
DriftUserRequestHistory: database.userRequestHistories,
DriftWorkspace: database.workspaces,
DriftUser: database.users,
DriftExploreMiniApp: database.exploreMiniApps,
DriftCallLog: database.callLogs,
DriftChat: database.chats,
};
}
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('CallLog')
@DataClassName('DriftCallLog')
class CallLogs extends Table {
TextColumn get id => text()();
IntColumn get callerId => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('ChatBot')
@DataClassName('DriftChatBot')
class ChatBots extends Table {
IntColumn get id => integer()();
TextColumn get name => text().nullable()();
@@ -1,9 +1,9 @@
import 'package:drift/drift.dart';
@DataClassName('ChatCategory')
@DataClassName('DriftChatCategory')
class ChatCategories extends Table {
IntColumn get id => integer()();
TextColumn get name => text().nullable().unique()();
TextColumn get name => text().nullable()();
TextColumn get includedChatIds => text().nullable()();
TextColumn get excludedChatIds => text().nullable()();
IntColumn get seq => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Chat')
@DataClassName('DriftChat')
class Chats extends Table {
IntColumn get id => integer()();
IntColumn get typ => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('DiscoverMiniApp')
@DataClassName('DriftDiscoverMiniApp')
class DiscoverMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('ExploreMiniApp')
@DataClassName('DriftExploreMiniApp')
class ExploreMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('FavoriteMiniApp')
@DataClassName('DriftFavoriteMiniApp')
class FavoriteMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('FavouriteDetail')
@DataClassName('DriftFavouriteDetail')
class FavouriteDetails extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get relatedId => text().withDefault(const Constant(''))();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Favourite')
@DataClassName('DriftFavourite')
class Favourites extends Table {
IntColumn get id => integer()();
TextColumn get parentId => text().withDefault(const Constant(''))();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Group')
@DataClassName('DriftGroup')
class Groups extends Table {
IntColumn get id => integer()();
IntColumn get userJoinDate => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Message')
@DataClassName('DriftMessage')
class Messages extends Table {
IntColumn get id => integer()();
IntColumn get messageId => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('PendingFriendRequestHistory')
@DataClassName('DriftPendingFriendRequestHistory')
class PendingFriendRequestHistories extends Table {
IntColumn get id => integer()();
IntColumn get uid => integer()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('RecentMiniApp')
@DataClassName('DriftRecentMiniApp')
class RecentMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Retry')
@DataClassName('DriftRetry')
class Retries extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Sound')
@DataClassName('DriftSound')
class Sounds extends Table {
IntColumn get id => integer()();
TextColumn get filePath => text().withDefault(const Constant(''))();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Tag')
@DataClassName('DriftTag')
class Tags extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()();
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('UserRequestHistory')
@DataClassName('DriftUserRequestHistory')
class UserRequestHistories extends Table {
IntColumn get id => integer()();
IntColumn get status => integer().nullable()();
@@ -1,9 +1,9 @@
import 'package:drift/drift.dart';
@DataClassName('User')
@DataClassName('DriftUser')
class Users extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()();
IntColumn get uid => integer().unique()();
TextColumn get uuid => text().nullable()();
IntColumn get lastOnline => integer().nullable()();
TextColumn get profilePic => text().nullable()();
@@ -36,6 +36,7 @@ class Users extends Table {
TextColumn get publicKey => text().nullable()();
IntColumn get configBits => integer().withDefault(const Constant(0))();
TextColumn get hint => text().nullable()();
@override
String get tableName => 'user';
}
@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
@DataClassName('Workspace')
@DataClassName('DriftWorkspace')
class Workspaces extends Table {
IntColumn get id => integer()();
TextColumn get name => text().nullable()();
@@ -0,0 +1,122 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/call_log.dart';
/// 通话记录 DTOData Transfer Object
///
/// local / remote 共用的数据传输对象。
/// 提供与 Domain Entity [CallLog] 之间的双向转换。
class CallLogDto {
final String id;
final int? callerId;
final int? receiverId;
final int? chatId;
final int? duration;
final int? videoCall;
final int? createdAt;
final int? updatedAt;
final int? endedAt;
final int? status;
final int? isDeleted;
final int? deletedAt;
final int? isRead;
const CallLogDto({
required this.id,
this.callerId,
this.receiverId,
this.chatId,
this.duration,
this.videoCall,
this.createdAt,
this.updatedAt,
this.endedAt,
this.status,
this.isDeleted,
this.deletedAt,
this.isRead,
});
factory CallLogDto.fromJson(Map<String, dynamic> json) => CallLogDto(
id: json['id'] as String,
callerId: json['caller_id'],
receiverId: json['receiver_id'],
chatId: json['chat_id'],
duration: json['duration'],
videoCall: json['video_call'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
endedAt: json['ended_at'],
status: json['status'],
isDeleted: json['is_deleted'],
deletedAt: json['deleted_at'],
isRead: json['is_read'],
);
Map<String, dynamic> toJson() => {
'id': id,
'caller_id': callerId,
'receiver_id': receiverId,
'chat_id': chatId,
'duration': duration,
'video_call': videoCall,
'created_at': createdAt,
'updated_at': updatedAt,
'ended_at': endedAt,
'status': status,
'is_deleted': isDeleted,
'deleted_at': deletedAt,
'is_read': isRead,
};
/// DTO → Domain Entity
CallLog toEntity() => CallLog(
id: id,
callerId: callerId,
receiverId: receiverId,
chatId: chatId,
duration: duration,
videoCall: videoCall,
createdAt: createdAt,
updatedAt: updatedAt,
endedAt: endedAt,
status: status,
isDeleted: isDeleted,
deletedAt: deletedAt,
isRead: isRead,
);
/// Domain Entity → DTO
factory CallLogDto.fromEntity(CallLog callLog) => CallLogDto(
id: callLog.id,
callerId: callLog.callerId,
receiverId: callLog.receiverId,
chatId: callLog.chatId,
duration: callLog.duration,
videoCall: callLog.videoCall,
createdAt: callLog.createdAt,
updatedAt: callLog.updatedAt,
endedAt: callLog.endedAt,
status: callLog.status,
isDeleted: callLog.isDeleted,
deletedAt: callLog.deletedAt,
isRead: callLog.isRead,
);
/// DTO → Drift Companion (for DB insert/update)
CallLogsCompanion toCompanion() => CallLogsCompanion(
id: Value(id),
callerId: Value(callerId),
receiverId: Value(receiverId),
chatId: Value(chatId),
duration: Value(duration),
videoCall: Value(videoCall),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
endedAt: Value(endedAt),
status: Value(status),
isDeleted: Value(isDeleted),
deletedAt: Value(deletedAt),
isRead: Value(isRead),
);
}
@@ -0,0 +1,179 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/chat_bot.dart';
/// 聊天机器人 DTO
class ChatBotDto {
final int id;
final String? name;
final String? username;
final int? botUserId;
final String? icon;
final String? iconGaussian;
final String? description;
final String? token;
final int? flag;
final int? status;
final String? webhook;
final String? commands;
final String? banner;
final int? channelId;
final int? channelGroupId;
final int? deletedAt;
final String? internalWebhook;
final int? mode;
final String? redirectUrl;
final int? isInvitable;
final int? isAllowForward;
final String? tips;
const ChatBotDto({
required this.id,
this.name,
this.username,
this.botUserId,
this.icon,
this.iconGaussian,
this.description,
this.token,
this.flag,
this.status,
this.webhook,
this.commands,
this.banner,
this.channelId,
this.channelGroupId,
this.deletedAt,
this.internalWebhook,
this.mode,
this.redirectUrl,
this.isInvitable,
this.isAllowForward,
this.tips,
});
factory ChatBotDto.fromJson(Map<String, dynamic> json) => ChatBotDto(
id: json['id'] as int,
name: json['name'],
username: json['username'],
botUserId: json['bot_user_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
description: json['description'],
token: json['token'],
flag: json['flag'],
status: json['status'],
webhook: json['webhook'],
commands: json['commands'],
banner: json['banner'],
channelId: json['channel_id'],
channelGroupId: json['channel_group_id'],
deletedAt: json['deleted_at'],
internalWebhook: json['internal_webhook'],
mode: json['mode'],
redirectUrl: json['redirect_url'],
isInvitable: json['is_invitable'],
isAllowForward: json['is_allow_forward'],
tips: json['tips'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'username': username,
'bot_user_id': botUserId,
'icon': icon,
'icon_gaussian': iconGaussian,
'description': description,
'token': token,
'flag': flag,
'status': status,
'webhook': webhook,
'commands': commands,
'banner': banner,
'channel_id': channelId,
'channel_group_id': channelGroupId,
'deleted_at': deletedAt,
'internal_webhook': internalWebhook,
'mode': mode,
'redirect_url': redirectUrl,
'is_invitable': isInvitable,
'is_allow_forward': isAllowForward,
'tips': tips,
};
ChatBot toEntity() => ChatBot(
id: id,
name: name,
username: username,
botUserId: botUserId,
icon: icon,
iconGaussian: iconGaussian,
description: description,
token: token,
flag: flag,
status: status,
webhook: webhook,
commands: commands,
banner: banner,
channelId: channelId,
channelGroupId: channelGroupId,
deletedAt: deletedAt,
internalWebhook: internalWebhook,
mode: mode,
redirectUrl: redirectUrl,
isInvitable: isInvitable,
isAllowForward: isAllowForward,
tips: tips,
);
factory ChatBotDto.fromEntity(ChatBot chatBot) => ChatBotDto(
id: chatBot.id,
name: chatBot.name,
username: chatBot.username,
botUserId: chatBot.botUserId,
icon: chatBot.icon,
iconGaussian: chatBot.iconGaussian,
description: chatBot.description,
token: chatBot.token,
flag: chatBot.flag,
status: chatBot.status,
webhook: chatBot.webhook,
commands: chatBot.commands,
banner: chatBot.banner,
channelId: chatBot.channelId,
channelGroupId: chatBot.channelGroupId,
deletedAt: chatBot.deletedAt,
internalWebhook: chatBot.internalWebhook,
mode: chatBot.mode,
redirectUrl: chatBot.redirectUrl,
isInvitable: chatBot.isInvitable,
isAllowForward: chatBot.isAllowForward,
tips: chatBot.tips,
);
ChatBotsCompanion toCompanion() => ChatBotsCompanion(
id: Value(id),
name: Value(name),
username: Value(username),
botUserId: Value(botUserId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
description: Value(description),
token: Value(token),
flag: Value(flag),
status: Value(status),
webhook: Value(webhook ?? ''),
commands: Value(commands ?? '[]'),
banner: Value(banner),
channelId: Value(channelId),
channelGroupId: Value(channelGroupId),
deletedAt: Value(deletedAt),
internalWebhook: Value(internalWebhook),
mode: Value(mode),
redirectUrl: Value(redirectUrl),
isInvitable: Value(isInvitable),
isAllowForward: Value(isAllowForward),
tips: Value(tips),
);
}
@@ -0,0 +1,90 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/chat_category.dart';
/// 聊天分类 DTO
class ChatCategoryDto {
final int id;
final String? name;
final String? includedChatIds;
final String? excludedChatIds;
final int? seq;
final int isHide;
final int createdAt;
final int updatedAt;
final int deletedAt;
const ChatCategoryDto({
required this.id,
this.name,
this.includedChatIds,
this.excludedChatIds,
this.seq,
this.isHide = 0,
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
});
factory ChatCategoryDto.fromJson(Map<String, dynamic> json) =>
ChatCategoryDto(
id: json['id'] as int,
name: json['name'],
includedChatIds: json['included_chat_ids'],
excludedChatIds: json['excluded_chat_ids'],
seq: json['seq'],
isHide: json['is_hide'] ?? 0,
createdAt: json['created_at'] ?? 0,
updatedAt: json['updated_at'] ?? 0,
deletedAt: json['deleted_at'] ?? 0,
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'included_chat_ids': includedChatIds,
'excluded_chat_ids': excludedChatIds,
'seq': seq,
'is_hide': isHide,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
};
ChatCategory toEntity() => ChatCategory(
id: id,
name: name,
includedChatIds: includedChatIds,
excludedChatIds: excludedChatIds,
seq: seq,
isHide: isHide,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
);
factory ChatCategoryDto.fromEntity(ChatCategory chatCategory) =>
ChatCategoryDto(
id: chatCategory.id,
name: chatCategory.name,
includedChatIds: chatCategory.includedChatIds,
excludedChatIds: chatCategory.excludedChatIds,
seq: chatCategory.seq,
isHide: chatCategory.isHide,
createdAt: chatCategory.createdAt,
updatedAt: chatCategory.updatedAt,
deletedAt: chatCategory.deletedAt,
);
ChatCategoriesCompanion toCompanion() => ChatCategoriesCompanion(
id: Value(id),
name: Value(name),
includedChatIds: Value(includedChatIds),
excludedChatIds: Value(excludedChatIds),
seq: Value(seq),
isHide: Value(isHide),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
);
}
+200
View File
@@ -0,0 +1,200 @@
/// 聊天 Domain 实体
class Chat {
final int id;
final int? typ;
final int? lastId;
final int? lastTyp;
final String? lastMsg;
final int? lastTime;
final int lastPos;
final int firstPos;
final int? msgIdx;
final String? profile;
final String? pin;
final String? icon;
final String iconGaussian;
final String? name;
final int? userId;
final int? chatId;
final int? friendId;
final int? sort;
final int? unreadNum;
final int? unreadCount;
final int? hideChatMsgIdx;
final int? readChatMsgIdx;
final int? otherReadIdx;
final String? unreadAtMsgIdx;
final int? deleteTime;
final int? addIndex;
final int flag;
final int? flagMy;
final int? autoDeleteInterval;
final int? mute;
final int? verified;
final int? createTime;
final int? startIdx;
final int? isReadMsg;
final String translateOutgoing;
final String translateIncoming;
final int incomingIdx;
final int outgoingIdx;
final int incomingSoundId;
final int outgoingSoundId;
final int notificationSoundId;
final String chatKey;
final String activeChatKey;
final int coverIdx;
final int round;
final int workspaceId;
final int localPermission;
const Chat({
required this.id,
this.typ,
this.lastId,
this.lastTyp,
this.lastMsg,
this.lastTime,
this.lastPos = 0,
this.firstPos = -1,
this.msgIdx,
this.profile,
this.pin,
this.icon,
this.iconGaussian = '',
this.name,
this.userId,
this.chatId,
this.friendId,
this.sort,
this.unreadNum,
this.unreadCount,
this.hideChatMsgIdx,
this.readChatMsgIdx,
this.otherReadIdx,
this.unreadAtMsgIdx,
this.deleteTime,
this.addIndex,
this.flag = 0,
this.flagMy,
this.autoDeleteInterval,
this.mute,
this.verified,
this.createTime,
this.startIdx,
this.isReadMsg,
this.translateOutgoing = '',
this.translateIncoming = '',
this.incomingIdx = 0,
this.outgoingIdx = 0,
this.incomingSoundId = 0,
this.outgoingSoundId = 0,
this.notificationSoundId = 0,
this.chatKey = '',
this.activeChatKey = '',
this.coverIdx = 0,
this.round = 0,
this.workspaceId = 0,
this.localPermission = 0,
});
Chat copyWith({
int? id,
int? typ,
int? lastId,
int? lastTyp,
String? lastMsg,
int? lastTime,
int? lastPos,
int? firstPos,
int? msgIdx,
String? profile,
String? pin,
String? icon,
String? iconGaussian,
String? name,
int? userId,
int? chatId,
int? friendId,
int? sort,
int? unreadNum,
int? unreadCount,
int? hideChatMsgIdx,
int? readChatMsgIdx,
int? otherReadIdx,
String? unreadAtMsgIdx,
int? deleteTime,
int? addIndex,
int? flag,
int? flagMy,
int? autoDeleteInterval,
int? mute,
int? verified,
int? createTime,
int? startIdx,
int? isReadMsg,
String? translateOutgoing,
String? translateIncoming,
int? incomingIdx,
int? outgoingIdx,
int? incomingSoundId,
int? outgoingSoundId,
int? notificationSoundId,
String? chatKey,
String? activeChatKey,
int? coverIdx,
int? round,
int? workspaceId,
int? localPermission,
}) {
return Chat(
id: id ?? this.id,
typ: typ ?? this.typ,
lastId: lastId ?? this.lastId,
lastTyp: lastTyp ?? this.lastTyp,
lastMsg: lastMsg ?? this.lastMsg,
lastTime: lastTime ?? this.lastTime,
lastPos: lastPos ?? this.lastPos,
firstPos: firstPos ?? this.firstPos,
msgIdx: msgIdx ?? this.msgIdx,
profile: profile ?? this.profile,
pin: pin ?? this.pin,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
name: name ?? this.name,
userId: userId ?? this.userId,
chatId: chatId ?? this.chatId,
friendId: friendId ?? this.friendId,
sort: sort ?? this.sort,
unreadNum: unreadNum ?? this.unreadNum,
unreadCount: unreadCount ?? this.unreadCount,
hideChatMsgIdx: hideChatMsgIdx ?? this.hideChatMsgIdx,
readChatMsgIdx: readChatMsgIdx ?? this.readChatMsgIdx,
otherReadIdx: otherReadIdx ?? this.otherReadIdx,
unreadAtMsgIdx: unreadAtMsgIdx ?? this.unreadAtMsgIdx,
deleteTime: deleteTime ?? this.deleteTime,
addIndex: addIndex ?? this.addIndex,
flag: flag ?? this.flag,
flagMy: flagMy ?? this.flagMy,
autoDeleteInterval: autoDeleteInterval ?? this.autoDeleteInterval,
mute: mute ?? this.mute,
verified: verified ?? this.verified,
createTime: createTime ?? this.createTime,
startIdx: startIdx ?? this.startIdx,
isReadMsg: isReadMsg ?? this.isReadMsg,
translateOutgoing: translateOutgoing ?? this.translateOutgoing,
translateIncoming: translateIncoming ?? this.translateIncoming,
incomingIdx: incomingIdx ?? this.incomingIdx,
outgoingIdx: outgoingIdx ?? this.outgoingIdx,
incomingSoundId: incomingSoundId ?? this.incomingSoundId,
outgoingSoundId: outgoingSoundId ?? this.outgoingSoundId,
notificationSoundId: notificationSoundId ?? this.notificationSoundId,
chatKey: chatKey ?? this.chatKey,
activeChatKey: activeChatKey ?? this.activeChatKey,
coverIdx: coverIdx ?? this.coverIdx,
round: round ?? this.round,
workspaceId: workspaceId ?? this.workspaceId,
localPermission: localPermission ?? this.localPermission,
);
}
}
@@ -0,0 +1,112 @@
/// 发现小程序 Domain 实体
class DiscoverMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final String? lastLoginAt;
final String? screen;
const DiscoverMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
DiscoverMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
String? lastLoginAt,
String? screen,
}) {
return DiscoverMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}
@@ -0,0 +1,202 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/explore_mini_app.dart';
/// 探索小程序 DTO
class ExploreMiniAppDto {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const ExploreMiniAppDto({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
factory ExploreMiniAppDto.fromJson(Map<String, dynamic> json) =>
ExploreMiniAppDto(
id: json['id'] as String,
name: json['name'],
openuid: json['openuid'],
devId: json['dev_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
downloadUrl: json['download_url'],
description: json['description'],
version: json['version'],
typ: json['typ'],
flag: json['flag'],
reviewStatus: json['review_status'],
favoriteAt: json['favorite_at'],
isActive: json['is_active'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
score: json['score']?.toDouble(),
channels: json['channels'],
devName: json['dev_name'],
pictureGaussian: json['picture_gaussian'],
picture: json['picture'],
commentNum: json['comment_num'],
lastLoginAt: json['last_login_at'],
screen: json['screen'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'openuid': openuid,
'dev_id': devId,
'icon': icon,
'icon_gaussian': iconGaussian,
'download_url': downloadUrl,
'description': description,
'version': version,
'typ': typ,
'flag': flag,
'review_status': reviewStatus,
'favorite_at': favoriteAt,
'is_active': isActive,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'score': score,
'channels': channels,
'dev_name': devName,
'picture_gaussian': pictureGaussian,
'picture': picture,
'comment_num': commentNum,
'last_login_at': lastLoginAt,
'screen': screen,
};
ExploreMiniApp toEntity() => ExploreMiniApp(
id: id,
name: name,
openuid: openuid,
devId: devId,
icon: icon,
iconGaussian: iconGaussian,
downloadUrl: downloadUrl,
description: description,
version: version,
typ: typ,
flag: flag,
reviewStatus: reviewStatus,
favoriteAt: favoriteAt,
isActive: isActive,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
score: score,
channels: channels,
devName: devName,
pictureGaussian: pictureGaussian,
picture: picture,
commentNum: commentNum,
lastLoginAt: lastLoginAt,
screen: screen,
);
factory ExploreMiniAppDto.fromEntity(ExploreMiniApp app) =>
ExploreMiniAppDto(
id: app.id,
name: app.name,
openuid: app.openuid,
devId: app.devId,
icon: app.icon,
iconGaussian: app.iconGaussian,
downloadUrl: app.downloadUrl,
description: app.description,
version: app.version,
typ: app.typ,
flag: app.flag,
reviewStatus: app.reviewStatus,
favoriteAt: app.favoriteAt,
isActive: app.isActive,
createdAt: app.createdAt,
updatedAt: app.updatedAt,
deletedAt: app.deletedAt,
score: app.score,
channels: app.channels,
devName: app.devName,
pictureGaussian: app.pictureGaussian,
picture: app.picture,
commentNum: app.commentNum,
lastLoginAt: app.lastLoginAt,
screen: app.screen,
);
ExploreMiniAppsCompanion toCompanion() => ExploreMiniAppsCompanion(
id: Value(id),
name: Value(name),
openuid: Value(openuid),
devId: Value(devId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
downloadUrl: Value(downloadUrl),
description: Value(description),
version: Value(version),
typ: Value(typ),
flag: Value(flag),
reviewStatus: Value(reviewStatus),
favoriteAt: Value(favoriteAt),
isActive: Value(isActive),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
score: Value(score),
channels: Value(channels),
devName: Value(devName),
pictureGaussian: Value(pictureGaussian),
picture: Value(picture),
commentNum: Value(commentNum),
lastLoginAt: Value(lastLoginAt),
screen: Value(screen),
);
}
@@ -0,0 +1,202 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/favorite_mini_app.dart';
/// 收藏小程序 DTO
class FavoriteMiniAppDto {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const FavoriteMiniAppDto({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
factory FavoriteMiniAppDto.fromJson(Map<String, dynamic> json) =>
FavoriteMiniAppDto(
id: json['id'] as String,
name: json['name'],
openuid: json['openuid'],
devId: json['dev_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
downloadUrl: json['download_url'],
description: json['description'],
version: json['version'],
typ: json['typ'],
flag: json['flag'],
reviewStatus: json['review_status'],
favoriteAt: json['favorite_at'],
isActive: json['is_active'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
score: json['score']?.toDouble(),
channels: json['channels'],
devName: json['dev_name'],
pictureGaussian: json['picture_gaussian'],
picture: json['picture'],
commentNum: json['comment_num'],
lastLoginAt: json['last_login_at'],
screen: json['screen'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'openuid': openuid,
'dev_id': devId,
'icon': icon,
'icon_gaussian': iconGaussian,
'download_url': downloadUrl,
'description': description,
'version': version,
'typ': typ,
'flag': flag,
'review_status': reviewStatus,
'favorite_at': favoriteAt,
'is_active': isActive,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'score': score,
'channels': channels,
'dev_name': devName,
'picture_gaussian': pictureGaussian,
'picture': picture,
'comment_num': commentNum,
'last_login_at': lastLoginAt,
'screen': screen,
};
FavoriteMiniApp toEntity() => FavoriteMiniApp(
id: id,
name: name,
openuid: openuid,
devId: devId,
icon: icon,
iconGaussian: iconGaussian,
downloadUrl: downloadUrl,
description: description,
version: version,
typ: typ,
flag: flag,
reviewStatus: reviewStatus,
favoriteAt: favoriteAt,
isActive: isActive,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
score: score,
channels: channels,
devName: devName,
pictureGaussian: pictureGaussian,
picture: picture,
commentNum: commentNum,
lastLoginAt: lastLoginAt,
screen: screen,
);
factory FavoriteMiniAppDto.fromEntity(FavoriteMiniApp app) =>
FavoriteMiniAppDto(
id: app.id,
name: app.name,
openuid: app.openuid,
devId: app.devId,
icon: app.icon,
iconGaussian: app.iconGaussian,
downloadUrl: app.downloadUrl,
description: app.description,
version: app.version,
typ: app.typ,
flag: app.flag,
reviewStatus: app.reviewStatus,
favoriteAt: app.favoriteAt,
isActive: app.isActive,
createdAt: app.createdAt,
updatedAt: app.updatedAt,
deletedAt: app.deletedAt,
score: app.score,
channels: app.channels,
devName: app.devName,
pictureGaussian: app.pictureGaussian,
picture: app.picture,
commentNum: app.commentNum,
lastLoginAt: app.lastLoginAt,
screen: app.screen,
);
FavoriteMiniAppsCompanion toCompanion() => FavoriteMiniAppsCompanion(
id: Value(id),
name: Value(name),
openuid: Value(openuid),
devId: Value(devId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
downloadUrl: Value(downloadUrl),
description: Value(description),
version: Value(version),
typ: Value(typ),
flag: Value(flag),
reviewStatus: Value(reviewStatus),
favoriteAt: Value(favoriteAt),
isActive: Value(isActive),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
score: Value(score),
channels: Value(channels),
devName: Value(devName),
pictureGaussian: Value(pictureGaussian),
picture: Value(picture),
commentNum: Value(commentNum),
lastLoginAt: Value(lastLoginAt),
screen: Value(screen),
);
}
@@ -0,0 +1,83 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/favourite_detail.dart';
/// 收藏详情 DTO
class FavouriteDetailDto {
final int? id;
final String relatedId;
final String content;
final int? typ;
final int? messageId;
final int? sendId;
final int? chatId;
final int? sendTime;
const FavouriteDetailDto({
this.id,
this.relatedId = '',
this.content = '',
this.typ,
this.messageId,
this.sendId,
this.chatId,
this.sendTime,
});
factory FavouriteDetailDto.fromJson(Map<String, dynamic> json) =>
FavouriteDetailDto(
id: json['id'],
relatedId: json['related_id'] ?? '',
content: json['content'] ?? '',
typ: json['typ'],
messageId: json['messageId'],
sendId: json['sendId'],
chatId: json['chatId'],
sendTime: json['sendTime'],
);
Map<String, dynamic> toJson() => {
'id': id,
'related_id': relatedId,
'content': content,
'typ': typ,
'messageId': messageId,
'sendId': sendId,
'chatId': chatId,
'sendTime': sendTime,
};
FavouriteDetail toEntity() => FavouriteDetail(
id: id,
relatedId: relatedId,
content: content,
typ: typ,
messageId: messageId,
sendId: sendId,
chatId: chatId,
sendTime: sendTime,
);
factory FavouriteDetailDto.fromEntity(FavouriteDetail detail) =>
FavouriteDetailDto(
id: detail.id,
relatedId: detail.relatedId,
content: detail.content,
typ: detail.typ,
messageId: detail.messageId,
sendId: detail.sendId,
chatId: detail.chatId,
sendTime: detail.sendTime,
);
FavouriteDetailsCompanion toCompanion() => FavouriteDetailsCompanion(
id: id != null ? Value(id!) : const Value.absent(),
relatedId: Value(relatedId),
content: Value(content),
typ: Value(typ),
messageId: Value(messageId),
sendId: Value(sendId),
chatId: Value(chatId),
sendTime: Value(sendTime),
);
}
@@ -0,0 +1,130 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/favourite.dart';
/// 收藏 DTO
class FavouriteDto {
final int id;
final String parentId;
final String data;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int? source;
final int? userId;
final int? authorId;
final String typ;
final String tag;
final int isPin;
final int chatTyp;
final int isUploaded;
final String urls;
const FavouriteDto({
required this.id,
this.parentId = '',
this.data = '',
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
this.source,
this.userId,
this.authorId,
this.typ = '[]',
this.tag = '[]',
this.isPin = 0,
this.chatTyp = 0,
this.isUploaded = 1,
this.urls = '[]',
});
factory FavouriteDto.fromJson(Map<String, dynamic> json) => FavouriteDto(
id: json['id'] as int,
parentId: json['parent_id'] ?? '',
data: json['data'] ?? '',
createdAt: json['created_at'] ?? 0,
updatedAt: json['updated_at'] ?? 0,
deletedAt: json['deleted_at'] ?? 0,
source: json['source'],
userId: json['user_id'],
authorId: json['author_id'],
typ: json['typ'] ?? '[]',
tag: json['tag'] ?? '[]',
isPin: json['is_pin'] ?? 0,
chatTyp: json['chat_typ'] ?? 0,
isUploaded: json['is_uploaded'] ?? 1,
urls: json['urls'] ?? '[]',
);
Map<String, dynamic> toJson() => {
'id': id,
'parent_id': parentId,
'data': data,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'source': source,
'user_id': userId,
'author_id': authorId,
'typ': typ,
'tag': tag,
'is_pin': isPin,
'chat_typ': chatTyp,
'is_uploaded': isUploaded,
'urls': urls,
};
Favourite toEntity() => Favourite(
id: id,
parentId: parentId,
data: data,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
source: source,
userId: userId,
authorId: authorId,
typ: typ,
tag: tag,
isPin: isPin,
chatTyp: chatTyp,
isUploaded: isUploaded,
urls: urls,
);
factory FavouriteDto.fromEntity(Favourite favourite) => FavouriteDto(
id: favourite.id,
parentId: favourite.parentId,
data: favourite.data,
createdAt: favourite.createdAt,
updatedAt: favourite.updatedAt,
deletedAt: favourite.deletedAt,
source: favourite.source,
userId: favourite.userId,
authorId: favourite.authorId,
typ: favourite.typ,
tag: favourite.tag,
isPin: favourite.isPin,
chatTyp: favourite.chatTyp,
isUploaded: favourite.isUploaded,
urls: favourite.urls,
);
FavouritesCompanion toCompanion() => FavouritesCompanion(
id: Value(id),
parentId: Value(parentId),
data: Value(data),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
source: Value(source),
userId: Value(userId),
authorId: Value(authorId),
typ: Value(typ),
tag: Value(tag),
isPin: Value(isPin),
chatTyp: Value(chatTyp),
isUploaded: Value(isUploaded),
urls: Value(urls),
);
}
+221
View File
@@ -0,0 +1,221 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/group.dart';
/// 群组 DTO
class GroupDto {
final int id;
final int? userJoinDate;
final String? name;
final String? profile;
final String? icon;
final String iconGaussian;
final int? permission;
final int? admin;
final String? members;
final int? owner;
final String? admins;
final int? visible;
final int? speakInterval;
final int? groupType;
final int? roomType;
final int? maxNumber;
final int? channelId;
final int? channelGroupId;
final int? createTime;
final int? updateTime;
final int? addIndex;
final int? maxMember;
final int? expireTime;
final int workspaceId;
final int mode;
final int redpacketPlay;
final String? topic;
final String? rp;
const GroupDto({
required this.id,
this.userJoinDate,
this.name,
this.profile,
this.icon,
this.iconGaussian = '',
this.permission,
this.admin,
this.members,
this.owner,
this.admins,
this.visible,
this.speakInterval,
this.groupType,
this.roomType,
this.maxNumber,
this.channelId,
this.channelGroupId,
this.createTime,
this.updateTime,
this.addIndex,
this.maxMember,
this.expireTime,
this.workspaceId = 0,
this.mode = 0,
this.redpacketPlay = 0,
this.topic,
this.rp,
});
factory GroupDto.fromJson(Map<String, dynamic> json) => GroupDto(
id: json['id'] as int,
userJoinDate: json['user_join_date'],
name: json['name'],
profile: json['profile'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'] ?? '',
permission: json['permission'],
admin: json['admin'],
members: json['members'],
owner: json['owner'],
admins: json['admins'],
visible: json['visible'],
speakInterval: json['speak_interval'],
groupType: json['group_type'],
roomType: json['room_type'],
maxNumber: json['max_number'],
channelId: json['channel_id'],
channelGroupId: json['channel_group_id'],
createTime: json['create_time'],
updateTime: json['update_time'],
addIndex: json['__add_index'],
maxMember: json['max_member'],
expireTime: json['expire_time'],
workspaceId: json['workspace_id'] ?? 0,
mode: json['mode'] ?? 0,
redpacketPlay: json['redpacket_play'] ?? 0,
topic: json['topic'],
rp: json['rp'],
);
Map<String, dynamic> toJson() => {
'id': id,
'user_join_date': userJoinDate,
'name': name,
'profile': profile,
'icon': icon,
'icon_gaussian': iconGaussian,
'permission': permission,
'admin': admin,
'members': members,
'owner': owner,
'admins': admins,
'visible': visible,
'speak_interval': speakInterval,
'group_type': groupType,
'room_type': roomType,
'max_number': maxNumber,
'channel_id': channelId,
'channel_group_id': channelGroupId,
'create_time': createTime,
'update_time': updateTime,
'__add_index': addIndex,
'max_member': maxMember,
'expire_time': expireTime,
'workspace_id': workspaceId,
'mode': mode,
'redpacket_play': redpacketPlay,
'topic': topic,
'rp': rp,
};
Group toEntity() => Group(
id: id,
userJoinDate: userJoinDate,
name: name,
profile: profile,
icon: icon,
iconGaussian: iconGaussian,
permission: permission,
admin: admin,
members: members,
owner: owner,
admins: admins,
visible: visible,
speakInterval: speakInterval,
groupType: groupType,
roomType: roomType,
maxNumber: maxNumber,
channelId: channelId,
channelGroupId: channelGroupId,
createTime: createTime,
updateTime: updateTime,
addIndex: addIndex,
maxMember: maxMember,
expireTime: expireTime,
workspaceId: workspaceId,
mode: mode,
redpacketPlay: redpacketPlay,
topic: topic,
rp: rp,
);
factory GroupDto.fromEntity(Group group) => GroupDto(
id: group.id,
userJoinDate: group.userJoinDate,
name: group.name,
profile: group.profile,
icon: group.icon,
iconGaussian: group.iconGaussian,
permission: group.permission,
admin: group.admin,
members: group.members,
owner: group.owner,
admins: group.admins,
visible: group.visible,
speakInterval: group.speakInterval,
groupType: group.groupType,
roomType: group.roomType,
maxNumber: group.maxNumber,
channelId: group.channelId,
channelGroupId: group.channelGroupId,
createTime: group.createTime,
updateTime: group.updateTime,
addIndex: group.addIndex,
maxMember: group.maxMember,
expireTime: group.expireTime,
workspaceId: group.workspaceId,
mode: group.mode,
redpacketPlay: group.redpacketPlay,
topic: group.topic,
rp: group.rp,
);
GroupsCompanion toCompanion() => GroupsCompanion(
id: Value(id),
userJoinDate: Value(userJoinDate),
name: Value(name),
profile: Value(profile),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
permission: Value(permission),
admin: Value(admin),
members: Value(members),
owner: Value(owner),
admins: Value(admins),
visible: Value(visible),
speakInterval: Value(speakInterval),
groupType: Value(groupType),
roomType: Value(roomType),
maxNumber: Value(maxNumber),
channelId: Value(channelId),
channelGroupId: Value(channelGroupId),
createTime: Value(createTime),
updateTime: Value(updateTime),
addIndex: Value(addIndex),
maxMember: Value(maxMember),
expireTime: Value(expireTime),
workspaceId: Value(workspaceId),
mode: Value(mode),
redpacketPlay: Value(redpacketPlay),
topic: Value(topic),
rp: Value(rp),
);
}
@@ -0,0 +1,137 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/message.dart';
/// 消息 DTO
class MessageDto {
final int id;
final int? messageId;
final int? chatId;
final int? chatIdx;
final int? sendId;
final String? content;
final int? typ;
final int? sendTime;
final int? expireTime;
final int? createTime;
final String? atUsers;
final String emojis;
final int editTime;
final int refTyp;
final int flag;
final String cmid;
const MessageDto({
required this.id,
this.messageId,
this.chatId,
this.chatIdx,
this.sendId,
this.content,
this.typ,
this.sendTime,
this.expireTime,
this.createTime,
this.atUsers,
this.emojis = '[]',
this.editTime = 0,
this.refTyp = 0,
this.flag = 0,
this.cmid = '',
});
factory MessageDto.fromJson(Map<String, dynamic> json) => MessageDto(
id: json['id'] as int,
messageId: json['message_id'],
chatId: json['chat_id'],
chatIdx: json['chat_idx'],
sendId: json['send_id'],
content: json['content'],
typ: json['typ'],
sendTime: json['send_time'],
expireTime: json['expire_time'],
createTime: json['create_time'],
atUsers: json['at_users'],
emojis: json['emojis'] ?? '[]',
editTime: json['edit_time'] ?? 0,
refTyp: json['ref_typ'] ?? 0,
flag: json['flag'] ?? 0,
cmid: json['cmid'] ?? '',
);
Map<String, dynamic> toJson() => {
'id': id,
'message_id': messageId,
'chat_id': chatId,
'chat_idx': chatIdx,
'send_id': sendId,
'content': content,
'typ': typ,
'send_time': sendTime,
'expire_time': expireTime,
'create_time': createTime,
'at_users': atUsers,
'emojis': emojis,
'edit_time': editTime,
'ref_typ': refTyp,
'flag': flag,
'cmid': cmid,
};
Message toEntity() => Message(
id: id,
messageId: messageId,
chatId: chatId,
chatIdx: chatIdx,
sendId: sendId,
content: content,
typ: typ,
sendTime: sendTime,
expireTime: expireTime,
createTime: createTime,
atUsers: atUsers,
emojis: emojis,
editTime: editTime,
refTyp: refTyp,
flag: flag,
cmid: cmid,
);
factory MessageDto.fromEntity(Message message) => MessageDto(
id: message.id,
messageId: message.messageId,
chatId: message.chatId,
chatIdx: message.chatIdx,
sendId: message.sendId,
content: message.content,
typ: message.typ,
sendTime: message.sendTime,
expireTime: message.expireTime,
createTime: message.createTime,
atUsers: message.atUsers,
emojis: message.emojis,
editTime: message.editTime,
refTyp: message.refTyp,
flag: message.flag,
cmid: message.cmid,
);
MessagesCompanion toCompanion() => MessagesCompanion(
id: Value(id),
messageId: Value(messageId),
chatId: Value(chatId),
chatIdx: Value(chatIdx),
sendId: Value(sendId),
content: Value(content),
typ: Value(typ),
sendTime: Value(sendTime),
expireTime: Value(expireTime),
createTime: Value(createTime),
atUsers: Value(atUsers),
emojis: Value(emojis),
editTime: Value(editTime),
refTyp: Value(refTyp),
flag: Value(flag),
cmid: Value(cmid),
);
}
@@ -0,0 +1,71 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/pending_friend_request_history.dart';
/// 待处理好友请求历史 DTO
class PendingFriendRequestHistoryDto {
final int id;
final int uid;
final int requestTime;
final String? remarks;
final String? source;
final int? rs;
const PendingFriendRequestHistoryDto({
required this.id,
required this.uid,
required this.requestTime,
this.remarks,
this.source,
this.rs,
});
factory PendingFriendRequestHistoryDto.fromJson(Map<String, dynamic> json) =>
PendingFriendRequestHistoryDto(
id: json['id'] as int,
uid: json['uid'] as int,
requestTime: json['request_time'] as int,
remarks: json['remarks'],
source: json['source'],
rs: json['rs'],
);
Map<String, dynamic> toJson() => {
'id': id,
'uid': uid,
'request_time': requestTime,
'remarks': remarks,
'source': source,
'rs': rs,
};
PendingFriendRequestHistory toEntity() => PendingFriendRequestHistory(
id: id,
uid: uid,
requestTime: requestTime,
remarks: remarks,
source: source,
rs: rs,
);
factory PendingFriendRequestHistoryDto.fromEntity(
PendingFriendRequestHistory history) =>
PendingFriendRequestHistoryDto(
id: history.id,
uid: history.uid,
requestTime: history.requestTime,
remarks: history.remarks,
source: history.source,
rs: history.rs,
);
PendingFriendRequestHistoriesCompanion toCompanion() =>
PendingFriendRequestHistoriesCompanion(
id: Value(id),
uid: Value(uid),
requestTime: Value(requestTime),
remarks: Value(remarks),
source: Value(source),
rs: Value(rs),
);
}
@@ -0,0 +1,201 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/recent_mini_app.dart';
/// 最近小程序 DTO
class RecentMiniAppDto {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const RecentMiniAppDto({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
factory RecentMiniAppDto.fromJson(Map<String, dynamic> json) =>
RecentMiniAppDto(
id: json['id'] as String,
name: json['name'],
openuid: json['openuid'],
devId: json['dev_id'],
icon: json['icon'],
iconGaussian: json['icon_gaussian'],
downloadUrl: json['download_url'],
description: json['description'],
version: json['version'],
typ: json['typ'],
flag: json['flag'],
reviewStatus: json['review_status'],
favoriteAt: json['favorite_at'],
isActive: json['is_active'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
score: json['score']?.toDouble(),
channels: json['channels'],
devName: json['dev_name'],
pictureGaussian: json['picture_gaussian'],
picture: json['picture'],
commentNum: json['comment_num'],
lastLoginAt: json['last_login_at'],
screen: json['screen'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'openuid': openuid,
'dev_id': devId,
'icon': icon,
'icon_gaussian': iconGaussian,
'download_url': downloadUrl,
'description': description,
'version': version,
'typ': typ,
'flag': flag,
'review_status': reviewStatus,
'favorite_at': favoriteAt,
'is_active': isActive,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'score': score,
'channels': channels,
'dev_name': devName,
'picture_gaussian': pictureGaussian,
'picture': picture,
'comment_num': commentNum,
'last_login_at': lastLoginAt,
'screen': screen,
};
RecentMiniApp toEntity() => RecentMiniApp(
id: id,
name: name,
openuid: openuid,
devId: devId,
icon: icon,
iconGaussian: iconGaussian,
downloadUrl: downloadUrl,
description: description,
version: version,
typ: typ,
flag: flag,
reviewStatus: reviewStatus,
favoriteAt: favoriteAt,
isActive: isActive,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
score: score,
channels: channels,
devName: devName,
pictureGaussian: pictureGaussian,
picture: picture,
commentNum: commentNum,
lastLoginAt: lastLoginAt,
screen: screen,
);
factory RecentMiniAppDto.fromEntity(RecentMiniApp app) => RecentMiniAppDto(
id: app.id,
name: app.name,
openuid: app.openuid,
devId: app.devId,
icon: app.icon,
iconGaussian: app.iconGaussian,
downloadUrl: app.downloadUrl,
description: app.description,
version: app.version,
typ: app.typ,
flag: app.flag,
reviewStatus: app.reviewStatus,
favoriteAt: app.favoriteAt,
isActive: app.isActive,
createdAt: app.createdAt,
updatedAt: app.updatedAt,
deletedAt: app.deletedAt,
score: app.score,
channels: app.channels,
devName: app.devName,
pictureGaussian: app.pictureGaussian,
picture: app.picture,
commentNum: app.commentNum,
lastLoginAt: app.lastLoginAt,
screen: app.screen,
);
RecentMiniAppsCompanion toCompanion() => RecentMiniAppsCompanion(
id: Value(id),
name: Value(name),
openuid: Value(openuid),
devId: Value(devId),
icon: Value(icon),
iconGaussian: Value(iconGaussian),
downloadUrl: Value(downloadUrl),
description: Value(description),
version: Value(version),
typ: Value(typ),
flag: Value(flag),
reviewStatus: Value(reviewStatus),
favoriteAt: Value(favoriteAt),
isActive: Value(isActive),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
score: Value(score),
channels: Value(channels),
devName: Value(devName),
pictureGaussian: Value(pictureGaussian),
picture: Value(picture),
commentNum: Value(commentNum),
lastLoginAt: Value(lastLoginAt),
screen: Value(screen),
);
}
+109
View File
@@ -0,0 +1,109 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/retry.dart';
/// 重试 DTO
class RetryDto {
final int? id;
final int? uid;
final String apiType;
final String endPoint;
final String requestData;
final int? synced;
final String callbackFun;
final int? expired;
final int? replace;
final int? expireTime;
final int? createTime;
final int? addIndex;
const RetryDto({
this.id,
this.uid,
this.apiType = '',
this.endPoint = '',
this.requestData = '',
this.synced,
this.callbackFun = '',
this.expired,
this.replace,
this.expireTime,
this.createTime,
this.addIndex,
});
factory RetryDto.fromJson(Map<String, dynamic> json) => RetryDto(
id: json['id'],
uid: json['uid'],
apiType: json['api_type'] ?? '',
endPoint: json['end_point'] ?? '',
requestData: json['request_data'] ?? '',
synced: json['synced'],
callbackFun: json['callback_fun'] ?? '',
expired: json['expired'],
replace: json['replace'],
expireTime: json['expire_time'],
createTime: json['create_time'],
addIndex: json['__add_index'],
);
Map<String, dynamic> toJson() => {
'id': id,
'uid': uid,
'api_type': apiType,
'end_point': endPoint,
'request_data': requestData,
'synced': synced,
'callback_fun': callbackFun,
'expired': expired,
'replace': replace,
'expire_time': expireTime,
'create_time': createTime,
'__add_index': addIndex,
};
Retry toEntity() => Retry(
id: id,
uid: uid,
apiType: apiType,
endPoint: endPoint,
requestData: requestData,
synced: synced,
callbackFun: callbackFun,
expired: expired,
replace: replace,
expireTime: expireTime,
createTime: createTime,
addIndex: addIndex,
);
factory RetryDto.fromEntity(Retry retry) => RetryDto(
id: retry.id,
uid: retry.uid,
apiType: retry.apiType,
endPoint: retry.endPoint,
requestData: retry.requestData,
synced: retry.synced,
callbackFun: retry.callbackFun,
expired: retry.expired,
replace: retry.replace,
expireTime: retry.expireTime,
createTime: retry.createTime,
addIndex: retry.addIndex,
);
RetriesCompanion toCompanion() => RetriesCompanion(
id: id != null ? Value(id!) : const Value.absent(),
uid: Value(uid),
apiType: Value(apiType),
endPoint: Value(endPoint),
requestData: Value(requestData),
synced: Value(synced),
callbackFun: Value(callbackFun),
expired: Value(expired),
replace: Value(replace),
expireTime: Value(expireTime),
createTime: Value(createTime),
addIndex: Value(addIndex),
);
}
@@ -0,0 +1,88 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/sound.dart';
/// 音效 DTO
class SoundDto {
final int id;
final String filePath;
final int typ;
final String name;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int channelGroupId;
final int isDefault;
const SoundDto({
required this.id,
this.filePath = '',
required this.typ,
this.name = '',
required this.createdAt,
required this.updatedAt,
this.deletedAt = 0,
required this.channelGroupId,
required this.isDefault,
});
factory SoundDto.fromJson(Map<String, dynamic> json) => SoundDto(
id: json['id'] as int,
filePath: json['file_path'] ?? '',
typ: json['typ'] as int,
name: json['name'] ?? '',
createdAt: json['created_at'] as int,
updatedAt: json['updated_at'] as int,
deletedAt: json['deleted_at'] ?? 0,
channelGroupId: json['channel_group_id'] as int,
isDefault: json['is_default'] as int,
);
Map<String, dynamic> toJson() => {
'id': id,
'file_path': filePath,
'typ': typ,
'name': name,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'channel_group_id': channelGroupId,
'is_default': isDefault,
};
Sound toEntity() => Sound(
id: id,
filePath: filePath,
typ: typ,
name: name,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
channelGroupId: channelGroupId,
isDefault: isDefault,
);
factory SoundDto.fromEntity(Sound sound) => SoundDto(
id: sound.id,
filePath: sound.filePath,
typ: sound.typ,
name: sound.name,
createdAt: sound.createdAt,
updatedAt: sound.updatedAt,
deletedAt: sound.deletedAt,
channelGroupId: sound.channelGroupId,
isDefault: sound.isDefault,
);
SoundsCompanion toCompanion() => SoundsCompanion(
id: Value(id),
filePath: Value(filePath),
typ: Value(typ),
name: Value(name),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
channelGroupId: Value(channelGroupId),
isDefault: Value(isDefault),
);
}
+74
View File
@@ -0,0 +1,74 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/tag.dart';
/// 标签 DTO
class TagDto {
final int? id;
final int? uid;
final String name;
final int? type;
final int? createdAt;
final int? updatedAt;
final int? addIndex;
const TagDto({
this.id,
this.uid,
this.name = '',
this.type,
this.createdAt,
this.updatedAt,
this.addIndex,
});
factory TagDto.fromJson(Map<String, dynamic> json) => TagDto(
id: json['id'],
uid: json['uid'],
name: json['name'] ?? '',
type: json['type'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
addIndex: json['__add_index'],
);
Map<String, dynamic> toJson() => {
'id': id,
'uid': uid,
'name': name,
'type': type,
'created_at': createdAt,
'updated_at': updatedAt,
'__add_index': addIndex,
};
Tag toEntity() => Tag(
id: id,
uid: uid,
name: name,
type: type,
createdAt: createdAt,
updatedAt: updatedAt,
addIndex: addIndex,
);
factory TagDto.fromEntity(Tag tag) => TagDto(
id: tag.id,
uid: tag.uid,
name: tag.name,
type: tag.type,
createdAt: tag.createdAt,
updatedAt: tag.updatedAt,
addIndex: tag.addIndex,
);
TagsCompanion toCompanion() => TagsCompanion(
id: id != null ? Value(id!) : const Value.absent(),
uid: Value(uid),
name: Value(name),
type: Value(type),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
addIndex: Value(addIndex),
);
}
+130 -50
View File
@@ -1,68 +1,148 @@
import 'package:json_annotation/json_annotation.dart';
import '../../domain/entities/user.dart';
part 'user_dto.g.dart';
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/user.dart';
/// 用户 DTOData Transfer Object
///
/// local / remote 共用的数据传输对象,放在 data/models/。
/// 提供与 Domain Entity [User] 之间的双向转换。
///
/// ## 数据流位置(本地存储场景)
///
/// ```
/// 写入本地:
/// LoginData.toEntity() → User
/// → UserDto.fromEntity(user) → ★ UserDto ★ ← 你在这里
/// → toJson() → SQLite / SharedPreferences
///
/// 读取本地:
/// SQLite / SharedPreferences → JSON
/// → ★ UserDto.fromJson() ★ ← 你在这里
/// → UserDto.toEntity() → User
/// → ViewModel.state → View
/// ```
///
/// 注意:登录接口的 Response DTO 是 [LoginData](含 token),
/// 本类用于纯用户信息的本地持久化,不含 token。
@JsonSerializable()
class UserDto {
@JsonKey(name: 'user_id')
final String userId;
final String email;
final int uid;
final String? uuid;
final int? lastOnline;
final String? profilePic;
final String? profilePicGaussian;
final String? nickname;
final String? avatar;
final String? contact;
final String? countryCode;
final String? email;
final String? recoveryEmail;
final String? username;
final String? bio;
final int? relationship;
final String? userAlias;
final int? channelId;
final int? channelGroupId;
final String? hint;
const UserDto({
required this.userId,
required this.email,
required this.uid,
this.uuid,
this.lastOnline,
this.profilePic,
this.profilePicGaussian,
this.nickname,
this.avatar,
this.contact,
this.countryCode,
this.email,
this.recoveryEmail,
this.username,
this.bio,
this.relationship,
this.userAlias,
this.channelId,
this.channelGroupId,
this.hint,
});
factory UserDto.fromJson(Map<String, dynamic> json) =>
_$UserDtoFromJson(json);
factory UserDto.fromJson(Map<String, dynamic> json) => UserDto(
uid: json['uid'] as int,
uuid: json['uuid'],
lastOnline: json['last_online'],
profilePic: json['profile_pic'],
profilePicGaussian: json['profile_pic_gaussian'] ?? '',
nickname: json['nickname'],
contact: json['contact'],
countryCode: json['country_code'],
email: json['email'],
recoveryEmail: json['recovery_email'] ?? '',
username: json['username'],
bio: json['bio'] ?? '',
relationship: json['relationship'],
userAlias: json['user_alias'],
channelId: json['channel_id'],
channelGroupId: json['channel_group_id'],
hint: json['hint'],
);
Map<String, dynamic> toJson() => _$UserDtoToJson(this);
Map<String, dynamic> toJson() => {
'uid': uid,
'uuid': uuid,
'last_online': lastOnline,
'profile_pic': profilePic,
'profile_pic_gaussian': profilePicGaussian,
'nickname': nickname,
'contact': contact,
'country_code': countryCode,
'email': email,
'recovery_email': recoveryEmail,
'username': username,
'bio': bio,
'relationship': relationship,
'user_alias': userAlias,
'channel_id': channelId,
'channel_group_id': channelGroupId,
'hint': hint,
};
/// DTO → Domain Entity
User toEntity() {
return User(
id: userId,
email: email,
nickname: nickname,
avatar: avatar,
);
}
User toEntity() => User(
uid: uid,
uuid: uuid,
lastOnline: lastOnline,
profilePic: profilePic,
profilePicGaussian: profilePicGaussian,
nickname: nickname,
contact: contact,
countryCode: countryCode,
email: email,
recoveryEmail: recoveryEmail,
username: username,
bio: bio,
relationship: relationship,
userAlias: userAlias,
channelId: channelId,
channelGroupId: channelGroupId,
hint: hint,
);
/// Domain Entity → DTO
factory UserDto.fromEntity(User user) {
return UserDto(
userId: user.id,
email: user.email,
nickname: user.nickname,
avatar: user.avatar,
);
}
factory UserDto.fromEntity(User user) => UserDto(
uid: user.uid,
uuid: user.uuid,
lastOnline: user.lastOnline,
profilePic: user.profilePic,
profilePicGaussian: user.profilePicGaussian,
nickname: user.nickname,
contact: user.contact,
countryCode: user.countryCode,
email: user.email,
recoveryEmail: user.recoveryEmail,
username: user.username,
bio: user.bio,
relationship: user.relationship,
userAlias: user.userAlias,
channelId: user.channelId,
channelGroupId: user.channelGroupId,
hint: user.hint,
);
/// DTO → Drift Companion (for DB insert/update)
UsersCompanion toCompanion() => UsersCompanion(
uid: Value(uid),
uuid: Value(uuid),
lastOnline: Value(lastOnline),
profilePic: Value(profilePic),
profilePicGaussian: Value(profilePicGaussian ?? ''),
nickname: Value(nickname),
contact: Value(contact),
countryCode: Value(countryCode),
email: Value(email),
recoveryEmail: Value(recoveryEmail),
username: Value(username),
bio: Value(bio),
relationship: Value(relationship),
userAlias: Value(userAlias),
hint: Value(hint),
);
}
@@ -0,0 +1,49 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/user_request_history.dart';
/// 用户请求历史 DTO
class UserRequestHistoryDto {
final int id;
final int? status;
final int? createdAt;
const UserRequestHistoryDto({
required this.id,
this.status,
this.createdAt,
});
factory UserRequestHistoryDto.fromJson(Map<String, dynamic> json) =>
UserRequestHistoryDto(
id: json['id'] as int,
status: json['status'],
createdAt: json['created_at'],
);
Map<String, dynamic> toJson() => {
'id': id,
'status': status,
'created_at': createdAt,
};
UserRequestHistory toEntity() => UserRequestHistory(
id: id,
status: status,
createdAt: createdAt,
);
factory UserRequestHistoryDto.fromEntity(UserRequestHistory history) =>
UserRequestHistoryDto(
id: history.id,
status: history.status,
createdAt: history.createdAt,
);
UserRequestHistoriesCompanion toCompanion() =>
UserRequestHistoriesCompanion(
id: Value(id),
status: Value(status),
createdAt: Value(createdAt),
);
}
@@ -0,0 +1,116 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/app_database.dart';
import 'package:im_app/domain/entities/workspace.dart';
/// 工作空间 DTO
class WorkspaceDto {
final int id;
final String? name;
final int? ownerId;
final String? description;
final String? logo;
final int? grade;
final int? cap;
final String? currency;
final int? status;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final int? channelGroupId;
const WorkspaceDto({
required this.id,
this.name,
this.ownerId,
this.description,
this.logo,
this.grade,
this.cap,
this.currency,
this.status,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.channelGroupId,
});
factory WorkspaceDto.fromJson(Map<String, dynamic> json) => WorkspaceDto(
id: json['id'] as int,
name: json['name'],
ownerId: json['owner_id'],
description: json['description'],
logo: json['logo'],
grade: json['grade'],
cap: json['cap'],
currency: json['currency'],
status: json['status'],
createdAt: json['created_at'],
updatedAt: json['updated_at'],
deletedAt: json['deleted_at'],
channelGroupId: json['channel_group_id'],
);
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'owner_id': ownerId,
'description': description,
'logo': logo,
'grade': grade,
'cap': cap,
'currency': currency,
'status': status,
'created_at': createdAt,
'updated_at': updatedAt,
'deleted_at': deletedAt,
'channel_group_id': channelGroupId,
};
Workspace toEntity() => Workspace(
id: id,
name: name,
ownerId: ownerId,
description: description,
logo: logo,
grade: grade,
cap: cap,
currency: currency,
status: status,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
channelGroupId: channelGroupId,
);
factory WorkspaceDto.fromEntity(Workspace workspace) => WorkspaceDto(
id: workspace.id,
name: workspace.name,
ownerId: workspace.ownerId,
description: workspace.description,
logo: workspace.logo,
grade: workspace.grade,
cap: workspace.cap,
currency: workspace.currency,
status: workspace.status,
createdAt: workspace.createdAt,
updatedAt: workspace.updatedAt,
deletedAt: workspace.deletedAt,
channelGroupId: workspace.channelGroupId,
);
WorkspacesCompanion toCompanion() => WorkspacesCompanion(
id: Value(id),
name: Value(name),
ownerId: Value(ownerId),
description: Value(description),
logo: Value(logo),
grade: Value(grade),
cap: Value(cap),
currency: Value(currency),
status: Value(status),
createdAt: Value(createdAt),
updatedAt: Value(updatedAt),
deletedAt: Value(deletedAt),
channelGroupId: Value(channelGroupId),
);
}
@@ -28,31 +28,75 @@ part 'get_profile_request.g.dart';
/// 用户资料响应 DTO(只需反序列化,禁止生成无用的 toJson)
@JsonSerializable(createToJson: false)
class ProfileData {
@JsonKey(name: 'user_id')
final String userId;
final int uid;
final String uuid;
@JsonKey(name: 'last_online')
final int lastOnline;
@JsonKey(name: 'profile_pic')
final String profilePic;
@JsonKey(name: 'profile_pic_gaussian')
final String profilePicGaussian;
final String nickname;
final String contact;
@JsonKey(name: 'country_code')
final String countryCode;
final String email;
final String? nickname;
final String? avatar;
@JsonKey(name: 'recovery_email')
final String recoveryEmail;
final String username;
final String bio;
final int relationship;
@JsonKey(name: 'user_alias')
final String? userAlias;
@JsonKey(name: 'channel_id')
final int channelId;
@JsonKey(name: 'channel_group_id')
final int channelGroupId;
final String hint;
const ProfileData({
required this.userId,
required this.uid,
required this.uuid,
required this.lastOnline,
required this.profilePic,
required this.profilePicGaussian,
required this.nickname,
required this.contact,
required this.countryCode,
required this.email,
this.nickname,
this.avatar,
required this.recoveryEmail,
required this.username,
required this.bio,
required this.relationship,
this.userAlias,
required this.channelId,
required this.channelGroupId,
required this.hint,
});
factory ProfileData.fromJson(Map<String, dynamic> json) =>
_$ProfileDataFromJson(json);
/// DTO → Domain Entity
User toEntity() {
return User(
id: userId,
email: email,
nickname: nickname,
avatar: avatar,
);
}
User toEntity() => User(
uid: uid,
uuid: uuid,
lastOnline: lastOnline,
profilePic: profilePic,
profilePicGaussian: profilePicGaussian,
nickname: nickname,
contact: contact,
countryCode: countryCode,
email: email,
recoveryEmail: recoveryEmail,
username: username,
bio: bio,
relationship: relationship,
userAlias: userAlias,
channelId: channelId,
channelGroupId: channelGroupId,
hint: hint,
);
}
// ─────────────────────────────────────────────
+116 -36
View File
@@ -8,75 +8,155 @@ part 'login_request.g.dart';
/// # /auth/login — 登录接口
///
/// 一个端点 = 一个文件,Response DTO + Request 放在同一文件中。
///
/// ## 数据流位置
///
/// ```
/// AuthRepositoryImpl.login(email, password)
/// → _client.executeRequest( ★ LoginRequest ★ ) ← 你在这里
/// → 服务端 POST /auth/login
/// → 响应 JSON → ★ LoginData ★ ← 也在这里
/// → LoginData.toEntity() → User
/// → 响应 JSON → ★ LoginResponse ★ ← 也在这里
/// → LoginResponse.toEntity() → User
/// ```
// ─────────────────────────────────────────────
// Response DTO
// ─────────────────────────────────────────────
/// 登录响应 DTO
///
/// 服务端返回的登录数据,包含 token 和用户信息。
/// 通过 [toEntity] 转换为 Domain Entity [User]。
@JsonSerializable()
class LoginData {
final String token;
@JsonKey(name: 'user_id')
final String userId;
@JsonSerializable(createToJson: false)
class LoginProfile {
final int uid;
final String uuid;
@JsonKey(name: 'last_online')
final int lastOnline;
@JsonKey(name: 'profile_pic')
final String profilePic;
@JsonKey(name: 'profile_pic_gaussian')
final String profilePicGaussian;
final String nickname;
final String contact;
@JsonKey(name: 'country_code')
final String countryCode;
final String email;
final String? nickname;
final String? avatar;
@JsonKey(name: 'recovery_email')
final String recoveryEmail;
final String username;
final String bio;
final int relationship;
@JsonKey(name: 'user_alias')
final String? userAlias;
@JsonKey(name: 'channel_id')
final int channelId;
@JsonKey(name: 'channel_group_id')
final int channelGroupId;
final String hint;
const LoginProfile({
required this.uid,
required this.uuid,
required this.lastOnline,
required this.profilePic,
required this.profilePicGaussian,
required this.nickname,
required this.contact,
required this.countryCode,
required this.email,
required this.recoveryEmail,
required this.username,
required this.bio,
required this.relationship,
this.userAlias,
required this.channelId,
required this.channelGroupId,
required this.hint,
});
factory LoginProfile.fromJson(Map<String, dynamic> json) =>
_$LoginProfileFromJson(json);
User toEntity() => User(
uid: uid,
uuid: uuid,
lastOnline: lastOnline,
profilePic: profilePic,
profilePicGaussian: profilePicGaussian,
nickname: nickname,
contact: contact,
countryCode: countryCode,
email: email,
recoveryEmail: recoveryEmail,
username: username,
bio: bio,
relationship: relationship,
userAlias: userAlias,
channelId: channelId,
channelGroupId: channelGroupId,
hint: hint,
);
}
@JsonSerializable(createToJson: false, explicitToJson: true)
class LoginData {
@JsonKey(name: 'account_id')
final String accountId;
final LoginProfile profile;
final String nonce;
@JsonKey(name: 'access_token')
final String accessToken;
@JsonKey(name: 'refresh_token')
final String refreshToken;
@JsonKey(name: 'device_id')
final String deviceId;
@JsonKey(name: 'login_data')
final String loginData;
const LoginData({
required this.token,
required this.userId,
required this.email,
this.nickname,
this.avatar,
required this.accountId,
required this.profile,
required this.nonce,
required this.accessToken,
required this.refreshToken,
required this.deviceId,
required this.loginData,
});
factory LoginData.fromJson(Map<String, dynamic> json) =>
_$LoginDataFromJson(json);
Map<String, dynamic> toJson() => _$LoginDataToJson(this);
User toEntity() => profile.toEntity();
}
/// DTO → Domain Entity
User toEntity() {
return User(
id: userId,
email: email,
nickname: nickname,
avatar: avatar,
);
}
/// Top-level envelope: { "code": 0, "message": "OK", "data": { ... } }
@JsonSerializable(createToJson: false, explicitToJson: true)
class LoginResponse {
final int code;
final String message;
final LoginData data;
const LoginResponse({
required this.code,
required this.message,
required this.data,
});
factory LoginResponse.fromJson(Map<String, dynamic> json) =>
_$LoginResponseFromJson(json);
User toEntity() => data.toEntity();
}
// ─────────────────────────────────────────────
// Request
// ─────────────────────────────────────────────
/// 登录请求
///
/// `@ApiRequest` 自动生成 `_$LoginRequestApi` mixin
/// 提供 path / method / requestType / includeToken / fromJson 自动注册。
@ApiRequest(
path: ApiPaths.authLogin,
method: HttpMethod.post,
responseType: LoginData,
responseType: LoginResponse,
requestType: ApiRequestType.login,
)
@JsonSerializable()
class LoginRequest extends ApiRequestable<LoginData> with _$LoginRequestApi {
class LoginRequest extends ApiRequestable<LoginResponse>
with _$LoginRequestApi {
final String email;
final String password;
@@ -30,18 +30,18 @@ class AuthRepositoryImpl implements AuthRepository {
AuthRepositoryImpl({required NetworksSdkApi client, required void Function(String?) onTokenUpdate,}) : _client = client, _onTokenUpdate = onTokenUpdate;
@override
Future<User> login({required String email, required String password,}) async
{
final LoginData? loginData = await _client.executeRequest(LoginRequest(email: email, password: password),);
Future<User> login({required String email, required String password}) async {
final LoginResponse? loginResponse = await _client.executeRequest(
LoginRequest(email: email, password: password),
);
if (loginData == null) {
throw Exception('Login failed: empty response'); // TODO: 接入国际化
if (loginResponse == null) {
throw Exception('Login failed: empty response');
}
// 回调写入 Token(内存 + 持久化由 Provider 层组合)
_onTokenUpdate(loginData.token);
_onTokenUpdate(loginResponse.data.accessToken);
return loginData.toEntity(); // DTO → Domain Entity
return loginResponse.toEntity();
}
@override
@@ -0,0 +1,67 @@
/// 通话记录 Domain 实体
///
/// 全局共享实体,被 call / chat 等多个 Feature 共用。
/// 纯 Dart 类,零 Flutter / 零网络 / 零 DB 依赖。
class CallLog {
final String id;
final int? callerId;
final int? receiverId;
final int? chatId;
final int? duration;
final int? videoCall;
final int? createdAt;
final int? updatedAt;
final int? endedAt;
final int? status;
final int? isDeleted;
final int? deletedAt;
final int? isRead;
const CallLog({
required this.id,
this.callerId,
this.receiverId,
this.chatId,
this.duration,
this.videoCall,
this.createdAt,
this.updatedAt,
this.endedAt,
this.status,
this.isDeleted,
this.deletedAt,
this.isRead,
});
CallLog copyWith({
String? id,
int? callerId,
int? receiverId,
int? chatId,
int? duration,
int? videoCall,
int? createdAt,
int? updatedAt,
int? endedAt,
int? status,
int? isDeleted,
int? deletedAt,
int? isRead,
}) {
return CallLog(
id: id ?? this.id,
callerId: callerId ?? this.callerId,
receiverId: receiverId ?? this.receiverId,
chatId: chatId ?? this.chatId,
duration: duration ?? this.duration,
videoCall: videoCall ?? this.videoCall,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
endedAt: endedAt ?? this.endedAt,
status: status ?? this.status,
isDeleted: isDeleted ?? this.isDeleted,
deletedAt: deletedAt ?? this.deletedAt,
isRead: isRead ?? this.isRead,
);
}
}
+200
View File
@@ -0,0 +1,200 @@
/// 聊天 Domain 实体
class Chat {
final int id;
final int? typ;
final int? lastId;
final int? lastTyp;
final String? lastMsg;
final int? lastTime;
final int lastPos;
final int firstPos;
final int? msgIdx;
final String? profile;
final String? pin;
final String? icon;
final String iconGaussian;
final String? name;
final int? userId;
final int? chatId;
final int? friendId;
final int? sort;
final int? unreadNum;
final int? unreadCount;
final int? hideChatMsgIdx;
final int? readChatMsgIdx;
final int? otherReadIdx;
final String? unreadAtMsgIdx;
final int? deleteTime;
final int? addIndex;
final int flag;
final int? flagMy;
final int? autoDeleteInterval;
final int? mute;
final int? verified;
final int? createTime;
final int? startIdx;
final int? isReadMsg;
final String translateOutgoing;
final String translateIncoming;
final int incomingIdx;
final int outgoingIdx;
final int incomingSoundId;
final int outgoingSoundId;
final int notificationSoundId;
final String chatKey;
final String activeChatKey;
final int coverIdx;
final int round;
final int workspaceId;
final int localPermission;
const Chat({
required this.id,
this.typ,
this.lastId,
this.lastTyp,
this.lastMsg,
this.lastTime,
this.lastPos = 0,
this.firstPos = -1,
this.msgIdx,
this.profile,
this.pin,
this.icon,
this.iconGaussian = '',
this.name,
this.userId,
this.chatId,
this.friendId,
this.sort,
this.unreadNum,
this.unreadCount,
this.hideChatMsgIdx,
this.readChatMsgIdx,
this.otherReadIdx,
this.unreadAtMsgIdx,
this.deleteTime,
this.addIndex,
this.flag = 0,
this.flagMy,
this.autoDeleteInterval,
this.mute,
this.verified,
this.createTime,
this.startIdx,
this.isReadMsg,
this.translateOutgoing = '',
this.translateIncoming = '',
this.incomingIdx = 0,
this.outgoingIdx = 0,
this.incomingSoundId = 0,
this.outgoingSoundId = 0,
this.notificationSoundId = 0,
this.chatKey = '',
this.activeChatKey = '',
this.coverIdx = 0,
this.round = 0,
this.workspaceId = 0,
this.localPermission = 0,
});
Chat copyWith({
int? id,
int? typ,
int? lastId,
int? lastTyp,
String? lastMsg,
int? lastTime,
int? lastPos,
int? firstPos,
int? msgIdx,
String? profile,
String? pin,
String? icon,
String? iconGaussian,
String? name,
int? userId,
int? chatId,
int? friendId,
int? sort,
int? unreadNum,
int? unreadCount,
int? hideChatMsgIdx,
int? readChatMsgIdx,
int? otherReadIdx,
String? unreadAtMsgIdx,
int? deleteTime,
int? addIndex,
int? flag,
int? flagMy,
int? autoDeleteInterval,
int? mute,
int? verified,
int? createTime,
int? startIdx,
int? isReadMsg,
String? translateOutgoing,
String? translateIncoming,
int? incomingIdx,
int? outgoingIdx,
int? incomingSoundId,
int? outgoingSoundId,
int? notificationSoundId,
String? chatKey,
String? activeChatKey,
int? coverIdx,
int? round,
int? workspaceId,
int? localPermission,
}) {
return Chat(
id: id ?? this.id,
typ: typ ?? this.typ,
lastId: lastId ?? this.lastId,
lastTyp: lastTyp ?? this.lastTyp,
lastMsg: lastMsg ?? this.lastMsg,
lastTime: lastTime ?? this.lastTime,
lastPos: lastPos ?? this.lastPos,
firstPos: firstPos ?? this.firstPos,
msgIdx: msgIdx ?? this.msgIdx,
profile: profile ?? this.profile,
pin: pin ?? this.pin,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
name: name ?? this.name,
userId: userId ?? this.userId,
chatId: chatId ?? this.chatId,
friendId: friendId ?? this.friendId,
sort: sort ?? this.sort,
unreadNum: unreadNum ?? this.unreadNum,
unreadCount: unreadCount ?? this.unreadCount,
hideChatMsgIdx: hideChatMsgIdx ?? this.hideChatMsgIdx,
readChatMsgIdx: readChatMsgIdx ?? this.readChatMsgIdx,
otherReadIdx: otherReadIdx ?? this.otherReadIdx,
unreadAtMsgIdx: unreadAtMsgIdx ?? this.unreadAtMsgIdx,
deleteTime: deleteTime ?? this.deleteTime,
addIndex: addIndex ?? this.addIndex,
flag: flag ?? this.flag,
flagMy: flagMy ?? this.flagMy,
autoDeleteInterval: autoDeleteInterval ?? this.autoDeleteInterval,
mute: mute ?? this.mute,
verified: verified ?? this.verified,
createTime: createTime ?? this.createTime,
startIdx: startIdx ?? this.startIdx,
isReadMsg: isReadMsg ?? this.isReadMsg,
translateOutgoing: translateOutgoing ?? this.translateOutgoing,
translateIncoming: translateIncoming ?? this.translateIncoming,
incomingIdx: incomingIdx ?? this.incomingIdx,
outgoingIdx: outgoingIdx ?? this.outgoingIdx,
incomingSoundId: incomingSoundId ?? this.incomingSoundId,
outgoingSoundId: outgoingSoundId ?? this.outgoingSoundId,
notificationSoundId: notificationSoundId ?? this.notificationSoundId,
chatKey: chatKey ?? this.chatKey,
activeChatKey: activeChatKey ?? this.activeChatKey,
coverIdx: coverIdx ?? this.coverIdx,
round: round ?? this.round,
workspaceId: workspaceId ?? this.workspaceId,
localPermission: localPermission ?? this.localPermission,
);
}
}
@@ -0,0 +1,100 @@
/// 聊天机器人 Domain 实体
class ChatBot {
final int id;
final String? name;
final String? username;
final int? botUserId;
final String? icon;
final String? iconGaussian;
final String? description;
final String? token;
final int? flag;
final int? status;
final String? webhook;
final String? commands;
final String? banner;
final int? channelId;
final int? channelGroupId;
final int? deletedAt;
final String? internalWebhook;
final int? mode;
final String? redirectUrl;
final int? isInvitable;
final int? isAllowForward;
final String? tips;
const ChatBot({
required this.id,
this.name,
this.username,
this.botUserId,
this.icon,
this.iconGaussian,
this.description,
this.token,
this.flag,
this.status,
this.webhook,
this.commands,
this.banner,
this.channelId,
this.channelGroupId,
this.deletedAt,
this.internalWebhook,
this.mode,
this.redirectUrl,
this.isInvitable,
this.isAllowForward,
this.tips,
});
ChatBot copyWith({
int? id,
String? name,
String? username,
int? botUserId,
String? icon,
String? iconGaussian,
String? description,
String? token,
int? flag,
int? status,
String? webhook,
String? commands,
String? banner,
int? channelId,
int? channelGroupId,
int? deletedAt,
String? internalWebhook,
int? mode,
String? redirectUrl,
int? isInvitable,
int? isAllowForward,
String? tips,
}) {
return ChatBot(
id: id ?? this.id,
name: name ?? this.name,
username: username ?? this.username,
botUserId: botUserId ?? this.botUserId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
description: description ?? this.description,
token: token ?? this.token,
flag: flag ?? this.flag,
status: status ?? this.status,
webhook: webhook ?? this.webhook,
commands: commands ?? this.commands,
banner: banner ?? this.banner,
channelId: channelId ?? this.channelId,
channelGroupId: channelGroupId ?? this.channelGroupId,
deletedAt: deletedAt ?? this.deletedAt,
internalWebhook: internalWebhook ?? this.internalWebhook,
mode: mode ?? this.mode,
redirectUrl: redirectUrl ?? this.redirectUrl,
isInvitable: isInvitable ?? this.isInvitable,
isAllowForward: isAllowForward ?? this.isAllowForward,
tips: tips ?? this.tips,
);
}
}
@@ -0,0 +1,48 @@
/// 聊天分类 Domain 实体
class ChatCategory {
final int id;
final String? name;
final String? includedChatIds;
final String? excludedChatIds;
final int? seq;
final int isHide;
final int createdAt;
final int updatedAt;
final int deletedAt;
const ChatCategory({
required this.id,
this.name,
this.includedChatIds,
this.excludedChatIds,
this.seq,
this.isHide = 0,
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
});
ChatCategory copyWith({
int? id,
String? name,
String? includedChatIds,
String? excludedChatIds,
int? seq,
int? isHide,
int? createdAt,
int? updatedAt,
int? deletedAt,
}) {
return ChatCategory(
id: id ?? this.id,
name: name ?? this.name,
includedChatIds: includedChatIds ?? this.includedChatIds,
excludedChatIds: excludedChatIds ?? this.excludedChatIds,
seq: seq ?? this.seq,
isHide: isHide ?? this.isHide,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
);
}
}
@@ -0,0 +1,112 @@
/// 发现小程序 Domain 实体
class DiscoverMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final String? lastLoginAt;
final String? screen;
const DiscoverMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
DiscoverMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
String? lastLoginAt,
String? screen,
}) {
return DiscoverMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}
@@ -0,0 +1,112 @@
/// 探索小程序 Domain 实体
class ExploreMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const ExploreMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
ExploreMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
int? lastLoginAt,
String? screen,
}) {
return ExploreMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}
@@ -0,0 +1,112 @@
/// 收藏小程序 Domain 实体
class FavoriteMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const FavoriteMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
FavoriteMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
int? lastLoginAt,
String? screen,
}) {
return FavoriteMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}
@@ -0,0 +1,72 @@
/// 收藏 Domain 实体
class Favourite {
final int id;
final String parentId;
final String data;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int? source;
final int? userId;
final int? authorId;
final String typ;
final String tag;
final int isPin;
final int chatTyp;
final int isUploaded;
final String urls;
const Favourite({
required this.id,
this.parentId = '',
this.data = '',
this.createdAt = 0,
this.updatedAt = 0,
this.deletedAt = 0,
this.source,
this.userId,
this.authorId,
this.typ = '[]',
this.tag = '[]',
this.isPin = 0,
this.chatTyp = 0,
this.isUploaded = 1,
this.urls = '[]',
});
Favourite copyWith({
int? id,
String? parentId,
String? data,
int? createdAt,
int? updatedAt,
int? deletedAt,
int? source,
int? userId,
int? authorId,
String? typ,
String? tag,
int? isPin,
int? chatTyp,
int? isUploaded,
String? urls,
}) {
return Favourite(
id: id ?? this.id,
parentId: parentId ?? this.parentId,
data: data ?? this.data,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
source: source ?? this.source,
userId: userId ?? this.userId,
authorId: authorId ?? this.authorId,
typ: typ ?? this.typ,
tag: tag ?? this.tag,
isPin: isPin ?? this.isPin,
chatTyp: chatTyp ?? this.chatTyp,
isUploaded: isUploaded ?? this.isUploaded,
urls: urls ?? this.urls,
);
}
}
@@ -0,0 +1,44 @@
/// 收藏详情 Domain 实体
class FavouriteDetail {
final int? id;
final String relatedId;
final String content;
final int? typ;
final int? messageId;
final int? sendId;
final int? chatId;
final int? sendTime;
const FavouriteDetail({
this.id,
this.relatedId = '',
this.content = '',
this.typ,
this.messageId,
this.sendId,
this.chatId,
this.sendTime,
});
FavouriteDetail copyWith({
int? id,
String? relatedId,
String? content,
int? typ,
int? messageId,
int? sendId,
int? chatId,
int? sendTime,
}) {
return FavouriteDetail(
id: id ?? this.id,
relatedId: relatedId ?? this.relatedId,
content: content ?? this.content,
typ: typ ?? this.typ,
messageId: messageId ?? this.messageId,
sendId: sendId ?? this.sendId,
chatId: chatId ?? this.chatId,
sendTime: sendTime ?? this.sendTime,
);
}
}
+124
View File
@@ -0,0 +1,124 @@
/// 群组 Domain 实体
class Group {
final int id;
final int? userJoinDate;
final String? name;
final String? profile;
final String? icon;
final String iconGaussian;
final int? permission;
final int? admin;
final String? members;
final int? owner;
final String? admins;
final int? visible;
final int? speakInterval;
final int? groupType;
final int? roomType;
final int? maxNumber;
final int? channelId;
final int? channelGroupId;
final int? createTime;
final int? updateTime;
final int? addIndex;
final int? maxMember;
final int? expireTime;
final int workspaceId;
final int mode;
final int redpacketPlay;
final String? topic;
final String? rp;
const Group({
required this.id,
this.userJoinDate,
this.name,
this.profile,
this.icon,
this.iconGaussian = '',
this.permission,
this.admin,
this.members,
this.owner,
this.admins,
this.visible,
this.speakInterval,
this.groupType,
this.roomType,
this.maxNumber,
this.channelId,
this.channelGroupId,
this.createTime,
this.updateTime,
this.addIndex,
this.maxMember,
this.expireTime,
this.workspaceId = 0,
this.mode = 0,
this.redpacketPlay = 0,
this.topic,
this.rp,
});
Group copyWith({
int? id,
int? userJoinDate,
String? name,
String? profile,
String? icon,
String? iconGaussian,
int? permission,
int? admin,
String? members,
int? owner,
String? admins,
int? visible,
int? speakInterval,
int? groupType,
int? roomType,
int? maxNumber,
int? channelId,
int? channelGroupId,
int? createTime,
int? updateTime,
int? addIndex,
int? maxMember,
int? expireTime,
int? workspaceId,
int? mode,
int? redpacketPlay,
String? topic,
String? rp,
}) {
return Group(
id: id ?? this.id,
userJoinDate: userJoinDate ?? this.userJoinDate,
name: name ?? this.name,
profile: profile ?? this.profile,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
permission: permission ?? this.permission,
admin: admin ?? this.admin,
members: members ?? this.members,
owner: owner ?? this.owner,
admins: admins ?? this.admins,
visible: visible ?? this.visible,
speakInterval: speakInterval ?? this.speakInterval,
groupType: groupType ?? this.groupType,
roomType: roomType ?? this.roomType,
maxNumber: maxNumber ?? this.maxNumber,
channelId: channelId ?? this.channelId,
channelGroupId: channelGroupId ?? this.channelGroupId,
createTime: createTime ?? this.createTime,
updateTime: updateTime ?? this.updateTime,
addIndex: addIndex ?? this.addIndex,
maxMember: maxMember ?? this.maxMember,
expireTime: expireTime ?? this.expireTime,
workspaceId: workspaceId ?? this.workspaceId,
mode: mode ?? this.mode,
redpacketPlay: redpacketPlay ?? this.redpacketPlay,
topic: topic ?? this.topic,
rp: rp ?? this.rp,
);
}
}
@@ -0,0 +1,76 @@
/// 消息 Domain 实体
class Message {
final int id;
final int? messageId;
final int? chatId;
final int? chatIdx;
final int? sendId;
final String? content;
final int? typ;
final int? sendTime;
final int? expireTime;
final int? createTime;
final String? atUsers;
final String emojis;
final int editTime;
final int refTyp;
final int flag;
final String cmid;
const Message({
required this.id,
this.messageId,
this.chatId,
this.chatIdx,
this.sendId,
this.content,
this.typ,
this.sendTime,
this.expireTime,
this.createTime,
this.atUsers,
this.emojis = '[]',
this.editTime = 0,
this.refTyp = 0,
this.flag = 0,
this.cmid = '',
});
Message copyWith({
int? id,
int? messageId,
int? chatId,
int? chatIdx,
int? sendId,
String? content,
int? typ,
int? sendTime,
int? expireTime,
int? createTime,
String? atUsers,
String? emojis,
int? editTime,
int? refTyp,
int? flag,
String? cmid,
}) {
return Message(
id: id ?? this.id,
messageId: messageId ?? this.messageId,
chatId: chatId ?? this.chatId,
chatIdx: chatIdx ?? this.chatIdx,
sendId: sendId ?? this.sendId,
content: content ?? this.content,
typ: typ ?? this.typ,
sendTime: sendTime ?? this.sendTime,
expireTime: expireTime ?? this.expireTime,
createTime: createTime ?? this.createTime,
atUsers: atUsers ?? this.atUsers,
emojis: emojis ?? this.emojis,
editTime: editTime ?? this.editTime,
refTyp: refTyp ?? this.refTyp,
flag: flag ?? this.flag,
cmid: cmid ?? this.cmid,
);
}
}
@@ -0,0 +1,36 @@
/// 待处理好友请求历史 Domain 实体
class PendingFriendRequestHistory {
final int id;
final int uid;
final int requestTime;
final String? remarks;
final String? source;
final int? rs;
const PendingFriendRequestHistory({
required this.id,
required this.uid,
required this.requestTime,
this.remarks,
this.source,
this.rs,
});
PendingFriendRequestHistory copyWith({
int? id,
int? uid,
int? requestTime,
String? remarks,
String? source,
int? rs,
}) {
return PendingFriendRequestHistory(
id: id ?? this.id,
uid: uid ?? this.uid,
requestTime: requestTime ?? this.requestTime,
remarks: remarks ?? this.remarks,
source: source ?? this.source,
rs: rs ?? this.rs,
);
}
}
@@ -0,0 +1,112 @@
/// 最近小程序 Domain 实体
class RecentMiniApp {
final String id;
final String? name;
final String? openuid;
final String? devId;
final String? icon;
final String? iconGaussian;
final String? downloadUrl;
final String? description;
final int? version;
final int? typ;
final int? flag;
final int? reviewStatus;
final int? favoriteAt;
final int? isActive;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final double? score;
final String? channels;
final String? devName;
final String? pictureGaussian;
final String? picture;
final int? commentNum;
final int? lastLoginAt;
final String? screen;
const RecentMiniApp({
required this.id,
this.name,
this.openuid,
this.devId,
this.icon,
this.iconGaussian,
this.downloadUrl,
this.description,
this.version,
this.typ,
this.flag,
this.reviewStatus,
this.favoriteAt,
this.isActive,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.score,
this.channels,
this.devName,
this.pictureGaussian,
this.picture,
this.commentNum,
this.lastLoginAt,
this.screen,
});
RecentMiniApp copyWith({
String? id,
String? name,
String? openuid,
String? devId,
String? icon,
String? iconGaussian,
String? downloadUrl,
String? description,
int? version,
int? typ,
int? flag,
int? reviewStatus,
int? favoriteAt,
int? isActive,
int? createdAt,
int? updatedAt,
int? deletedAt,
double? score,
String? channels,
String? devName,
String? pictureGaussian,
String? picture,
int? commentNum,
int? lastLoginAt,
String? screen,
}) {
return RecentMiniApp(
id: id ?? this.id,
name: name ?? this.name,
openuid: openuid ?? this.openuid,
devId: devId ?? this.devId,
icon: icon ?? this.icon,
iconGaussian: iconGaussian ?? this.iconGaussian,
downloadUrl: downloadUrl ?? this.downloadUrl,
description: description ?? this.description,
version: version ?? this.version,
typ: typ ?? this.typ,
flag: flag ?? this.flag,
reviewStatus: reviewStatus ?? this.reviewStatus,
favoriteAt: favoriteAt ?? this.favoriteAt,
isActive: isActive ?? this.isActive,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
score: score ?? this.score,
channels: channels ?? this.channels,
devName: devName ?? this.devName,
pictureGaussian: pictureGaussian ?? this.pictureGaussian,
picture: picture ?? this.picture,
commentNum: commentNum ?? this.commentNum,
lastLoginAt: lastLoginAt ?? this.lastLoginAt,
screen: screen ?? this.screen,
);
}
}
@@ -0,0 +1,60 @@
/// 重试 Domain 实体
class Retry {
final int? id;
final int? uid;
final String apiType;
final String endPoint;
final String requestData;
final int? synced;
final String callbackFun;
final int? expired;
final int? replace;
final int? expireTime;
final int? createTime;
final int? addIndex;
const Retry({
this.id,
this.uid,
this.apiType = '',
this.endPoint = '',
this.requestData = '',
this.synced,
this.callbackFun = '',
this.expired,
this.replace,
this.expireTime,
this.createTime,
this.addIndex,
});
Retry copyWith({
int? id,
int? uid,
String? apiType,
String? endPoint,
String? requestData,
int? synced,
String? callbackFun,
int? expired,
int? replace,
int? expireTime,
int? createTime,
int? addIndex,
}) {
return Retry(
id: id ?? this.id,
uid: uid ?? this.uid,
apiType: apiType ?? this.apiType,
endPoint: endPoint ?? this.endPoint,
requestData: requestData ?? this.requestData,
synced: synced ?? this.synced,
callbackFun: callbackFun ?? this.callbackFun,
expired: expired ?? this.expired,
replace: replace ?? this.replace,
expireTime: expireTime ?? this.expireTime,
createTime: createTime ?? this.createTime,
addIndex: addIndex ?? this.addIndex,
);
}
}
@@ -0,0 +1,48 @@
/// 音效 Domain 实体
class Sound {
final int id;
final String filePath;
final int typ;
final String name;
final int createdAt;
final int updatedAt;
final int deletedAt;
final int channelGroupId;
final int isDefault;
const Sound({
required this.id,
this.filePath = '',
required this.typ,
this.name = '',
required this.createdAt,
required this.updatedAt,
this.deletedAt = 0,
required this.channelGroupId,
required this.isDefault,
});
Sound copyWith({
int? id,
String? filePath,
int? typ,
String? name,
int? createdAt,
int? updatedAt,
int? deletedAt,
int? channelGroupId,
int? isDefault,
}) {
return Sound(
id: id ?? this.id,
filePath: filePath ?? this.filePath,
typ: typ ?? this.typ,
name: name ?? this.name,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
channelGroupId: channelGroupId ?? this.channelGroupId,
isDefault: isDefault ?? this.isDefault,
);
}
}
+40
View File
@@ -0,0 +1,40 @@
/// 标签 Domain 实体
class Tag {
final int? id;
final int? uid;
final String name;
final int? type;
final int? createdAt;
final int? updatedAt;
final int? addIndex;
const Tag({
this.id,
this.uid,
this.name = '',
this.type,
this.createdAt,
this.updatedAt,
this.addIndex,
});
Tag copyWith({
int? id,
int? uid,
String? name,
int? type,
int? createdAt,
int? updatedAt,
int? addIndex,
}) {
return Tag(
id: id ?? this.id,
uid: uid ?? this.uid,
name: name ?? this.name,
type: type ?? this.type,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
addIndex: addIndex ?? this.addIndex,
);
}
}
+72 -6
View File
@@ -14,15 +14,81 @@
/// → View 渲染
/// ```
class User {
final String id;
final String email;
final int uid;
final String? uuid;
final int? lastOnline;
final String? profilePic;
final String? profilePicGaussian;
final String? nickname;
final String? avatar;
final String? contact;
final String? countryCode;
final String? email;
final String? recoveryEmail;
final String? username;
final String? bio;
final int? relationship;
final String? userAlias;
final int? channelId;
final int? channelGroupId;
final String? hint;
const User({
required this.id,
required this.email,
required this.uid,
this.uuid,
this.lastOnline,
this.profilePic,
this.profilePicGaussian,
this.nickname,
this.avatar,
this.contact,
this.countryCode,
this.email,
this.recoveryEmail,
this.username,
this.bio,
this.relationship,
this.userAlias,
this.channelId,
this.channelGroupId,
this.hint,
});
User copyWith({
int? uid,
String? uuid,
int? lastOnline,
String? profilePic,
String? profilePicGaussian,
String? nickname,
String? contact,
String? countryCode,
String? email,
String? recoveryEmail,
String? username,
String? bio,
int? relationship,
String? userAlias,
int? channelId,
int? channelGroupId,
String? hint,
}) {
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,
contact: contact ?? this.contact,
countryCode: countryCode ?? this.countryCode,
email: email ?? this.email,
recoveryEmail: recoveryEmail ?? this.recoveryEmail,
username: username ?? this.username,
bio: bio ?? this.bio,
relationship: relationship ?? this.relationship,
userAlias: userAlias ?? this.userAlias,
channelId: channelId ?? this.channelId,
channelGroupId: channelGroupId ?? this.channelGroupId,
hint: hint ?? this.hint,
);
}
}
@@ -0,0 +1,24 @@
/// 用户请求历史 Domain 实体
class UserRequestHistory {
final int id;
final int? status;
final int? createdAt;
const UserRequestHistory({
required this.id,
this.status,
this.createdAt,
});
UserRequestHistory copyWith({
int? id,
int? status,
int? createdAt,
}) {
return UserRequestHistory(
id: id ?? this.id,
status: status ?? this.status,
createdAt: createdAt ?? this.createdAt,
);
}
}
@@ -0,0 +1,64 @@
/// 工作空间 Domain 实体
class Workspace {
final int id;
final String? name;
final int? ownerId;
final String? description;
final String? logo;
final int? grade;
final int? cap;
final String? currency;
final int? status;
final int? createdAt;
final int? updatedAt;
final int? deletedAt;
final int? channelGroupId;
const Workspace({
required this.id,
this.name,
this.ownerId,
this.description,
this.logo,
this.grade,
this.cap,
this.currency,
this.status,
this.createdAt,
this.updatedAt,
this.deletedAt,
this.channelGroupId,
});
Workspace copyWith({
int? id,
String? name,
int? ownerId,
String? description,
String? logo,
int? grade,
int? cap,
String? currency,
int? status,
int? createdAt,
int? updatedAt,
int? deletedAt,
int? channelGroupId,
}) {
return Workspace(
id: id ?? this.id,
name: name ?? this.name,
ownerId: ownerId ?? this.ownerId,
description: description ?? this.description,
logo: logo ?? this.logo,
grade: grade ?? this.grade,
cap: cap ?? this.cap,
currency: currency ?? this.currency,
status: status ?? this.status,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
channelGroupId: channelGroupId ?? this.channelGroupId,
);
}
}
@@ -1,7 +1,6 @@
import 'dart:math';
import 'package:drift/drift.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:im_app/app/di/db_provider.dart';
import 'package:im_app/data/local/drift/app_database.dart';
@@ -87,12 +86,12 @@ class ChatDbTestViewModel extends _$ChatDbTestViewModel {
final chunk = List.generate(
chunkSize.clamp(0, count - i),
(j) => UsersCompanion.insert(
uid: Value(i + j),
uid: i + j,
nickname: Value('User ${i + j}'),
),
);
await db.batchInsertOrReplace<User>(chunk);
await db.batchInsertOrReplace<DriftUser>(chunk);
completed += chunk.length;
// 让出主线程
@@ -1,4 +1,8 @@
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:im_app/data/models/user_dto.dart';
import 'package:im_app/data/remote/login_request.dart';
import 'package:networks_sdk/networks_sdk.dart';
import 'package:im_app/app/di/db_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
@@ -56,10 +60,23 @@ class LoginViewModel extends _$LoginViewModel {
/// 正式 [login] 成功后同样需要调用 [AuthNotifier.login] 更新守卫状态。
Future<void> demoLogin() async {
final storageApi = ref.read(storageSdkProvider);
///TODO: StorageSDKLifeCycle 需要只在主项目暴露
final storageLifeCycle = storageApi as StorageSdkLifecycle;
ref.read(authNotifierProvider).login();
await storageLifeCycle.openDatabase(1234567);
final provider = ref.read(authNotifierProvider);
// Read mock response from assets
final String raw = await rootBundle.loadString('assets/loginData.json');
final Map<String, dynamic> json = jsonDecode(raw);
// Parse into LoginData (nested under 'data' key)
final loginResponse = LoginResponse.fromJson(json);
final user = loginResponse.data.toEntity();
provider.login();
// Open database for the user
await storageLifeCycle.openDatabase(user.uid);
///TODO: User 和 DTO和数据库之间转换
final userCompanion = UserDto.fromEntity(user).toCompanion();
storageApi.insert(userCompanion);
}
/// 执行登录
+2
View File
@@ -62,3 +62,5 @@ dev_dependencies:
flutter:
uses-material-design: true
assets:
- assets/
@@ -18,19 +18,19 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<void> insertOrReplace<T extends Table, D>(
TableInfo<T, D> table,
Insertable<D> companion,
) async {
TableInfo<T, D> table,
Insertable<D> companion,
) async {
final db = _db;
if (db == null) return;
await db.into(table).insertOnConflictUpdate(companion);
await db.into(table).insert(companion, mode: InsertMode.insertOrReplace);
}
@override
Future<void> insert<T extends Table, D>(
TableInfo<T, D> table,
Insertable<D> companion,
) async {
TableInfo<T, D> table,
Insertable<D> companion,
) async {
final db = _db;
if (db == null) return;
await db.into(table).insert(companion, mode: InsertMode.insertOrIgnore);
@@ -38,13 +38,17 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<void> batchInsertOrReplace<T extends Table, D>(
TableInfo<T, D> table,
List<Insertable<D>> companions,
) async {
TableInfo<T, D> table,
List<Insertable<D>> companions,
) async {
final db = _db;
if (db == null) return;
await db.batch(
(batch) => batch.insertAllOnConflictUpdate(table, companions),
(batch) => batch.insertAll(
table,
companions,
mode: InsertMode.insertOrReplace,
),
);
}
@@ -52,10 +56,10 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<void> updateWhere<T extends Table, D>(
TableInfo<T, D> table,
Insertable<D> companion,
Expression<bool> Function(T) filter,
) async {
TableInfo<T, D> table,
Insertable<D> companion,
Expression<bool> Function(T) filter,
) async {
final db = _db;
if (db == null) return;
await (db.update(table)..where(filter)).write(companion);
@@ -65,9 +69,9 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<void> deleteWhere<T extends Table, D>(
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) async {
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) async {
final db = _db;
if (db == null) return;
await (db.delete(table)..where(filter)).go();
@@ -91,9 +95,9 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<List<D>> selectWhere<T extends Table, D>(
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) async {
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) async {
final db = _db;
if (db == null) return [];
return (db.select(table)..where(filter)).get();
@@ -101,9 +105,9 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<D?> selectFirst<T extends Table, D>(
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) async {
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) async {
final db = _db;
if (db == null) return null;
return (db.select(table)..where(filter)..limit(1)).getSingleOrNull();
@@ -120,9 +124,9 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Stream<List<D>> watchWhere<T extends Table, D>(
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) {
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) {
final db = _db;
if (db == null) return const Stream.empty();
return (db.select(table)..where(filter)).watch();
@@ -130,9 +134,9 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Stream<D?> watchFirst<T extends Table, D>(
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) {
TableInfo<T, D> table,
Expression<bool> Function(T) filter,
) {
final db = _db;
if (db == null) return const Stream.empty();
return (db.select(table)..where(filter)..limit(1)).watchSingleOrNull();
@@ -142,24 +146,24 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<List<QueryRow>> rawQuery(
String sql, [
List<Object?> args = const [],
]) async {
String sql, [
List<Object?> args = const [],
]) async {
final db = _db;
if (db == null) return [];
return db
.customSelect(
sql,
variables: args.map((e) => Variable(e)).toList(),
)
sql,
variables: args.map((e) => Variable(e)).toList(),
)
.get();
}
@override
Future<void> rawExecute(
String sql, [
List<Object?> args = const [],
]) async {
String sql, [
List<Object?> args = const [],
]) async {
final db = _db;
if (db == null) return;
await db.customStatement(sql, args);
@@ -169,9 +173,9 @@ class DatabaseRepositoryImpl implements DatabaseRepository {
@override
Future<int> count<T extends Table, D>(
TableInfo<T, D> table, {
Expression<bool> Function(T)? filter,
}) async {
TableInfo<T, D> table, {
Expression<bool> Function(T)? filter,
}) async {
final db = _db;
if (db == null) return 0;
final countExpr = table.$columns.first.count();