TF-4265 Refactor: Move Regex pattern generation to Main Thread to leverage static caching and reduce Isolate initialization overhead.
This commit is contained in:
@@ -882,10 +882,7 @@ class ComposerController extends BaseController
|
||||
}
|
||||
|
||||
final emailContent = await getContentInEditor();
|
||||
if (!context.mounted) {
|
||||
_sendButtonState = ButtonState.enabled;
|
||||
return;
|
||||
}
|
||||
|
||||
final attachmentKeywords = await validateAttachmentReminder(
|
||||
emailSubject: subjectEmail.value ?? '',
|
||||
emailContent: emailContent,
|
||||
@@ -893,6 +890,7 @@ class ComposerController extends BaseController
|
||||
|
||||
if (!context.mounted) {
|
||||
logWarning('ComposerController::_prepareToSendMessages: CONTEXT IS NOT MOUNTED');
|
||||
_sendButtonState = ButtonState.enabled;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,13 +46,12 @@ class AttachmentTextDetector {
|
||||
"مستند",
|
||||
"ملف",
|
||||
"تقرير",
|
||||
"ملف",
|
||||
"إرفاق",
|
||||
],
|
||||
};
|
||||
|
||||
/// Cached RegExp for the default case (when no include list is provided).
|
||||
static RegExp? _cachedDefaultRegExp;
|
||||
/// Cached RegExp Pattern for the default case (when no include list is provided).
|
||||
static String? _cachedDefaultPattern;
|
||||
/// Threshold to switch from Sync to Async execution.
|
||||
///
|
||||
/// Value: 20,000 characters (approx. 4-5 pages of text).
|
||||
@@ -118,7 +117,7 @@ class AttachmentTextDetector {
|
||||
|
||||
/// Builds the Regex pattern.
|
||||
/// Merges [defaultKeywords] with [includeList] to create the search scope.
|
||||
static RegExp _buildRegExp(List<String> additionalKeywords) {
|
||||
static String _generatePatternString(List<String> additionalKeywords) {
|
||||
// 1. Get all default keywords
|
||||
final defaultKeywords = _keywordsByLang.values.expand((l) => l).toList();
|
||||
|
||||
@@ -133,11 +132,16 @@ class AttachmentTextDetector {
|
||||
// (?![\p{L}]) ensures we don't match substrings inside other words (e.g., "filetage").
|
||||
final pattern = allKeywords.map(RegExp.escape).join('|');
|
||||
|
||||
return RegExp(
|
||||
'($pattern)(?![\\p{L}])',
|
||||
unicode: true,
|
||||
caseSensitive: false,
|
||||
);
|
||||
return'($pattern)(?![\\p{L}])';
|
||||
}
|
||||
|
||||
static String _getPattern(List<String> includeList) {
|
||||
if (includeList.isNotEmpty) {
|
||||
return _generatePatternString(includeList);
|
||||
}
|
||||
|
||||
_cachedDefaultPattern ??= _generatePatternString([]);
|
||||
return _cachedDefaultPattern!;
|
||||
}
|
||||
|
||||
/// The core logic function.
|
||||
@@ -148,16 +152,11 @@ class AttachmentTextDetector {
|
||||
final text = params.text;
|
||||
if (text.isEmpty) return [];
|
||||
|
||||
RegExp regex;
|
||||
|
||||
// Use cached Regex if there are no custom keywords.
|
||||
if (params.includeList.isEmpty) {
|
||||
_cachedDefaultRegExp ??= _buildRegExp([]);
|
||||
regex = _cachedDefaultRegExp!;
|
||||
} else {
|
||||
// Rebuild Regex if Include List is present.
|
||||
regex = _buildRegExp(params.includeList);
|
||||
}
|
||||
final regex = RegExp(
|
||||
params.regexPattern,
|
||||
unicode: true,
|
||||
caseSensitive: false,
|
||||
);
|
||||
|
||||
final matches = regex.allMatches(text);
|
||||
final result = <String>{};
|
||||
@@ -199,10 +198,12 @@ class AttachmentTextDetector {
|
||||
filters.add(ExcludeListFilter(excludeList));
|
||||
}
|
||||
|
||||
final patternString = _getPattern(includeList);
|
||||
|
||||
final params = DetectionParams(
|
||||
text: text,
|
||||
includeList: includeList, // Passed to build the Regex
|
||||
filters: filters, // Passed to filter the matches
|
||||
regexPattern: patternString,
|
||||
filters: filters,
|
||||
);
|
||||
|
||||
// Decision: Run Sync (fast) or Async (safe)
|
||||
|
||||
@@ -4,12 +4,12 @@ import 'package:tmail_ui_user/features/composer/presentation/manager/keyword_fil
|
||||
/// Isolates cannot share memory, so we package everything here.
|
||||
class DetectionParams {
|
||||
final String text;
|
||||
final List<String> includeList; // Keywords to ADD to the search.
|
||||
final String regexPattern;
|
||||
final List<KeywordFilter> filters; // Filters to BLOCK specific matches.
|
||||
|
||||
DetectionParams({
|
||||
required this.text,
|
||||
required this.includeList,
|
||||
required this.regexPattern,
|
||||
required this.filters,
|
||||
});
|
||||
}
|
||||
@@ -23,6 +23,10 @@ class ExcludeListFilter with TokenExtractionMixin implements KeywordFilter {
|
||||
final cleanToken = lowerToken.replaceAll(RegExp(r'[^\w\s]+$'), '');
|
||||
if (_excludes.contains(cleanToken)) return false;
|
||||
|
||||
// Check 3: Block even if it has leading punctuation (e.g., "(file")
|
||||
final fullyCleanToken = cleanToken.replaceAll(RegExp(r'^[^\w\s]+'), '');
|
||||
if (_excludes.contains(fullyCleanToken)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user