Initial project
This commit is contained in:
0
apps/im_app/lib/features/chat/di/.gitkeep
Normal file
0
apps/im_app/lib/features/chat/di/.gitkeep
Normal file
0
apps/im_app/lib/features/chat/presentation/.gitkeep
Normal file
0
apps/im_app/lib/features/chat/presentation/.gitkeep
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import '../../../app/di/app_providers.dart';
|
||||
import '../../../app/router/app_route_name.dart';
|
||||
|
||||
part 'chat_view_model.g.dart';
|
||||
|
||||
/// 聊天页 ViewModel(@riverpod 自动生成 `chatViewModelProvider`)
|
||||
///
|
||||
/// 当前 chat 页面为 Demo,无需从服务端加载数据,状态为 void。
|
||||
/// 后续接入会话列表时,将 build() 改为返回会话列表状态,并在此加载数据。
|
||||
///
|
||||
/// ## 数据流
|
||||
///
|
||||
/// ```
|
||||
/// ChatPage
|
||||
/// → ref.read(chatViewModelProvider.notifier).someMethod(context)
|
||||
/// → ★ ChatViewModel ★ ← 你在这里
|
||||
/// → 导航 / 业务逻辑
|
||||
/// ```
|
||||
@riverpod
|
||||
class ChatViewModel extends _$ChatViewModel {
|
||||
@override
|
||||
void build() {}
|
||||
|
||||
// ── 导航(Demo 按钮,正式开发后随 UI 一并替换) ──────────────────────────
|
||||
|
||||
/// 切换到联系人 Tab。
|
||||
void goToContact(BuildContext context) {
|
||||
context.go(AppRouteName.contact.path);
|
||||
}
|
||||
|
||||
/// 带 extra 参数 push 聊天详情页(extra 传 Dart Record)。
|
||||
void pushChatDetailWithExtra(BuildContext context) {
|
||||
context.push(
|
||||
AppRouteName.chatDetail.path,
|
||||
extra: (conversationId: '42', title: 'extra 传参'),
|
||||
);
|
||||
}
|
||||
|
||||
/// 带路径参数 push 聊天详情页(id 内嵌在 URL 中)。
|
||||
void pushChatDetailById(BuildContext context) {
|
||||
context.push(AppRouteName.chatDetailByIdPath('99'));
|
||||
}
|
||||
|
||||
/// 无参 push(演示 push 导航)。
|
||||
void pushSettingsTheme(BuildContext context) {
|
||||
context.push(AppRouteName.settingsTheme.path);
|
||||
}
|
||||
|
||||
/// 切换到设置 Tab。
|
||||
void goToSettings(BuildContext context) {
|
||||
context.go(AppRouteName.settings.path);
|
||||
}
|
||||
|
||||
// ── 业务 ─────────────────────────────────────────────────────────────────
|
||||
|
||||
/// 退出登录
|
||||
///
|
||||
/// 调用 [AuthNotifier.logout] 清除登录状态,go_router 守卫检测到后
|
||||
/// 自动重定向到登录页,无需手动导航。
|
||||
void logout() {
|
||||
ref.read(authNotifierProvider).logout();
|
||||
}
|
||||
}
|
||||
0
apps/im_app/lib/features/chat/usecases/.gitkeep
Normal file
0
apps/im_app/lib/features/chat/usecases/.gitkeep
Normal file
43
apps/im_app/lib/features/chat/view/chat_detail_page.dart
Normal file
43
apps/im_app/lib/features/chat/view/chat_detail_page.dart
Normal file
@@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../../core/ui/base/context_theme_ext.dart';
|
||||
|
||||
/// 会话详情页(路由传参 Demo)
|
||||
///
|
||||
/// 通过 go_router 的 `extra` 接收上一页传入的数据,
|
||||
/// 由 [app_router.dart] 的 builder 解包后以构造参数注入,
|
||||
/// 本页不感知 GoRouter 任何实现细节。
|
||||
///
|
||||
/// ## 正式开发
|
||||
///
|
||||
/// 将 [conversationId] 传给对应的 Riverpod `.family` provider 加载完整会话数据。
|
||||
/// 构造参数保持不变,数据来源从 `extra` 换成 provider 即可。
|
||||
class ChatDetailPage extends StatelessWidget {
|
||||
const ChatDetailPage({
|
||||
super.key,
|
||||
required this.conversationId,
|
||||
required this.title,
|
||||
});
|
||||
|
||||
final String conversationId;
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final s = context.styles;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(title)),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text('会话 ID', style: s.labelMuted),
|
||||
Text(conversationId, style: s.headlineSmall),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
67
apps/im_app/lib/features/chat/view/chat_page.dart
Normal file
67
apps/im_app/lib/features/chat/view/chat_page.dart
Normal file
@@ -0,0 +1,67 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../core/ui/components/app_button.dart';
|
||||
import '../presentation/chat_view_model.dart';
|
||||
|
||||
/// 聊天页(Demo 按钮)
|
||||
///
|
||||
/// 包含五个演示按钮,覆盖 go_router 的常见导航场景:
|
||||
/// - 「切换 Tab」 — go,替换历史,不可返回
|
||||
/// - 「有参 push(extra)」 — push + extra(Dart Record),可返回
|
||||
/// - 「有参 push(路径参数)」— push + URL 内嵌 id,可返回
|
||||
/// - 「无参 push」 — push,可返回
|
||||
/// - 「退出登录」 — 守卫自动重定向到 /login
|
||||
///
|
||||
/// 所有操作通过 [ChatViewModel] 处理,View 不直接调用路由。
|
||||
/// 正式开发后替换为会话列表,按钮相关代码一并清除。
|
||||
class ChatPage extends ConsumerWidget {
|
||||
const ChatPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final vm = ref.read(chatViewModelProvider.notifier);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('聊天')),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 16,
|
||||
children: [
|
||||
// 切换 Tab:用 go,替换整个历史栈,不可返回
|
||||
AppButton.inverse(
|
||||
label: '切换 Tab(go)',
|
||||
onPressed: () => vm.goToContact(context),
|
||||
),
|
||||
// 带参数 push:extra 传 Dart Record,适合已有对象的场景
|
||||
AppButton.inverse(
|
||||
label: '有参 push(extra)',
|
||||
onPressed: () => vm.pushChatDetailWithExtra(context),
|
||||
),
|
||||
// 带参数 push:id 内嵌在路径中,适合需要深链接 / 分享的场景
|
||||
AppButton.inverse(
|
||||
label: '有参 push(路径参数)',
|
||||
onPressed: () => vm.pushChatDetailById(context),
|
||||
),
|
||||
// 无参 push:压栈,自动显示返回按钮,不切 Tab
|
||||
AppButton.inverse(
|
||||
label: '无参 push',
|
||||
onPressed: () => vm.pushSettingsTheme(context),
|
||||
),
|
||||
// 无参 go:替换历史,切换到对应 Tab,TabBar 可见,不可返回
|
||||
AppButton.inverse(
|
||||
label: '无参 go',
|
||||
onPressed: () => vm.goToSettings(context),
|
||||
),
|
||||
AppButton.secondary(
|
||||
label: '退出登录',
|
||||
fullWidth: false,
|
||||
onPressed: () => vm.logout(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user