Merge remote-tracking branch 'origin/dev' into cody/netwrok_SDK

# Conflicts:
#	apps/im_app/lib/features/chat/presentation/chat_db_test_view_model.dart
#	apps/im_app/lib/features/login/presentation/login_view_model.dart

修复逻辑漏洞,性能优化
This commit is contained in:
Cody
2026-03-08 20:47:28 +08:00
88 changed files with 5695 additions and 593 deletions

View File

@@ -1,27 +1,82 @@
import 'package:drift/drift.dart';
import 'package:im_app/data/local/drift/tables/favourites.dart';
import 'package:im_app/data/local/drift/tables/sounds.dart';
import 'package:im_app/data/local/drift/tables/tags.dart';
import 'package:im_app/data/local/drift/tables/pending_friend_request_histories.dart';
import 'package:im_app/data/local/drift/tables/message.dart';
import 'package:im_app/data/local/drift/tables/recent_mini_apps.dart';
import 'package:im_app/data/local/drift/tables/retries.dart';
import 'package:im_app/data/local/drift/tables/groups.dart';
import 'package:im_app/data/local/drift/tables/favorite_mini_apps.dart';
import 'package:im_app/data/local/drift/tables/discover_mini_apps.dart';
import 'package:im_app/data/local/drift/tables/chat_categories.dart';
import 'package:im_app/data/local/drift/tables/chat_bots.dart';
import 'package:im_app/data/local/drift/tables/favourite_details.dart';
import 'package:im_app/data/local/drift/tables/user_request_histories.dart';
import 'package:im_app/data/local/drift/tables/workspaces.dart';
import 'package:im_app/data/local/drift/tables/users.dart';
import 'package:im_app/data/local/drift/tables/test_tables.dart';
import 'package:im_app/data/local/drift/tables/explore_mini_apps.dart';
import 'package:im_app/data/local/drift/tables/call_logs.dart';
import 'package:im_app/data/local/drift/tables/chats.dart';
part 'app_database.g.dart';
@DriftDatabase(tables: [Users,TestTables]) //update mapping here
@DriftDatabase(
tables: [
Favourites,
Sounds,
Tags,
PendingFriendRequestHistories,
Messages,
RecentMiniApps,
Retries,
Groups,
FavoriteMiniApps,
DiscoverMiniApps,
ChatCategories,
ChatBots,
FavouriteDetails,
UserRequestHistories,
Workspaces,
Users,
ExploreMiniApps,
CallLogs,
Chats,
],
) //update mapping here
class AppDatabase extends _$AppDatabase {
static Map<Type, TableInfo> getTableRegistry(GeneratedDatabase database) {
if (database is! AppDatabase) {
return {
};
return {};
}
return {
User: database.users,
TestTable: database.testTables,
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,
};
}
AppDatabase(super.e);
//升级数据库用此版本号
@override
int get schemaVersion => 1;
int get schemaVersion => 2;
@override
MigrationStrategy get migration {
@@ -30,9 +85,20 @@ class AppDatabase extends _$AppDatabase {
await m.createAll();
},
onUpgrade: (m, from, to) async {
// 自动检测并添加缺失列
// Create any new tables that don't exist yet
for (final table in allTables) {
//取原来的字段
final existingTables = await m.database
.customSelect(
"SELECT name FROM sqlite_master WHERE type='table' AND name='${table.actualTableName}'",
)
.get();
if (existingTables.isEmpty) {
await m.createTable(table);
continue;
}
// Auto-detect and add missing columns
final existingColumns = await m.database
.customSelect('PRAGMA table_info(${table.actualTableName})')
.get();
@@ -42,7 +108,6 @@ class AppDatabase extends _$AppDatabase {
for (final column in table.$columns) {
if (!existingNames.contains(column.name)) {
//字段缺失,添加。
await m.addColumn(table, column);
}
}
@@ -50,6 +115,4 @@ class AppDatabase extends _$AppDatabase {
},
);
}
}

View File

@@ -0,0 +1,24 @@
import 'package:drift/drift.dart';
@DataClassName('DriftCallLog')
class CallLogs extends Table {
TextColumn get id => text()();
IntColumn get callerId => integer().nullable()();
IntColumn get receiverId => integer().nullable()();
IntColumn get chatId => integer().nullable()();
IntColumn get duration => integer().nullable()();
IntColumn get videoCall => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get endedAt => integer().nullable()();
IntColumn get status => integer().nullable()();
IntColumn get isDeleted => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
IntColumn get isRead => integer().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'call_log';
}

View File

@@ -0,0 +1,33 @@
import 'package:drift/drift.dart';
@DataClassName('DriftChatBot')
class ChatBots extends Table {
IntColumn get id => integer()();
TextColumn get name => text().nullable()();
TextColumn get username => text().nullable()();
IntColumn get botUserId => integer().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().nullable()();
TextColumn get description => text().nullable()();
TextColumn get token => text().nullable()();
IntColumn get flag => integer().nullable()();
IntColumn get status => integer().nullable()();
TextColumn get webhook => text().withDefault(const Constant(''))();
TextColumn get commands => text().withDefault(const Constant('[]'))();
TextColumn get banner => text().nullable()();
IntColumn get channelId => integer().nullable()();
IntColumn get channelGroupId => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
TextColumn get internalWebhook => text().nullable()();
IntColumn get mode => integer().nullable()();
TextColumn get redirectUrl => text().nullable()();
IntColumn get isInvitable => integer().nullable()();
IntColumn get isAllowForward => integer().nullable()();
TextColumn get tips => text().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'chat_bot';
}

View File

@@ -0,0 +1,20 @@
import 'package:drift/drift.dart';
@DataClassName('DriftChatCategory')
class ChatCategories extends Table {
IntColumn get id => integer()();
TextColumn get name => text().nullable()();
TextColumn get includedChatIds => text().nullable()();
TextColumn get excludedChatIds => text().nullable()();
IntColumn get seq => integer().nullable()();
IntColumn get isHide => integer().withDefault(const Constant(0))();
IntColumn get createdAt => integer().withDefault(const Constant(0))();
IntColumn get updatedAt => integer().withDefault(const Constant(0))();
IntColumn get deletedAt => integer().withDefault(const Constant(0))();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'chat_category';
}

View File

@@ -0,0 +1,59 @@
import 'package:drift/drift.dart';
@DataClassName('DriftChat')
class Chats extends Table {
IntColumn get id => integer()();
IntColumn get typ => integer().nullable()();
IntColumn get lastId => integer().nullable()();
IntColumn get lastTyp => integer().nullable()();
TextColumn get lastMsg => text().nullable()();
IntColumn get lastTime => integer().nullable()();
IntColumn get lastPos => integer().withDefault(const Constant(0))();
IntColumn get firstPos => integer().withDefault(const Constant(-1))();
IntColumn get msgIdx => integer().nullable()();
TextColumn get profile => text().nullable()();
TextColumn get pin => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().withDefault(const Constant(''))();
TextColumn get name => text().nullable()();
IntColumn get userId => integer().nullable()();
IntColumn get chatId => integer().nullable()();
IntColumn get friendId => integer().nullable()();
IntColumn get sort => integer().nullable()();
IntColumn get unreadNum => integer().nullable()();
IntColumn get unreadCount => integer().nullable()();
IntColumn get hideChatMsgIdx => integer().nullable()();
IntColumn get readChatMsgIdx => integer().nullable()();
IntColumn get otherReadIdx => integer().nullable()();
TextColumn get unreadAtMsgIdx => text().nullable()();
IntColumn get deleteTime => integer().nullable()();
IntColumn get addIndex => integer().nullable()();
IntColumn get flag => integer().withDefault(const Constant(0))();
IntColumn get flagMy => integer().nullable()();
IntColumn get autoDeleteInterval => integer().nullable()();
IntColumn get mute => integer().nullable()();
IntColumn get verified => integer().nullable()();
IntColumn get createTime => integer().nullable()();
IntColumn get startIdx => integer().nullable()();
IntColumn get isReadMsg => integer().nullable()();
TextColumn get translateOutgoing => text().withDefault(const Constant(''))();
TextColumn get translateIncoming => text().withDefault(const Constant(''))();
IntColumn get incomingIdx => integer().withDefault(const Constant(0))();
IntColumn get outgoingIdx => integer().withDefault(const Constant(0))();
IntColumn get incomingSoundId => integer().withDefault(const Constant(0))();
IntColumn get outgoingSoundId => integer().withDefault(const Constant(0))();
IntColumn get notificationSoundId =>
integer().withDefault(const Constant(0))();
TextColumn get chatKey => text().withDefault(const Constant(''))();
TextColumn get activeChatKey => text().withDefault(const Constant(''))();
IntColumn get coverIdx => integer().withDefault(const Constant(0))();
IntColumn get round => integer().withDefault(const Constant(0))();
IntColumn get workspaceId => integer().withDefault(const Constant(0))();
IntColumn get localPermission => integer().withDefault(const Constant(0))();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'chat';
}

View File

@@ -0,0 +1,36 @@
import 'package:drift/drift.dart';
@DataClassName('DriftDiscoverMiniApp')
class DiscoverMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
TextColumn get openuid => text().nullable()();
TextColumn get devId => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().nullable()();
TextColumn get downloadUrl => text().nullable()();
TextColumn get description => text().nullable()();
IntColumn get version => integer().nullable()();
IntColumn get typ => integer().nullable()();
IntColumn get flag => integer().nullable()();
IntColumn get reviewStatus => integer().nullable()();
IntColumn get favoriteAt => integer().nullable()();
IntColumn get isActive => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
RealColumn get score => real().nullable()();
TextColumn get channels => text().nullable()();
TextColumn get devName => text().nullable()();
TextColumn get pictureGaussian => text().nullable()();
TextColumn get picture => text().nullable()();
IntColumn get commentNum => integer().nullable()();
TextColumn get lastLoginAt => text().nullable()();
TextColumn get screen => text().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'discover_mini_app';
}

View File

@@ -0,0 +1,36 @@
import 'package:drift/drift.dart';
@DataClassName('DriftExploreMiniApp')
class ExploreMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
TextColumn get openuid => text().nullable()();
TextColumn get devId => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().nullable()();
TextColumn get downloadUrl => text().nullable()();
TextColumn get description => text().nullable()();
IntColumn get version => integer().nullable()();
IntColumn get typ => integer().nullable()();
IntColumn get flag => integer().nullable()();
IntColumn get reviewStatus => integer().nullable()();
IntColumn get favoriteAt => integer().nullable()();
IntColumn get isActive => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
RealColumn get score => real().nullable()();
TextColumn get channels => text().nullable()();
TextColumn get devName => text().nullable()();
TextColumn get pictureGaussian => text().nullable()();
TextColumn get picture => text().nullable()();
IntColumn get commentNum => integer().nullable()();
IntColumn get lastLoginAt => integer().nullable()();
TextColumn get screen => text().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'explore_mini_app';
}

