feat(app): EditorPage 读取 template 参数 — 模板选择框架

This commit is contained in:
iven
2026-06-01 21:41:53 +08:00
parent db881c25a0
commit 6378da055f
2 changed files with 48 additions and 28 deletions

View File

@@ -1,4 +1,5 @@
// 暖记路由表 — go_router 20 页面 + 认证守卫
// 暖记路由表 — go_router + 认证守卫
// 对齐 Open Design: TabBar = 首页/日历/发现/我的,中心 FAB = 写日记
//
// 路由守卫逻辑:
// - 未认证用户访问受保护路由 → 重定向到 /login
@@ -24,6 +25,8 @@ import '../../features/editor/views/editor_page.dart';
import '../../features/auth/views/login_page.dart';
import '../../features/auth/views/role_selection_page.dart';
import '../../features/auth/views/class_code_join_page.dart';
import '../../features/onboarding/views/splash_page.dart';
import '../../features/onboarding/views/onboarding_page.dart';
import '../../features/class_/views/class_page.dart';
import '../../features/teacher/views/teacher_page.dart';
import '../../features/parent/views/parent_page.dart';
@@ -38,7 +41,7 @@ final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();
/// 不需要认证的白名单路径
const _publicPaths = ['/login', '/role-selection', '/class-code'];
const _publicPaths = ['/splash', '/onboarding', '/login', '/role-selection', '/class-code'];
/// 创建路由配置 — 需要注入 AuthBloc
GoRouter createAppRouter(AuthBloc authBloc) {
@@ -91,6 +94,18 @@ GoRouter createAppRouter(AuthBloc authBloc) {
refreshListenable: _AuthListenable(authBloc),
routes: [
// 启动页 & 引导页(无 Shell无需认证
GoRoute(
path: '/splash',
name: 'splash',
builder: (context, state) => const SplashPage(),
),
GoRoute(
path: '/onboarding',
name: 'onboarding',
builder: (context, state) => const OnboardingPage(),
),
// 认证路由(无 Shell
GoRoute(
path: '/login',
@@ -108,7 +123,7 @@ GoRouter createAppRouter(AuthBloc authBloc) {
builder: (context, state) => const ClassCodeJoinPage(),
),
// 主 Shell 路由(底部导航 + 侧边导航
// 主 Shell 路由(底部导航: 首页/日历/发现/我的
ShellRoute(
navigatorKey: _shellNavigatorKey,
builder: (context, state, child) {
@@ -129,14 +144,10 @@ GoRouter createAppRouter(AuthBloc authBloc) {
name: 'calendar',
builder: (context, state) => const CalendarPage(),
),
// 发现页(复用搜索页,后续可替换为独立 DiscoverPage
GoRoute(
path: '/mood',
name: 'mood',
builder: (context, state) => const MoodPage(),
),
GoRoute(
path: '/search',
name: 'search',
path: '/discover',
name: 'discover',
builder: (context, state) => const SearchPage(),
),
GoRoute(
@@ -154,9 +165,17 @@ GoRouter createAppRouter(AuthBloc authBloc) {
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state) {
final journalId = state.uri.queryParameters['id'];
return EditorPage(journalId: journalId);
final templateId = state.uri.queryParameters['template'];
return EditorPage(journalId: journalId, templateId: templateId);
},
),
// 心情追踪(全屏,从首页心情卡片进入)
GoRoute(
path: '/mood',
name: 'mood',
parentNavigatorKey: _rootNavigatorKey,
builder: (context, state) => const MoodPage(),
),
GoRoute(
path: '/class',
name: 'class',
@@ -203,13 +222,12 @@ GoRouter createAppRouter(AuthBloc authBloc) {
);
}
/// 路径 → Tab index 映射
/// 路径 → Tab index 映射4 项: 首页=0, 日历=1, 发现=2, 我的=3
int _selectedIndexFromLocation(String location) {
if (location.startsWith('/calendar')) return 1;
if (location.startsWith('/mood')) return 2;
if (location.startsWith('/search')) return 3;
if (location.startsWith('/profile')) return 4;
return 0;
if (location.startsWith('/discover')) return 2;
if (location.startsWith('/profile')) return 3;
return 0; // /home 或未知路径
}
/// AuthBloc 变化监听器 — 驱动 GoRouter refreshListenable
@@ -230,6 +248,8 @@ class _AuthListenable extends ChangeNotifier {
}
/// App Shell — 包裹 ResponsiveScaffold
/// TabBar: 首页(0) / 日历(1) / 发现(2) / 我的(3)
/// 中心 FAB: 写日记
class _AppShell extends StatelessWidget {
const _AppShell({
required this.selectedIndex,
@@ -250,20 +270,13 @@ class _AppShell extends StatelessWidget {
case 1:
context.go('/calendar');
case 2:
context.go('/mood');
context.go('/discover');
case 3:
context.go('/search');
case 4:
context.go('/profile');
}
},
body: child,
floatingActionButton: selectedIndex == 0
? FloatingActionButton(
onPressed: () => context.push('/editor'),
child: const Icon(Icons.edit_rounded),
)
: null,
onCenterButtonPressed: () => context.push('/editor'),
);
}
}

View File

@@ -29,8 +29,9 @@ import '../widgets/sticker_picker_sheet.dart';
/// 手账编辑器页面
class EditorPage extends StatelessWidget {
final String? journalId;
final String? templateId;
const EditorPage({super.key, this.journalId});
const EditorPage({super.key, this.journalId, this.templateId});
@override
Widget build(BuildContext context) {
@@ -53,6 +54,7 @@ class EditorPage extends StatelessWidget {
),
child: _EditorView(
journalId: journalId,
templateId: templateId,
onSaveComplete: () {
if (context.canPop()) {
context.pop();
@@ -154,9 +156,10 @@ class EditorPage extends StatelessWidget {
class _EditorView extends StatelessWidget {
final String? journalId;
final String? templateId;
final VoidCallback onSaveComplete;
const _EditorView({this.journalId, required this.onSaveComplete});
const _EditorView({this.journalId, this.templateId, required this.onSaveComplete});
@override
Widget build(BuildContext context) {
@@ -227,7 +230,11 @@ class _EditorView extends StatelessWidget {
// 日记标题
Expanded(
child: Text(
journalId != null ? '编辑日记' : '新建日记',
journalId != null
? '编辑日记'
: templateId != null
? '从模板新建'
: '新建日记',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),