Files
MaliangAINovalWriter/AINoval/lib/screens/editor/components/act_section.dart
2025-09-10 00:07:52 +08:00

238 lines
8.8 KiB
Dart
Raw 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/models/novel_structure.dart' as novel_models;
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';
class ActSection extends StatefulWidget {
const ActSection({
super.key,
required this.title,
required this.chapters,
required this.actId,
required this.editorBloc,
this.totalChaptersCount,
this.loadedChaptersCount,
this.actIndex, // 添加卷序号参数
});
final String title;
final List<Widget> chapters;
final String actId;
final EditorBloc editorBloc;
final int? totalChaptersCount; // 章节总数
final int? loadedChaptersCount; // 已加载章节数
final int? actIndex; // 卷序号从1开始
@override
State<ActSection> createState() => _ActSectionState();
}
class _ActSectionState extends State<ActSection> {
late TextEditingController _actTitleController;
Timer? _actTitleDebounceTimer;
@override
void initState() {
super.initState();
_actTitleController = TextEditingController(text: widget.title);
}
@override
void didUpdateWidget(ActSection oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.title != widget.title) {
_actTitleController.text = widget.title;
}
}
@override
void dispose() {
_actTitleDebounceTimer?.cancel();
_actTitleController.dispose();
super.dispose();
}
// 获取卷序号文本
String _getActIndexText() {
if (widget.actIndex == null) return '';
// 使用中文数字表示卷序号
final List<String> chineseNumbers = ['', '', '', '', '', '', '', '', '', '', ''];
if (widget.actIndex! <= 10) {
return '${chineseNumbers[widget.actIndex!]}卷 · ';
} else if (widget.actIndex! < 20) {
return '第十${chineseNumbers[widget.actIndex! - 10]}卷 · ';
} else {
// 对于更大的数字,直接使用阿拉伯数字
return '${widget.actIndex}卷 · ';
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
color: WebTheme.getBackgroundColor(context), // 使用动态背景色
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Act标题 - 居中显示
Padding(
padding: const EdgeInsets.fromLTRB(0, 16, 0, 24),
child: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// 可编辑的文本字段
IntrinsicWidth(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 400),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, // 确保垂直居中对齐
children: [
// 添加卷序号前缀
if (widget.actIndex != null)
Text(
_getActIndexText(),
style: WebTheme.getAlignedTextStyle(
baseStyle: theme.textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
) ?? const TextStyle(),
),
),
Expanded(
child: Material(
type: MaterialType.transparency, // 使用透明Material类型避免黄色下划线
child: TextField(
controller: _actTitleController,
style: WebTheme.getAlignedTextStyle(
baseStyle: theme.textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.w600,
color: WebTheme.getTextColor(context),
) ?? const TextStyle(),
),
decoration: WebTheme.getBorderlessInputDecoration(
contentPadding: const EdgeInsets.symmetric(horizontal: 8),
context: context, // 传递context以设置正确的hintStyle
),
textAlign: TextAlign.center,
onChanged: (value) {
// 使用防抖动机制,避免频繁更新
_actTitleDebounceTimer?.cancel();
_actTitleDebounceTimer =
Timer(const Duration(milliseconds: 500), () {
if (mounted) {
widget.editorBloc.add(UpdateActTitle(
actId: widget.actId,
title: value,
));
}
});
},
),
),
),
],
),
),
),
const SizedBox(width: 8),
// 显示加载状态
if (widget.totalChaptersCount != null && widget.loadedChaptersCount != null)
Tooltip(
message: '已加载 ${widget.loadedChaptersCount}/${widget.totalChaptersCount} 章节',
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: WebTheme.grey100,
borderRadius: BorderRadius.circular(12),
),
child: Text(
'${widget.loadedChaptersCount}/${widget.totalChaptersCount}',
style: TextStyle(
fontSize: 12,
color: WebTheme.getSecondaryTextColor(context),
),
),
),
),
const SizedBox(width: 8),
// 替换为MenuBuilder
MenuBuilder.buildActMenu(
context: context,
editorBloc: widget.editorBloc,
actId: widget.actId,
onRenamePressed: () {
// 聚焦到标题编辑框
setState(() {});
},
),
],
),
),
),
// 显示"没有章节"提示信息(当章节列表为空时)
if (widget.chapters.isEmpty)
Center(
child: Padding(
padding: const EdgeInsets.only(bottom: 24.0),
child: Column(
children: [
Icon(Icons.menu_book_outlined,
size: 48, color: WebTheme.getSecondaryTextColor(context)),
const SizedBox(height: 16),
Text(
'该卷下还没有章节',
style: TextStyle(
fontSize: 16,
color: WebTheme.getSecondaryTextColor(context),
),
),
const SizedBox(height: 8),
Text(
'请使用下方添加章节按钮来创建章节',
style: TextStyle(
fontSize: 14,
color: WebTheme.getSecondaryTextColor(context),
),
),
],
),
),
),
// 章节列表
...widget.chapters,
// Act分隔线
// const _ActDivider(),
],
),
);
}
}
// 可以保留或移除 _ActDivider
// class _ActDivider extends StatelessWidget {
// const _ActDivider();
// @override
// Widget build(BuildContext context) {
// return Divider(
// height: 80,
// thickness: 1,
// color: Colors.grey.shade200,
// indent: 40,
// endIndent: 40,
// );
// }
// }