View File

@@ -0,0 +1,36 @@
import 'package:drift/drift.dart';
@DataClassName('DriftFavoriteMiniApp')
class FavoriteMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
TextColumn get openuid => text().nullable()();
TextColumn get devId => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().nullable()();
TextColumn get downloadUrl => text().nullable()();
TextColumn get description => text().nullable()();
IntColumn get version => integer().nullable()();
IntColumn get typ => integer().nullable()();
IntColumn get flag => integer().nullable()();
IntColumn get reviewStatus => integer().nullable()();
IntColumn get favoriteAt => integer().nullable()();
IntColumn get isActive => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
RealColumn get score => real().nullable()();
TextColumn get channels => text().nullable()();
TextColumn get devName => text().nullable()();
TextColumn get pictureGaussian => text().nullable()();
TextColumn get picture => text().nullable()();
IntColumn get commentNum => integer().nullable()();
IntColumn get lastLoginAt => integer().nullable()();
TextColumn get screen => text().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'favorite_mini_app';
}

View File

@@ -0,0 +1,16 @@
import 'package:drift/drift.dart';
@DataClassName('DriftFavouriteDetail')
class FavouriteDetails extends Table {
IntColumn get id => integer().autoIncrement()();
TextColumn get relatedId => text().withDefault(const Constant(''))();
TextColumn get content => text().withDefault(const Constant(''))();
IntColumn get typ => integer().nullable()();
IntColumn get messageId => integer().nullable()();
IntColumn get sendId => integer().nullable()();
IntColumn get chatId => integer().nullable()();
IntColumn get sendTime => integer().nullable()();
@override
String get tableName => 'favourite_detail';
}

