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

162 lines
5.6 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:ainoval/utils/web_theme.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:ainoval/utils/logger.dart';
import 'package:ainoval/utils/setting_reference_processor.dart';
/// 🎯 简化版设定引用悬停状态管理器
/// 使用TextStyle.backgroundColor实现悬停效果比复杂的位置计算更简单高效
class SettingReferenceHoverManager extends ChangeNotifier {
static final SettingReferenceHoverManager _instance = SettingReferenceHoverManager._internal();
factory SettingReferenceHoverManager() => _instance;
SettingReferenceHoverManager._internal();
String? _hoveredSettingId;
String? get hoveredSettingId => _hoveredSettingId;
/// 设置悬停的设定引用ID
void setHoveredSetting(String? settingId) {
if (_hoveredSettingId != settingId) {
_hoveredSettingId = settingId;
notifyListeners();
AppLogger.d('SettingReferenceHoverManager',
_hoveredSettingId != null
? '🖱️ 设定引用悬停开始: $_hoveredSettingId'
: '🖱️ 设定引用悬停结束');
}
}
/// 清除悬停状态
void clearHover() {
setHoveredSetting(null);
}
}
/// 设定引用交互混入 - 为 SceneEditor 提供设定引用交互功能
mixin SettingReferenceInteractionMixin {
/// 🎯 获取支持悬停效果的设定引用样式构建器
/// 这是最核心的方法直接在customStyleBuilder中处理悬停效果
static TextStyle Function(Attribute) getCustomStyleBuilderWithHover({
required String? hoveredSettingId,
}) {
return (Attribute attribute) {
// 处理设定引用的样式标记
if (attribute.key == SettingReferenceProcessor.settingStyleAttr &&
attribute.value == 'reference') {
// 🎯 关键使用TextStyle.backgroundColor实现悬停效果
return const TextStyle(
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.dotted,
decorationColor: WebTheme.grey400,
decorationThickness: 1.5,
// 🎯 核心直接使用TextStyle的backgroundColor属性
backgroundColor: Color(0x00FFF3CD),
).copyWith(
backgroundColor: hoveredSettingId != null ? const Color(0xFFFFF3CD) : null,
);
}
return const TextStyle();
};
}
/// 获取设定引用的自定义手势识别器构建器
static GestureRecognizer? Function(Attribute, Node) getCustomRecognizerBuilder({
required Function(String settingId)? onSettingReferenceClicked,
required Function(String settingId)? onSettingReferenceHovered,
required VoidCallback? onSettingReferenceHoverEnd,
}) {
return (Attribute attribute, Node node) {
// 检查是否是设定引用属性
if (attribute.key == SettingReferenceProcessor.settingReferenceAttr ) {
final settingId = attribute.value as String?;
if (settingId != null && settingId.isNotEmpty) {
//AppLogger.d('SettingReferenceInteraction', '🎯 创建设定引用手势识别器: $settingId');
// 创建支持点击和悬停的手势识别器
final tapRecognizer = TapGestureRecognizer()
..onTap = () {
AppLogger.i('SettingReferenceInteraction', '🖱️ 设定引用被点击: $settingId');
onSettingReferenceClicked?.call(settingId);
};
return tapRecognizer;
}
}
return null;
};
}
/// 获取设定引用的自定义样式构建器(基础版本)
static TextStyle Function(Attribute) getCustomStyleBuilder() {
return (Attribute attribute) {
// 处理设定引用的样式标记
if (attribute.key == SettingReferenceProcessor.settingStyleAttr &&
attribute.value == 'reference') {
return const TextStyle(
decoration: TextDecoration.underline,
decorationStyle: TextDecorationStyle.dotted,
decorationColor: WebTheme.grey400,
decorationThickness: 1.5,
);
}
return const TextStyle();
};
}
}
/// 🎯 设定引用鼠标悬停检测器Widget
/// 使用MouseRegion包装编辑器检测鼠标悬停并更新状态
class SettingReferenceMouseDetector extends StatefulWidget {
final Widget child;
final QuillController controller;
final String? novelId;
const SettingReferenceMouseDetector({
Key? key,
required this.child,
required this.controller,
this.novelId,
}) : super(key: key);
@override
State<SettingReferenceMouseDetector> createState() => _SettingReferenceMouseDetectorState();
}
class _SettingReferenceMouseDetectorState extends State<SettingReferenceMouseDetector> {
final _hoverManager = SettingReferenceHoverManager();
@override
Widget build(BuildContext context) {
return MouseRegion(
onHover: _handleMouseMove,
onExit: (_) => _hoverManager.clearHover(),
child: widget.child,
);
}
void _handleMouseMove(PointerHoverEvent event) {
// 🎯 这里可以实现基于鼠标位置的设定引用检测
// 为了简化,暂时先处理基本的悬停状态
try {
// TODO: 实现更精确的位置检测逻辑
// 目前先简化处理,后续可以根据需要优化
// 暂时用一个简单的方式来模拟检测
// 实际项目中可能需要更复杂的位置计算
AppLogger.v('SettingReferenceMouseDetector', '🖱️ 鼠标移动: ${event.localPosition}');
} catch (e) {
AppLogger.w('SettingReferenceMouseDetector', '检测设定引用悬停失败', e);
}
}
}