优化配置,修复 demo bug
1,network 框架完善 2,websocket 机制完善 3,设计文档整理到架构文档 4,脚本,配置完善
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:im_app/app/di/db_provider.dart';
|
||||
import 'package:im_app/data/local/drift/app_database.dart';
|
||||
@@ -45,13 +44,12 @@ class ChatDbTestState {
|
||||
|
||||
@riverpod
|
||||
class ChatDbTestViewModel extends _$ChatDbTestViewModel {
|
||||
|
||||
@override
|
||||
ChatDbTestState build() {
|
||||
// 这里就是 onInit
|
||||
final List<TestResult> testResults = List.generate(
|
||||
1000,
|
||||
(i) => TestResult(
|
||||
(i) => TestResult(
|
||||
title: '用户 ${Random().nextInt(9999)}',
|
||||
subtitle: 'uid: ${Random().nextInt(999999)}',
|
||||
duration: '${Random().nextInt(500)}ms',
|
||||
@@ -86,7 +84,7 @@ class ChatDbTestViewModel extends _$ChatDbTestViewModel {
|
||||
for (var i = 0; i < count; i += chunkSize) {
|
||||
final chunk = List.generate(
|
||||
chunkSize.clamp(0, count - i),
|
||||
(j) => UsersCompanion.insert(
|
||||
(j) => UsersCompanion.insert(
|
||||
uid: Value(i + j),
|
||||
nickname: Value('User ${i + j}'),
|
||||
),
|
||||
@@ -98,13 +96,13 @@ class ChatDbTestViewModel extends _$ChatDbTestViewModel {
|
||||
// 让出主线程
|
||||
await Future.delayed(Duration.zero);
|
||||
|
||||
debugPrint('已完成: $completed / $count (${stopwatch.elapsedMilliseconds}ms)');
|
||||
debugPrint(
|
||||
'已完成: $completed / $count (${stopwatch.elapsedMilliseconds}ms)',
|
||||
);
|
||||
|
||||
// 更新 UI 状态
|
||||
if (ref.mounted) {
|
||||
state = state.copyWith(
|
||||
currentState: '已插入 $completed / $count 条',
|
||||
);
|
||||
state = state.copyWith(currentState: '已插入 $completed / $count 条');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,4 +114,4 @@ class ChatDbTestViewModel extends _$ChatDbTestViewModel {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../../core/ui/base/context_theme_ext.dart';
|
||||
|
||||
@@ -12,7 +13,7 @@ import '../../../../core/ui/base/context_theme_ext.dart';
|
||||
///
|
||||
/// 将 [conversationId] 传给对应的 Riverpod `.family` provider 加载完整会话数据。
|
||||
/// 构造参数保持不变,数据来源从 `extra` 换成 provider 即可。
|
||||
class ChatDetailPage extends StatelessWidget {
|
||||
class ChatDetailPage extends ConsumerWidget {
|
||||
const ChatDetailPage({
|
||||
super.key,
|
||||
required this.conversationId,
|
||||
@@ -23,7 +24,7 @@ class ChatDetailPage extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final s = context.styles;
|
||||
|
||||
return Scaffold(
|
||||
|
||||
@@ -20,8 +20,6 @@ class ChatPage extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final vm = ref.read(chatViewModelProvider.notifier);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('聊天')),
|
||||
body: Center(
|
||||
@@ -32,36 +30,48 @@ class ChatPage extends ConsumerWidget {
|
||||
// 切换 Tab:用 go,替换整个历史栈,不可返回
|
||||
AppButton.inverse(
|
||||
label: '切换 Tab(go)',
|
||||
onPressed: () => vm.goToContact(context),
|
||||
onPressed: () =>
|
||||
ref.read(chatViewModelProvider.notifier).goToContact(context),
|
||||
),
|
||||
// 带参数 push:extra 传 Dart Record,适合已有对象的场景
|
||||
AppButton.inverse(
|
||||
label: '有参 push(extra)',
|
||||
onPressed: () => vm.pushChatDetailWithExtra(context),
|
||||
onPressed: () => ref
|
||||
.read(chatViewModelProvider.notifier)
|
||||
.pushChatDetailWithExtra(context),
|
||||
),
|
||||
// 带参数 push:id 内嵌在路径中,适合需要深链接 / 分享的场景
|
||||
AppButton.inverse(
|
||||
label: '有参 push(路径参数)',
|
||||
onPressed: () => vm.pushChatDetailById(context),
|
||||
onPressed: () => ref
|
||||
.read(chatViewModelProvider.notifier)
|
||||
.pushChatDetailById(context),
|
||||
),
|
||||
// 无参 push:压栈,自动显示返回按钮,不切 Tab
|
||||
AppButton.inverse(
|
||||
label: '无参 push',
|
||||
onPressed: () => vm.pushSettingsTheme(context),
|
||||
onPressed: () => ref
|
||||
.read(chatViewModelProvider.notifier)
|
||||
.pushSettingsTheme(context),
|
||||
),
|
||||
// 无参 go:替换历史,切换到对应 Tab,TabBar 可见,不可返回
|
||||
AppButton.inverse(
|
||||
label: '无参 go',
|
||||
onPressed: () => vm.goToSettings(context),
|
||||
onPressed: () => ref
|
||||
.read(chatViewModelProvider.notifier)
|
||||
.goToSettings(context),
|
||||
),
|
||||
AppButton.inverse(
|
||||
label: '测试数据库性能',
|
||||
onPressed: () => vm.goToDatabaseTest(context),
|
||||
onPressed: () => ref
|
||||
.read(chatViewModelProvider.notifier)
|
||||
.goToDatabaseTest(context),
|
||||
),
|
||||
AppButton.secondary(
|
||||
label: '退出登录',
|
||||
fullWidth: false,
|
||||
onPressed: () => vm.logout(),
|
||||
onPressed: () =>
|
||||
ref.read(chatViewModelProvider.notifier).logout(),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
/// 联系人页占位
|
||||
///
|
||||
/// 待 contact 功能开发后替换为实际内容。
|
||||
class ContactPage extends StatelessWidget {
|
||||
class ContactPage extends ConsumerWidget {
|
||||
const ContactPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return const Scaffold();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import '../usecases/login_usecase.dart';
|
||||
/// ViewModel Provider 由 `@riverpod` 注解自动生成,不在此文件中。
|
||||
///
|
||||
/// Auth 模块的 DI 链路:Repository → UseCase(按需)。
|
||||
/// app/di/ 只提供 SDK 基础设施(apiConfig / apiClient / socketManager / storageApi),
|
||||
/// app/di/ 只提供 SDK 基础设施(apiConfig / networkSdkApi / socketManager / storageApi),
|
||||
/// 业务模块的 Provider 内聚在 features/{模块}/di/ 下。
|
||||
///
|
||||
/// ```
|
||||
@@ -21,7 +21,7 @@ import '../usecases/login_usecase.dart';
|
||||
/// → ref.read(authRepositoryProvider) ← di/ 手动装配
|
||||
/// → ref.read(socketManagerProvider) ← app/di/ 手动装配
|
||||
/// → ref.read(apiConfigProvider) ← app/di/ 手动装配
|
||||
/// → ref.read(apiClientProvider) ← app/di/ 手动装配
|
||||
/// → ref.read(networkSdkApiProvider) ← app/di/ 手动装配
|
||||
/// → ref.read(storageSdkProvider) ← app/di/ 手动装配
|
||||
/// ```
|
||||
|
||||
@@ -41,7 +41,7 @@ final authRepositoryProvider = Provider<AuthRepository>((ref) {
|
||||
// TODO: final secureStorage = ref.read(secureStorageProvider);
|
||||
|
||||
return AuthRepositoryImpl(
|
||||
client: ref.read(networkSdkApiProvider), // 直接注入 ApiClient
|
||||
client: ref.read(networkSdkApiProvider), // 注入 Facade 接口
|
||||
onTokenUpdate: (token) {
|
||||
apiConfig.updateToken(token); // 内存(network_sdk)
|
||||
// TODO: secureStorage.saveToken(token); // 持久化(crypto_sdk)
|
||||
|
||||
@@ -29,7 +29,7 @@ part 'login_view_model.g.dart';
|
||||
/// loginViewModelProvider ← @riverpod 自动生成(本文件)
|
||||
/// → ref.read(loginUseCaseProvider) ← di/ 手动装配
|
||||
/// → ref.read(authRepositoryProvider) ← di/ 手动装配
|
||||
/// → ref.read(apiClientProvider) ← app/di/ 手动装配
|
||||
/// → ref.read(networkSdkApiProvider) ← app/di/ 手动装配
|
||||
/// ```
|
||||
///
|
||||
/// ## 数据流位置
|
||||
@@ -56,6 +56,7 @@ class LoginViewModel extends _$LoginViewModel {
|
||||
/// 正式 [login] 成功后同样需要调用 [AuthNotifier.login] 更新守卫状态。
|
||||
Future<void> demoLogin() async {
|
||||
final storageApi = ref.read(storageSdkProvider);
|
||||
|
||||
///TODO: StorageSDKLifeCycle 需要只在主项目暴露
|
||||
final storageLifeCycle = storageApi as StorageSdkLifecycle;
|
||||
ref.read(authNotifierProvider).login();
|
||||
@@ -76,10 +77,9 @@ class LoginViewModel extends _$LoginViewModel {
|
||||
state = state.copyWith(isLoading: true, error: null);
|
||||
|
||||
try {
|
||||
final user = await ref.read(loginUseCaseProvider).execute(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
final user = await ref
|
||||
.read(loginUseCaseProvider)
|
||||
.execute(email: email, password: password);
|
||||
|
||||
state = state.copyWith(user: user, isLoading: false);
|
||||
} on FormatException catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user