View File

@@ -0,0 +1,26 @@
import 'package:drift/drift.dart';
@DataClassName('DriftFavourite')
class Favourites extends Table {
IntColumn get id => integer()();
TextColumn get parentId => text().withDefault(const Constant(''))();
TextColumn get data => text().withDefault(const Constant(''))();
IntColumn get createdAt => integer().withDefault(const Constant(0))();
IntColumn get updatedAt => integer().withDefault(const Constant(0))();
IntColumn get deletedAt => integer().withDefault(const Constant(0))();
IntColumn get source => integer().nullable()();
IntColumn get userId => integer().nullable()();
IntColumn get authorId => integer().nullable()();
TextColumn get typ => text().withDefault(const Constant('[]'))();
TextColumn get tag => text().withDefault(const Constant('[]'))();
IntColumn get isPin => integer().withDefault(const Constant(0))();
IntColumn get chatTyp => integer().withDefault(const Constant(0))();
IntColumn get isUploaded => integer().withDefault(const Constant(1))();
TextColumn get urls => text().withDefault(const Constant('[]'))();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'favourite';
}

View File

@@ -0,0 +1,39 @@
import 'package:drift/drift.dart';
@DataClassName('DriftGroup')
class Groups extends Table {
IntColumn get id => integer()();
IntColumn get userJoinDate => integer().nullable()();
TextColumn get name => text().nullable()();
TextColumn get profile => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().withDefault(const Constant(''))();
IntColumn get permission => integer().nullable()();
IntColumn get admin => integer().nullable()();
TextColumn get members => text().nullable()();
IntColumn get owner => integer().nullable()();
TextColumn get admins => text().nullable()();
IntColumn get visible => integer().nullable()();
IntColumn get speakInterval => integer().nullable()();
IntColumn get groupType => integer().nullable()();
IntColumn get roomType => integer().nullable()();
IntColumn get maxNumber => integer().nullable()();
IntColumn get channelId => integer().nullable()();
IntColumn get channelGroupId => integer().nullable()();
IntColumn get createTime => integer().nullable()();
IntColumn get updateTime => integer().nullable()();
IntColumn get addIndex => integer().nullable()();
IntColumn get maxMember => integer().nullable()();
IntColumn get expireTime => integer().nullable()();
IntColumn get workspaceId => integer().withDefault(const Constant(0))();
IntColumn get mode => integer().withDefault(const Constant(0))();
IntColumn get redpacketPlay => integer().withDefault(const Constant(0))();
TextColumn get topic => text().nullable()();
TextColumn get rp => text().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'chat_group';
}

