-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SearchSnippet][Part-3] TF-3236 SearchSnippet search result and search suggest #3255
base: feature/search-snippet
Are you sure you want to change the base?
[SearchSnippet][Part-3] TF-3236 SearchSnippet search result and search suggest #3255
Conversation
This PR has been deployed to https://linagora.github.io/tmail-flutter/3255. |
Use below code to center highlight to frame class HighlightTextWidget2 extends StatefulWidget {
final String text;
final String highlight;
HighlightTextWidget2({required this.text, required this.highlight});
@override
_HighlightTextWidget2State createState() => _HighlightTextWidget2State();
}
class _HighlightTextWidget2State extends State<HighlightTextWidget2> {
final ScrollController _scrollController = ScrollController();
late List<TextSpan> _highlightedTextSpans;
List<double> _highlightPositions = [];
int _currentHighlightIndex = 0;
late double _lastKnownWidth;
@override
void initState() {
super.initState();
_highlightedTextSpans = _buildHighlightedTextSpans();
_lastKnownWidth = 0.0;
WidgetsBinding.instance
.addPostFrameCallback((_) => _calculateHighlightPositions());
}
// Tạo TextSpans với từ khóa highlight
List<TextSpan> _buildHighlightedTextSpans() {
List<TextSpan> spans = [];
int start = 0;
String lowerText = widget.text.toLowerCase();
String lowerHighlight = widget.highlight.toLowerCase();
int index = lowerText.indexOf(lowerHighlight);
while (index != -1) {
if (index > start) {
spans.add(TextSpan(text: widget.text.substring(start, index)));
}
spans.add(TextSpan(
text: widget.text.substring(index, index + widget.highlight.length),
style: TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
));
start = index + widget.highlight.length;
index = lowerText.indexOf(lowerHighlight, start);
}
if (start < widget.text.length) {
spans.add(TextSpan(text: widget.text.substring(start)));
}
return spans;
}
// Tính toán vị trí của tất cả các từ khóa highlight
void _calculateHighlightPositions() {
String lowerText = widget.text.toLowerCase();
String lowerHighlight = widget.highlight.toLowerCase();
_highlightPositions.clear();
int index = lowerText.indexOf(lowerHighlight);
while (index != -1) {
final textBeforeHighlight = widget.text.substring(0, index);
final TextPainter textPainter = TextPainter(
text:
TextSpan(text: textBeforeHighlight, style: TextStyle(fontSize: 16)),
textDirection: TextDirection.ltr,
)..layout();
_highlightPositions.add(textPainter.width);
index = lowerText.indexOf(lowerHighlight, index + lowerHighlight.length);
}
}
// Cuộn để từ khóa hiện tại hiển thị ở giữa
void _scrollToCurrentHighlight() {
if (_highlightPositions.isNotEmpty) {
final centerPosition = _highlightPositions[_currentHighlightIndex] -
(MediaQuery.of(context).size.width / 2) +
(widget.highlight.length * 8.0 / 2);
_scrollController.animateTo(
centerPosition.clamp(0.0, _scrollController.position.maxScrollExtent),
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);
}
}
// Xử lý khi chuyển sang highlight tiếp theo
void _scrollToNextHighlight() {
setState(() {
_currentHighlightIndex =
(_currentHighlightIndex + 1) % _highlightPositions.length;
});
_scrollToCurrentHighlight();
}
// Xử lý khi màn hình thay đổi kích thước
void _onScreenResize(BoxConstraints constraints) {
if (constraints.maxWidth != _lastKnownWidth) {
_lastKnownWidth = constraints.maxWidth;
_scrollToCurrentHighlight();
}
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
// Gọi hàm _onScreenResize để kiểm tra khi màn hình thay đổi kích thước
WidgetsBinding.instance.addPostFrameCallback((_) {
_onScreenResize(constraints);
});
return Column(
children: [
ElevatedButton(
onPressed: _scrollToNextHighlight,
child: Text("Scroll to Next Highlight"),
),
SizedBox(
height: 60,
child: ListView(
scrollDirection: Axis.horizontal,
controller: _scrollController,
physics:
NeverScrollableScrollPhysics(), // Vô hiệu hóa cuộn ngang của người dùng
children: [
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black, fontSize: 16),
children: _highlightedTextSpans,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
],
);
},
);
}
}
|
6f785cc
to
0ceb832
Compare
d2cb7bd
to
415d69e
Compare
415d69e
to
a103c78
Compare
Please check again |
Screen.Recording.2024-11-15.at.11.27.29.mov |
Screen.Recording.2024-11-18.at.10.24.31.mov |
Screen.Recording.2024-11-18.at.14.30.32.mov |
@@ -80,7 +83,13 @@ class _RichTextBuilderState extends State<RichTextBuilder> with AutomaticKeepAli | |||
return SingleChildScrollView( | |||
physics: const NeverScrollableScrollPhysics(), | |||
scrollDirection: Axis.horizontal, | |||
child: text, | |||
child: VisibilityDetector( | |||
key: ValueKey(hashCode), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it dangerous to use hashcode
like that? What if 2 different objects have the same hashcode? If the RichTextBuilder
object changes frequently it can lead to unnecessary widget re-rendering.
Screen.Recording.2024-11-18.at.18.52.50.mov |
Issue
Demo
Search results
Web
Screen.Recording.2024-11-05.at.15.46.09.mov
Mobile
search_result.webm
Search suggest
Web
Screen.Recording.2024-11-06.at.11.53.01.mov
Mobile
mobile_suggest.webm