2026-04-09 21:32:23 +08:00

96 lines
2.7 KiB
Dart

import 'dart:ui';
import 'package:extended_text/extended_text.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:yumi/ui_kit/theme/socialchat_theme.dart';
import 'package:yumi/shared/tools/sc_string_utils.dart';
class AtTextSpanBuilder extends SpecialTextSpanBuilder {
final Function(String userId)? onTapCall;
AtTextSpanBuilder({this.onTapCall});
@override
SpecialText? createSpecialText(
String flag, {
TextStyle? textStyle,
SpecialTextGestureTapCallback? onTap,
required int index,
}) {
if (isStart(flag, AtText.flag)) {
return AtText(
textStyle: textStyle!,
start: index - (AtText.flag.length - 1),
onTap: (userId) {
onTapCall?.call(userId);
},
);
}
return null;
}
}
class AtText extends SpecialText {
static const String flag = '<user id="';
static const String endFlag2 = '</user>';
final int start;
final SpecialTextGestureTapCallback? onTap;
AtText({
required TextStyle textStyle,
required this.start,
required this.onTap,
}) : super(flag, endFlag2, textStyle, onTap: onTap);
@override
InlineSpan finishText() {
final String atContent = toString();
final TextStyle style =
textStyle?.copyWith(color: SocialChatTheme.primaryLight, fontWeight: FontWeight.w600) ??
const TextStyle();
String userName = _extractUserName(toString());
return SpecialTextSpan(
start: start,
actualText: atContent,
deleteAll: true,
style: style,
text:
SCStringUtils.containsArabicCharacters(userName) ? "${userName}@" : "@${userName}",
recognizer:
TapGestureRecognizer()
..onTap = () {
onTap?.call(_extractUserId(atContent));
},
);
}
/// 提取用户ID
String _extractUserId(String atContent) {
// 匹配 id="xxx"
final RegExp exp = RegExp(r'id\s*=\s*"([^"]*)"');
final RegExpMatch? match = exp.firstMatch(atContent);
return match?.group(1)?.trim() ?? '';
}
/// 提取用户名
String _extractUserName(String atContent) {
// 匹配 >用户名<
final RegExp exp = RegExp(r'>([^<]+)<');
final RegExpMatch? match = exp.firstMatch(atContent);
return match?.group(1)?.trim() ?? '';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is AtText &&
other.start == start &&
other.toString() == toString();
}
@override
int get hashCode => start.hashCode ^ toString().hashCode;
}