Files
2025-09-10 00:07:52 +08:00

221 lines
8.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:ainoval/blocs/editor/editor_bloc.dart';
import 'package:ainoval/screens/editor/controllers/editor_screen_controller.dart';
import 'package:ainoval/components/editable_title.dart';
import 'package:ainoval/utils/debouncer.dart' as debouncer;
import 'package:ainoval/utils/logger.dart';
import 'package:ainoval/screens/editor/widgets/custom_dropdown.dart';
import 'package:ainoval/screens/editor/widgets/menu_builder.dart';
import 'package:ainoval/utils/web_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
class ChapterSection extends StatefulWidget {
const ChapterSection({
super.key, // Will be replaced by chapterKey if passed
required this.title,
required this.scenes,
required this.actId,
required this.chapterId,
required this.editorBloc,
this.chapterIndex, // 添加章节序号参数
this.chapterKey, // New GlobalKey parameter
});
final String title;
final List<Widget> scenes;
final String actId;
final String chapterId;
final EditorBloc editorBloc;
final int? chapterIndex; // 章节在卷中的序号从1开始
final GlobalKey? chapterKey; // New GlobalKey parameter
@override
State<ChapterSection> createState() => _ChapterSectionState();
}
class _ChapterSectionState extends State<ChapterSection> {
late TextEditingController _chapterTitleController;
late debouncer.Debouncer _debouncer;
// 为章节创建一个ValueKey确保唯一性 - This will be overridden by widget.chapterKey if provided
// late final Key _chapterKey =
// ValueKey('chapter_${widget.actId}_${widget.chapterId}');
@override
void initState() {
super.initState();
_chapterTitleController = TextEditingController(text: widget.title);
_debouncer = debouncer.Debouncer();
}
@override
void didUpdateWidget(ChapterSection oldWidget) {
super.didUpdateWidget(oldWidget);
// 更新标题控制器
if (oldWidget.title != widget.title) {
_chapterTitleController.text = widget.title;
}
}
@override
void dispose() {
_debouncer.dispose();
_chapterTitleController.dispose();
super.dispose();
}
// 获取章节序号文本
String _getChapterIndexText() {
if (widget.chapterIndex == null) return '';
// 使用中文数字表示章节序号
final List<String> chineseNumbers = ['', '', '', '', '', '', '', '', '', '', ''];
if (widget.chapterIndex! <= 10) {
return '${chineseNumbers[widget.chapterIndex!]}章 · ';
} else if (widget.chapterIndex! < 20) {
return '第十${chineseNumbers[widget.chapterIndex! - 10]}章 · ';
} else {
// 对于更大的数字,直接使用阿拉伯数字
return '${widget.chapterIndex}章 · ';
}
}
// 手动触发加载场景的方法
void _loadScenes() {
AppLogger.i('ChapterSection', '手动触发加载章节场景: ${widget.actId} - ${widget.chapterId}');
try {
final controller = Provider.of<EditorScreenController>(context, listen: false);
controller.loadScenesForChapter(widget.actId, widget.chapterId);
} catch (e) {
// 如果无法获取控制器直接使用EditorBloc
widget.editorBloc.add(LoadMoreScenes(
fromChapterId: widget.chapterId,
direction: 'center',
actId: widget.actId,
chaptersLimit: 2,
preventFocusChange: true,
));
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
key: widget.chapterKey, // Use the passed GlobalKey here
color: WebTheme.getBackgroundColor(context), // 使用动态背景色
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Chapter标题
Padding(
// 调整间距
padding: const EdgeInsets.fromLTRB(0, 8, 0, 24), // 调整上下间距
child: Row(
crossAxisAlignment: CrossAxisAlignment.center, // 垂直居中对齐
children: [
// 添加章节序号前缀
if (widget.chapterIndex != null)
Text(
_getChapterIndexText(),
style: WebTheme.getAlignedTextStyle(
baseStyle: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
) ?? const TextStyle(),
),
),
// 可编辑的文本字段
Expanded(
child: EditableTitle(
// 保持 EditableTitle
initialText: widget.title,
style: WebTheme.getAlignedTextStyle(
baseStyle: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
) ?? const TextStyle(),
),
onChanged: (value) {
// 使用防抖更新
_debouncer.run(() {
if (mounted) {
widget.editorBloc.add(UpdateChapterTitle(
actId: widget.actId,
chapterId: widget.chapterId,
title: value,
));
}
});
},
),
),
const SizedBox(width: 8), // 增加间距
// 替换为MenuBuilder
MenuBuilder.buildChapterMenu(
context: context,
editorBloc: widget.editorBloc,
actId: widget.actId,
chapterId: widget.chapterId,
onRenamePressed: () {
// 聚焦到标题编辑框
// 通过setState强制刷新使标题进入编辑状态
setState(() {});
},
),
],
),
),
// 场景列表
if (widget.scenes.isEmpty)
// 显示空章节的UI提供手动加载按钮
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0, horizontal: 16.0),
child: Center(
child: Column(
children: [
Icon(Icons.article_outlined,
size: 48, color: WebTheme.getSecondaryTextColor(context)),
const SizedBox(height: 16),
Text(
'章节 "${widget.title}" 暂无场景内容',
style: TextStyle(color: WebTheme.getSecondaryTextColor(context)),
),
const SizedBox(height: 8),
Text(
'请手动加载或等待自动加载',
style: TextStyle(color: WebTheme.getSecondaryTextColor(context), fontSize: 14),
),
const SizedBox(height: 24),
// 加载场景按钮
OutlinedButton.icon(
onPressed: _loadScenes,
icon: Icon(Icons.download, size: 18, color: WebTheme.getTextColor(context)),
label: Text('加载场景', style: TextStyle(color: WebTheme.getTextColor(context))),
style: OutlinedButton.styleFrom(
foregroundColor: WebTheme.getTextColor(context),
side: BorderSide.none, // 去掉边框
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
elevation: 0, // 去掉阴影
),
),
],
),
),
)
else
Column(children: widget.scenes),
// 移除添加新场景按钮 - 现在由EditorMainArea统一管理
],
),
);
}
}