View File

@@ -0,0 +1,27 @@
import 'package:drift/drift.dart';
@DataClassName('DriftMessage')
class Messages extends Table {
IntColumn get id => integer()();
IntColumn get messageId => integer().nullable()();
IntColumn get chatId => integer().nullable()();
IntColumn get chatIdx => integer().nullable()();
IntColumn get sendId => integer().nullable()();
TextColumn get content => text().nullable()();
IntColumn get typ => integer().nullable()();
IntColumn get sendTime => integer().nullable()();
IntColumn get expireTime => integer().nullable()();
IntColumn get createTime => integer().nullable()();
TextColumn get atUsers => text().nullable()();
TextColumn get emojis => text().withDefault(const Constant('[]'))();
IntColumn get editTime => integer().withDefault(const Constant(0))();
IntColumn get refTyp => integer().withDefault(const Constant(0))();
IntColumn get flag => integer().withDefault(const Constant(0))();
TextColumn get cmid => text().withDefault(const Constant(''))();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'message';
}

View File

@@ -0,0 +1,17 @@
import 'package:drift/drift.dart';
@DataClassName('DriftPendingFriendRequestHistory')
class PendingFriendRequestHistories extends Table {
IntColumn get id => integer()();
IntColumn get uid => integer()();
IntColumn get requestTime => integer()();
TextColumn get remarks => text().nullable()();
TextColumn get source => text().nullable()();
IntColumn get rs => integer().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'pending_friend_request_histories';
}

