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

120 lines
4.4 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 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:ainoval/utils/logger.dart';
import 'package:ainoval/widgets/common/top_toast.dart';
import 'package:ainoval/screens/editor/controllers/editor_screen_controller.dart';
import 'package:ainoval/utils/web_theme.dart';
/// 添加新卷按钮组件
///
/// 在编辑器中用于添加新卷时使用的按钮组件,包含点击反馈和加载态。
/// 使用Provider模式调用EditorScreenController中的创建方法。
class AddActButton extends StatefulWidget {
/// 创建一个添加新卷按钮
const AddActButton({Key? key}) : super(key: key);
@override
State<AddActButton> createState() => _AddActButtonState();
}
class _AddActButtonState extends State<AddActButton> {
/// 标记是否正在添加中,用于显示加载状态
bool _isAdding = false;
/// 记录上次点击时间,用于防抖
DateTime? _lastAddTime;
/// 防抖时间间隔2秒
static const Duration _debounceInterval = Duration(seconds: 2);
/// 添加新卷的处理方法
///
/// 包含防抖和错误处理逻辑,避免短时间内多次触发
void _addNewAct() {
// 防止频繁点击导致重复添加
final now = DateTime.now();
if (_isAdding || (_lastAddTime != null &&
now.difference(_lastAddTime!) < _debounceInterval)) {
// 如果正在添加中或最后添加时间在2秒内忽略此次点击
AppLogger.i('AddActButton', '忽略重复点击: 正在添加=${_isAdding}, 距上次点击=${_lastAddTime != null ? now.difference(_lastAddTime!).inMilliseconds : "首次点击"}ms');
// 显示提示仅在UI上
TopToast.warning(context, '操作正在处理中,请稍候...');
return;
}
// 记录当前时间并标记为添加中
_lastAddTime = now;
setState(() {
_isAdding = true;
});
AppLogger.i('AddActButton', '触发EditorScreenController的createNewAct方法');
// 使用EditorScreenController创建新卷及章节
Provider.of<EditorScreenController>(context, listen: false).createNewAct().then((_) {
if (mounted) {
setState(() {
_isAdding = false;
});
}
}).catchError((error) {
AppLogger.e('AddActButton', '调用createNewAct失败', error);
if (mounted) {
setState(() {
_isAdding = false;
});
TopToast.error(context, '创建失败: ${error.toString()}');
}
});
}
@override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: OutlinedButton.icon(
onPressed: _isAdding ? null : _addNewAct, // 如果正在添加中,禁用按钮
icon: _isAdding
// 添加中状态显示加载指示器
? SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(WebTheme.getPrimaryColor(context)),
),
)
// 常规状态显示加号图标
: const Icon(Icons.add, size: 18),
label: Text(_isAdding ? '添加中...' : '添加新卷'),
style: OutlinedButton.styleFrom(
foregroundColor: WebTheme.getPrimaryColor(context),
backgroundColor: WebTheme.getSurfaceColor(context),
side: BorderSide(color: WebTheme.getPrimaryColor(context), width: 1.5),
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 1,
).copyWith(
overlayColor: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return WebTheme.getPrimaryColor(context).withOpacity(0.1);
}
return null;
},
),
),
),
),
);
}
}