fix(ui): resolve search history hover RenderFollowerLayer transform exception on Windows desktop
This commit is contained in:
1 parent
631134f822
commit
9129a3c0ff
2 files changed
+103
-79
No files matched your search
@@ -327,6 +327,12 @@ Files backup/restore - mirror mode or zip -->
|
||||
<!-- # STUDENT SCREEN
|
||||
- use icon for multi select, no background color and border -->
|
||||
|
||||
<!-- # SEARCH BAR
|
||||
- Windows app:
|
||||
- 'x' button not clickable and does not remove the history
|
||||
- make the history renders half of the screen
|
||||
- Android app:
|
||||
- make the history renders half of the screen, dont modify other code, only the design -->
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -52,11 +52,6 @@ class _AppSearchBarState extends ConsumerState<AppSearchBar> {
|
||||
if (currentHasText) _isExpanded = true;
|
||||
});
|
||||
}
|
||||
if (oldWidget.maxWidth != widget.maxWidth && _overlayEntry != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (mounted) _overlayEntry?.markNeedsBuild();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -78,11 +73,6 @@ class _AppSearchBarState extends ConsumerState<AppSearchBar> {
|
||||
if (hasText) _isExpanded = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Update overlay if history is visible
|
||||
if (_overlayEntry != null && widget.enableHistory) {
|
||||
_overlayEntry?.markNeedsBuild();
|
||||
}
|
||||
}
|
||||
|
||||
void _onFocusChanged() {
|
||||
@@ -100,7 +90,7 @@ class _AppSearchBarState extends ConsumerState<AppSearchBar> {
|
||||
_showOverlay();
|
||||
} else {
|
||||
// Delay removal to allow overlay tap events (InkWell) to fire before the widget is destroyed
|
||||
Future.delayed(const Duration(milliseconds: 150), () {
|
||||
Future.delayed(const Duration(milliseconds: 200), () {
|
||||
if (mounted && !_focusNode.hasFocus) {
|
||||
_removeOverlay();
|
||||
|
||||
@@ -150,82 +140,107 @@ class _AppSearchBarState extends ConsumerState<AppSearchBar> {
|
||||
|
||||
Widget _buildHistoryOverlay() {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final halfScreenHeight = MediaQuery.of(context).size.height * 0.5;
|
||||
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(searchHistoryProvider);
|
||||
if (history.isEmpty) return const SizedBox.shrink();
|
||||
|
||||
return TapRegion(
|
||||
groupId: _focusNode,
|
||||
child: Material(
|
||||
elevation: 4,
|
||||
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxHeight: 200),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: isDark ? AppColors.darkBorder : Colors.grey.shade200),
|
||||
return Material(
|
||||
elevation: 4,
|
||||
color: isDark ? AppColors.darkSurfaceCard : Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Container(
|
||||
constraints: BoxConstraints(maxHeight: halfScreenHeight),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: isDark ? AppColors.darkBorder : Colors.grey.shade200,
|
||||
),
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shrinkWrap: true,
|
||||
itemCount: history.length,
|
||||
itemBuilder: (context, index) {
|
||||
final term = history[index];
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
_controller.text = term;
|
||||
if (widget.onSubmitted != null) {
|
||||
widget.onSubmitted!(term);
|
||||
}
|
||||
ref.read(searchHistoryProvider.notifier).addSearch(term);
|
||||
Future.delayed(const Duration(milliseconds: 50), () {
|
||||
if (mounted) _focusNode.unfocus();
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 10,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.history,
|
||||
size: 18,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
term,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: isDark ? AppColors.darkTextPrimary : Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.close,
|
||||
size: 16,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(searchHistoryProvider.notifier)
|
||||
.removeSearch(term);
|
||||
),
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
shrinkWrap: true,
|
||||
itemCount: history.length,
|
||||
itemBuilder: (context, index) {
|
||||
final term = history[index];
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
onTap: () {
|
||||
_controller.text = term;
|
||||
if (widget.onSubmitted != null) {
|
||||
widget.onSubmitted!(term);
|
||||
}
|
||||
ref
|
||||
.read(searchHistoryProvider.notifier)
|
||||
.addSearch(term);
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: 50),
|
||||
() {
|
||||
if (mounted) _focusNode.unfocus();
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 10,
|
||||
),
|
||||
],
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.history,
|
||||
size: 18,
|
||||
color: isDark
|
||||
? AppColors.darkTextSecondary
|
||||
: Colors.grey.shade400,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
term,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: isDark
|
||||
? AppColors.darkTextPrimary
|
||||
: Colors.black87,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
InkResponse(
|
||||
radius: 16,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(searchHistoryProvider.notifier)
|
||||
.removeSearch(term);
|
||||
_focusNode.requestFocus();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
vertical: 10,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.close_rounded,
|
||||
size: 16,
|
||||
color: isDark
|
||||
? AppColors.darkTextMuted
|
||||
: Colors.grey.shade400,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -273,8 +288,11 @@ class _AppSearchBarState extends ConsumerState<AppSearchBar> {
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
|
||||
return TapRegion(
|
||||
groupId: _focusNode,
|
||||
onTapOutside: (event) => _focusNode.unfocus(),
|
||||
onTapOutside: (event) {
|
||||
if (_focusNode.hasFocus) {
|
||||
_focusNode.unfocus();
|
||||
}
|
||||
},
|
||||
child: CompositedTransformTarget(
|
||||
link: _layerLink,
|
||||
child: Container(
|
||||
|
||||
Reference in new issue
Block a user