View File

@@ -0,0 +1,36 @@
import 'package:drift/drift.dart';
@DataClassName('DriftRecentMiniApp')
class RecentMiniApps extends Table {
TextColumn get id => text()();
TextColumn get name => text().nullable()();
TextColumn get openuid => text().nullable()();
TextColumn get devId => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get iconGaussian => text().nullable()();
TextColumn get downloadUrl => text().nullable()();
TextColumn get description => text().nullable()();
IntColumn get version => integer().nullable()();
IntColumn get typ => integer().nullable()();
IntColumn get flag => integer().nullable()();
IntColumn get reviewStatus => integer().nullable()();
IntColumn get favoriteAt => integer().nullable()();
IntColumn get isActive => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
RealColumn get score => real().nullable()();
TextColumn get channels => text().nullable()();
TextColumn get devName => text().nullable()();
TextColumn get pictureGaussian => text().nullable()();
TextColumn get picture => text().nullable()();
IntColumn get commentNum => integer().nullable()();
IntColumn get lastLoginAt => integer().nullable()();
TextColumn get screen => text().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'recent_mini_app';
}

View File

@@ -0,0 +1,20 @@
import 'package:drift/drift.dart';
@DataClassName('DriftRetry')
class Retries extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()();
TextColumn get apiType => text().withDefault(const Constant(''))();
TextColumn get endPoint => text().withDefault(const Constant(''))();
TextColumn get requestData => text().withDefault(const Constant(''))();
IntColumn get synced => integer().nullable()();
TextColumn get callbackFun => text().withDefault(const Constant(''))();
IntColumn get expired => integer().nullable()();
IntColumn get replace => integer().nullable()();
IntColumn get expireTime => integer().nullable()();
IntColumn get createTime => integer().nullable()();
IntColumn get addIndex => integer().nullable()();
@override
String get tableName => 'retry';
}

View File

@@ -0,0 +1,20 @@
import 'package:drift/drift.dart';
@DataClassName('DriftSound')
class Sounds extends Table {
IntColumn get id => integer()();
TextColumn get filePath => text().withDefault(const Constant(''))();
IntColumn get typ => integer()();
TextColumn get name => text().withDefault(const Constant(''))();
IntColumn get createdAt => integer()();
IntColumn get updatedAt => integer()();
IntColumn get deletedAt => integer().withDefault(const Constant(0))();
IntColumn get channelGroupId => integer()();
IntColumn get isDefault => integer()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'sound';
}

View File

@@ -0,0 +1,15 @@
import 'package:drift/drift.dart';
@DataClassName('DriftTag')
class Tags extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()();
TextColumn get name => text().withDefault(const Constant(''))();
IntColumn get type => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get addIndex => integer().nullable()();
@override
String get tableName => 'tags';
}

View File

