// 手账编辑器页面 — 三层 Stack 架构 // // Layer 1 (底层): HandwritingCanvas — 手写画布 // Layer 2 (中层): DraggableElements — 贴纸/照片/文字元素 // Layer 3 (顶层): EditorToolbar — 底部工具栏 + 顶栏操作 // // 交互逻辑: // - 画笔模式 → Layer 1 接收手势,Layer 2 透传 // - 选择模式 → Layer 2 接收手势,Layer 1 透传 // - 工具栏 → 始终在最顶层 import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import '../../../core/constants/design_tokens.dart'; import '../../../data/models/journal_element.dart'; import '../bloc/editor_bloc.dart'; import '../widgets/handwriting_canvas.dart'; import '../widgets/draggable_element.dart'; import '../widgets/editor_toolbar.dart'; /// 手账编辑器页面 class EditorPage extends StatelessWidget { final String? journalId; const EditorPage({super.key, this.journalId}); @override Widget build(BuildContext context) { return BlocProvider( create: (_) => EditorBloc( onSave: (state) { // TODO: 通过 JournalRepository 保存到 Isar debugPrint('自动保存: ${state.strokes.length} 笔画, ${state.elements.length} 元素'); }, ), child: _EditorView(journalId: journalId), ); } } class _EditorView extends StatelessWidget { final String? journalId; const _EditorView({this.journalId}); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Scaffold( backgroundColor: colorScheme.surface, body: SafeArea( child: Column( children: [ // 顶栏 _buildTopBar(context), // 编辑区域(三层 Stack) Expanded( child: BlocBuilder( builder: (context, state) { return _EditorStack(state: state); }, ), ), // 底部工具栏 BlocBuilder( builder: (context, state) { return EditorToolbar( state: state, onEvent: (event) => context.read().add(event), ); }, ), ], ), ), ); } /// 顶部操作栏 — 返回/日记标题/完成 Widget _buildTopBar(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return Container( height: 52, padding: const EdgeInsets.symmetric(horizontal: DesignTokens.spacing8), decoration: BoxDecoration( color: colorScheme.surface, border: Border( bottom: BorderSide(color: colorScheme.outline.withValues(alpha: 0.1)), ), ), child: Row( children: [ // 返回按钮 IconButton( onPressed: () => context.pop(), icon: const Icon(Icons.arrow_back_rounded), tooltip: '返回', ), const SizedBox(width: DesignTokens.spacing8), // 日记标题 Expanded( child: Text( journalId != null ? '编辑日记' : '新建日记', style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), ), // 完成按钮 FilledButton.tonal( onPressed: () { // TODO: 保存并返回 context.pop(); }, style: FilledButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: DesignTokens.spacing16), minimumSize: const Size(0, 36), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), ), child: const Text('完成'), ), ], ), ); } } // ============================================================ // 编辑器三层 Stack // ============================================================ /// 编辑器 Stack — 三层叠加结构 /// /// Layer 1 (底层): HandwritingCanvas /// Layer 2 (中层): 可拖拽元素(贴纸/照片/文字) /// Layer 3 (顶层): 由 _EditorView 中的工具栏处理 class _EditorStack extends StatelessWidget { final EditorState state; const _EditorStack({required this.state}); @override Widget build(BuildContext context) { return Stack( fit: StackFit.expand, children: [ // Layer 1: 手写画布(底层) // 始终渲染,通过 IgnorePointer 控制交互(避免模式切换时销毁重建) IgnorePointer( ignoring: !state.isDrawingMode, child: HandwritingCanvas( brushType: state.brushType, brushColor: state.brushColor, brushWidth: state.brushWidth, strokes: state.strokes, onStrokeCompleted: (stroke) { context.read().add(StrokeCompleted(stroke)); }, ), ), // Layer 2: 可拖拽元素(中层) if (state.elements.isNotEmpty) _buildElementLayer(context), // 空状态提示 if (state.strokes.isEmpty && state.elements.isEmpty) _buildEmptyHint(context), ], ); } /// 元素层 — 所有日记元素叠加显示 Widget _buildElementLayer(BuildContext context) { // 按 zIndex 排序 final sorted = List.from(state.elements) ..sort((a, b) => a.zIndex.compareTo(b.zIndex)); return Stack( children: sorted.map((element) { return DraggableElement( key: ValueKey(element.id), element: element, isSelected: state.selectedElementId == element.id, onTap: (id) { context.read().add(ElementSelected(id)); }, onMoved: (id, x, y) { context.read().add(ElementMoved( elementId: id, positionX: x, positionY: y, )); }, onDeleted: (id) { context.read().add(ElementRemoved(id)); }, ); }).toList(), ); } /// 空状态提示 Widget _buildEmptyHint(BuildContext context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon( Icons.draw_rounded, size: 48, color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.15), ), const SizedBox(height: DesignTokens.spacing12), Text( '在这里开始书写吧 ✏️', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.3), ), ), ], ), ); } }