Files
workavia-mail-front/lib/features/composer/presentation/mixin/text_selection_mixin.dart
T
dab246 6e09d853fd feat(ai-scribe): Fix the English locale file `(intl_en.arb)` is missing all three AI Scribe keys
feat(ai-scribe): Fix async function declared without proper return type annotation.

feat(ai-scribe): Fix Async operations not properly awaited.

feat(ai-scribe): Fix inconsistent capitalization between button labels.

feat(ai-scribe): Fix GenerateAITextFailure check will never match.

feat(ai-scribe): Fix consider validating text input for predefined actions.

feat(ai-scribe): Using a subshell for directory isolation.

feat(ai-scribe): Fix verify the mock usage or document intent.

feat(ai-scribe): Using a more conventional import for Offset.

feat(ai-scribe): Adding error handling for consistency

feat(ai-scribe): Remove `fromJson` and `toJson` of AIResponse

feat(ai-scribe): Using constants for role values.

feat(ai-scribe): Using a more specific import.

feat(ai-scribe): Using Timer for cleaner lifecycle management

feat(ai-scribe): Adding error handling to fromMap() for consistency.

feat(ai-scribe): Disposing the ValueNotifier

feat(ai-scribe): Redundant null check after assignment

feat(ai-scribe): Fix calling `registerSelectionChangeListener` multiple times may be inefficient.

feat(ai-scribe): Safer type handling for JavaScript callback args

feat(ai-scribe): Fix async callbacks not awaited in switch statement.

feat(ai-scribe): Fix binding lifecycle mismatch for GetAIScribeConfigInteractor

feat(ai-scribe): Fix ai prompts

feat(ai-scribe): Fix unawaited async call to `_setupSelectionListener`

feat(ai-scribe): Fix switch cases use top-origin coordinates while `PositionedDirectional(bottom:)`` expects bottom-origin coordinates.

feat(ai-scribe): Adding error handling for selection listener setup.
2025-12-19 19:03:39 +07:00

89 lines
2.2 KiB
Dart

import 'package:flutter/material.dart';
typedef OnTextSelectionChanged = Function(TextSelectionData?);
class TextSelectionData {
final bool hasSelection;
final String? selectedText;
final TextSelectionCoordinates? coordinates;
const TextSelectionData({
required this.hasSelection,
this.selectedText,
this.coordinates,
});
factory TextSelectionData.empty() {
return const TextSelectionData(hasSelection: false);
}
factory TextSelectionData.fromMap(Map<dynamic, dynamic> data) {
try {
final hasSelection = data['hasSelection'] as bool? ?? false;
if (!hasSelection) {
return TextSelectionData.empty();
}
final selectedText = data['selectedText'] as String?;
final coordinatesData = data['coordinates'];
if (coordinatesData != null && selectedText != null) {
final coordinates = TextSelectionCoordinates.fromMap(coordinatesData);
return TextSelectionData(
hasSelection: true,
selectedText: selectedText,
coordinates: coordinates,
);
}
return TextSelectionData.empty();
} catch (e) {
return TextSelectionData.empty();
}
}
}
class TextSelectionCoordinates {
final double x;
final double y;
final double width;
final double height;
const TextSelectionCoordinates({
required this.x,
required this.y,
required this.width,
required this.height,
});
factory TextSelectionCoordinates.fromMap(Map<dynamic, dynamic> data) {
try {
return TextSelectionCoordinates(
x: (data['x'] as num?)?.toDouble() ?? 0.0,
y: (data['y'] as num?)?.toDouble() ?? 0.0,
width: (data['width'] as num?)?.toDouble() ?? 0.0,
height: (data['height'] as num?)?.toDouble() ?? 0.0,
);
} catch (e) {
return const TextSelectionCoordinates(
x: 0.0,
y: 0.0,
width: 0.0,
height: 0.0,
);
}
}
Offset get position => Offset(x, y);
}
mixin TextSelectionMixin<T extends StatefulWidget> on State<T> {
OnTextSelectionChanged? get onSelectionChanged => null;
void handleSelectionChange(Map<dynamic, dynamic> data) {
final selectionData = TextSelectionData.fromMap(data);
onSelectionChanged?.call(selectionData);
}
}