@@ -1,41 +0,0 @@
import 'package:drift/drift.dart';
@DataClassName('TestTable')
class TestTables extends Table {
IntColumn get id => integer().autoIncrement()();
IntColumn get uid => integer().nullable()();
TextColumn get uuid => text().nullable()();
IntColumn get lastOnline => integer().nullable()();
TextColumn get profilePic => text().nullable()();
TextColumn get profilePicGaussian => text().withDefault(const Constant(''))();
TextColumn get nickname => text().nullable()();
TextColumn get depositName => text().nullable()();
IntColumn get hasSetDepositName => integer().withDefault(const Constant(0))();
TextColumn get contact => text().nullable()();
TextColumn get countryCode => text().nullable()();
TextColumn get username => text().nullable()();
IntColumn get role => integer().nullable()();
IntColumn get relationship => integer().nullable()();
IntColumn get friendStatus => integer().nullable()();
TextColumn get bio => text().nullable()();
TextColumn get userAlias => text().nullable()();
IntColumn get requestAt => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
TextColumn get email => text().nullable()();
TextColumn get recoveryEmail => text().nullable()();
TextColumn get remark => text().nullable()();
TextColumn get source => text().nullable()();
IntColumn get addIndex => integer().nullable()();
IntColumn get incomingSoundId => integer().withDefault(const Constant(0))();
IntColumn get outgoingSoundId => integer().withDefault(const Constant(0))();
IntColumn get notificationSoundId => integer().withDefault(const Constant(0))();
IntColumn get sendMessageSoundId => integer().withDefault(const Constant(0))();
IntColumn get groupNotificationSoundId => integer().withDefault(const Constant(0))();
TextColumn get groupTags => text().withDefault(const Constant('[]'))();
TextColumn get friendTags => text().withDefault(const Constant('[]'))();
TextColumn get publicKey => text().nullable()();
IntColumn get configBits => integer().withDefault(const Constant(0))();
TextColumn get hint => text().nullable()();
@override
String get tableName => 'test_tables';
}

View File

@@ -0,0 +1,14 @@
import 'package:drift/drift.dart';
@DataClassName('DriftUserRequestHistory')
class UserRequestHistories extends Table {
IntColumn get id => integer()();
IntColumn get status => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'user_request_history';
}

View File

@@ -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()();
@@ -28,14 +28,18 @@ class Users extends Table {
IntColumn get addIndex => integer().nullable()();
IntColumn get incomingSoundId => integer().withDefault(const Constant(0))();
IntColumn get outgoingSoundId => integer().withDefault(const Constant(0))();
IntColumn get notificationSoundId => integer().withDefault(const Constant(0))();
IntColumn get sendMessageSoundId => integer().withDefault(const Constant(0))();
IntColumn get groupNotificationSoundId => integer().withDefault(const Constant(0))();
IntColumn get notificationSoundId =>
integer().withDefault(const Constant(0))();
IntColumn get sendMessageSoundId =>
integer().withDefault(const Constant(0))();
IntColumn get groupNotificationSoundId =>
integer().withDefault(const Constant(0))();
TextColumn get groupTags => text().withDefault(const Constant('[]'))();
TextColumn get friendTags => text().withDefault(const Constant('[]'))();
TextColumn get publicKey => text().nullable()();
IntColumn get configBits => integer().withDefault(const Constant(0))();
TextColumn get hint => text().nullable()();
@override
String get tableName => 'user';
}
}

View File

@@ -0,0 +1,24 @@
import 'package:drift/drift.dart';
@DataClassName('DriftWorkspace')
class Workspaces extends Table {
IntColumn get id => integer()();
TextColumn get name => text().nullable()();
IntColumn get ownerId => integer().nullable()();
TextColumn get description => text().nullable()();
TextColumn get logo => text().nullable()();
IntColumn get grade => integer().nullable()();
IntColumn get cap => integer().nullable()();
TextColumn get currency => text().nullable()();
IntColumn get status => integer().nullable()();
IntColumn get createdAt => integer().nullable()();
IntColumn get updatedAt => integer().nullable()();
IntColumn get deletedAt => integer().nullable()();
IntColumn get channelGroupId => integer().nullable()();
@override
Set<Column> get primaryKey => {id};
@override
String get tableName => 'workspace';
}

View File

@@ -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),
);
}

View File

@@ -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),
);
}

View File

@@ -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),
);
}

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,
);
}
}

View File

@@ -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,
);
}
}

View File

@@ -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/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),
);
}

View File

@@ -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),
);
}

View File

@@ -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),
);
}

View File

@@ -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),
);
}

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),
);
}

View File

@@ -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),
);
}

View File

@@ -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),
);
}

View File

@@ -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),
);
}

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),
);
}

View File

@@ -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),
);
}

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),
);
}

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),
);
}

View File

@@ -0,0 +1,41 @@
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),
);
}

View File

@@ -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),
);
}

View File

@@ -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,
);
}
// ─────────────────────────────────────────────
@@ -61,7 +105,7 @@ class ProfileData {
/// 获取用户资料请求GET无参数
///
/// GET 请求无 bodytoJson() 返回空 map。
/// GET 请求无 bodymixin 自动生成 toJson() 空 map。
/// 如需 query 参数(如分页),添加字段即可,
/// toJson() 会自动将字段序列化为 URL query string。
@ApiRequest(
@@ -69,14 +113,7 @@ class ProfileData {
method: HttpMethod.get,
responseType: ProfileData,
)
@JsonSerializable()
class GetProfileRequest extends ApiRequestable<ProfileData>
with _$GetProfileRequestApi {
GetProfileRequest();
factory GetProfileRequest.fromJson(Map<String, dynamic> json) =>
_$GetProfileRequestFromJson(json);
@override
Map<String, dynamic> toJson() => _$GetProfileRequestToJson(this);
}

View File

@@ -8,57 +8,140 @@ 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();
}
// ─────────────────────────────────────────────
@@ -67,24 +150,21 @@ class LoginData {
/// 登录请求
///
/// `@ApiRequest` 自动生成 `_$LoginRequestApi` mixin
/// 提供 path / method / requestType / includeToken / fromJson 自动注册。
/// `@ApiRequest` 一个注解搞定一切:
/// - mixin 自动生成 path / method / requestType / includeToken / toJson
/// - toJson 只序列化类自身字段email, password不含继承属性
/// - Response 的 fromJson 在 parameters getter 中自动注册
/// - 无需 @JsonSerializable无需手写 fromJson / toJson
@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;
LoginRequest({required this.email, required this.password});
factory LoginRequest.fromJson(Map<String, dynamic> json) =>
_$LoginRequestFromJson(json);
@override
Map<String, dynamic> toJson() => _$LoginRequestToJson(this);
}

View File

@@ -52,7 +52,7 @@ class UploadResult {
/// FormData 上传请求
///
/// 上传到自有后端 `/upload/file`,响应为标准 `{ code, message, data }` 信封
/// 上传到自有后端 `/upload/file`,响应为标准 `{ code, message, data }` 格式
/// 无需 override `decodeResponse`。
@ApiRequest(
path: ApiPaths.uploadFile,
@@ -97,7 +97,7 @@ class S3UploadResponse {
/// - path 为完整的 presigned URLSDK 检测到 http 开头不拼 baseURL
/// - uploadData 为 Uint8List 二进制数据
/// - 自定义 headersContent-Type: application/octet-stream
/// - override decodeResponse — S3 返回 204 No Content 或 XML不是标准信封
/// - override decodeResponse — S3 返回 204 No Content 或 XML不是标准响应格式
class S3UploadRequest extends ApiRequestable<S3UploadResponse> {
final Uint8List data;
final String presignedURL;
@@ -115,8 +115,8 @@ class S3UploadRequest extends ApiRequestable<S3UploadResponse> {
@override
Map<String, String>? get customHeaders => {
'Content-Type': 'application/octet-stream',
};
'Content-Type': 'application/octet-stream',
};
@override
Map<String, dynamic> toJson() => {};
@@ -125,7 +125,7 @@ class S3UploadRequest extends ApiRequestable<S3UploadResponse> {
@override
Object? get uploadData => data;
/// S3 响应不走标准 { code, message, data } 信封,需要自定义解码
/// S3 响应不走标准 { code, message, data } 格式,需要自定义解码
///
/// 可能的响应:
/// - 204 No Content空 body→ 成功

View File

@@ -27,21 +27,25 @@ class AuthRepositoryImpl implements AuthRepository {
final NetworksSdkApi _client;
final void Function(String?) _onTokenUpdate;
AuthRepositoryImpl({required NetworksSdkApi client, required void Function(String?) onTokenUpdate,}) : _client = client, _onTokenUpdate = onTokenUpdate;
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