update search box design
This commit is contained in:
@@ -232,7 +232,8 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
final measuredHeight = getTextFieldHeight(textFieldKey);
|
final measuredHeight = getTextFieldHeight(textFieldKey);
|
||||||
|
|
||||||
if (measuredHeight != null) {
|
if (measuredHeight != null) {
|
||||||
preferredHeight.value = measuredHeight;
|
// Add 2px to account for SearchField container border
|
||||||
|
preferredHeight.value = measuredHeight + 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -458,7 +459,7 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
title: isEditMode
|
title: isEditMode
|
||||||
? null
|
? null
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final tabTypeSwitcher = Focus(
|
final tabTypeSwitcher = Focus(
|
||||||
@@ -529,111 +530,105 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
bottom: PreferredSize(
|
bottom: PreferredSize(
|
||||||
preferredSize: Size.fromHeight(preferredHeight.value),
|
preferredSize: Size.fromHeight(preferredHeight.value),
|
||||||
child: Padding(
|
child: SearchField(
|
||||||
padding: const EdgeInsets.only(left: 16.0),
|
textFieldKey: textFieldKey,
|
||||||
child: SearchField(
|
showBangIcon: showBangIcon,
|
||||||
textFieldKey: textFieldKey,
|
textEditingController: searchTextController,
|
||||||
showBangIcon: showBangIcon,
|
focusNode: searchFocusNode,
|
||||||
textEditingController: searchTextController,
|
maxLines: isEditMode ? 3 : 1,
|
||||||
focusNode: searchFocusNode,
|
autofocus: true,
|
||||||
maxLines: isEditMode ? 3 : 1,
|
label: const Text('Search or enter URL'),
|
||||||
autofocus: true,
|
unfocusOnTapOutside: false,
|
||||||
label: const Text('Search or enter URL'),
|
onSubmitted: (value) async {
|
||||||
unfocusOnTapOutside: false,
|
if (value.isNotEmpty) {
|
||||||
onSubmitted: (value) async {
|
final classification = classifyAddressBarInput(value);
|
||||||
if (value.isNotEmpty) {
|
Uri? newUrl;
|
||||||
final classification = classifyAddressBarInput(value);
|
String? searchQuery;
|
||||||
Uri? newUrl;
|
|
||||||
String? searchQuery;
|
|
||||||
|
|
||||||
switch (classification) {
|
|
||||||
case NavigateInputClassification(:final uri):
|
|
||||||
newUrl = uri;
|
|
||||||
case SearchInputClassification(:final query):
|
|
||||||
searchQuery = query;
|
|
||||||
case InvalidInputClassification():
|
|
||||||
if (context.mounted) {
|
|
||||||
ui_helper.showErrorMessage(
|
|
||||||
context,
|
|
||||||
'Invalid address',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newUrl == null && searchQuery != null) {
|
|
||||||
// Read from both providers - use site if set, otherwise global
|
|
||||||
final siteBang = isEditMode
|
|
||||||
? ref.read(
|
|
||||||
selectedBangDataProvider(
|
|
||||||
domain: existingTabState.url.host,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: null;
|
|
||||||
final globalBang = ref.read(
|
|
||||||
selectedBangDataProvider(),
|
|
||||||
);
|
|
||||||
final bang =
|
|
||||||
siteBang ??
|
|
||||||
globalBang ??
|
|
||||||
await ref.read(
|
|
||||||
defaultSearchBangDataProvider.future,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (bang != null) {
|
|
||||||
newUrl = bang.getTemplateUrl(searchQuery);
|
|
||||||
|
|
||||||
if (!privateTabMode) {
|
|
||||||
await ref
|
|
||||||
.read(bangSearchProvider.notifier)
|
|
||||||
.triggerBangSearch(bang, searchQuery);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newUrl != null) {
|
|
||||||
if (isEditMode) {
|
|
||||||
// Load into existing tab
|
|
||||||
await ref
|
|
||||||
.read(
|
|
||||||
tabSessionProvider(tabId: tabId).notifier,
|
|
||||||
)
|
|
||||||
.loadUrl(url: newUrl);
|
|
||||||
} else {
|
|
||||||
// Create new tab
|
|
||||||
await ref
|
|
||||||
.read(tabRepositoryProvider.notifier)
|
|
||||||
.addTab(
|
|
||||||
url: newUrl,
|
|
||||||
tabMode: effectiveTabMode,
|
|
||||||
parentId:
|
|
||||||
(selectedTabType.value == TabType.child)
|
|
||||||
? ref.read(selectedTabProvider)
|
|
||||||
: null,
|
|
||||||
launchedFromIntent: launchedFromIntent,
|
|
||||||
selectTab: true,
|
|
||||||
containerSelection:
|
|
||||||
selectedContainer == null
|
|
||||||
? const TabContainerSelection.unassigned()
|
|
||||||
: TabContainerSelection.specific(
|
|
||||||
selectedContainer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
switch (classification) {
|
||||||
|
case NavigateInputClassification(:final uri):
|
||||||
|
newUrl = uri;
|
||||||
|
case SearchInputClassification(:final query):
|
||||||
|
searchQuery = query;
|
||||||
|
case InvalidInputClassification():
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ref
|
ui_helper.showErrorMessage(
|
||||||
.read(bottomSheetControllerProvider.notifier)
|
context,
|
||||||
.requestDismiss();
|
'Invalid address',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const BrowserRoute().go(context);
|
if (newUrl == null && searchQuery != null) {
|
||||||
|
// Read from both providers - use site if set, otherwise global
|
||||||
|
final siteBang = isEditMode
|
||||||
|
? ref.read(
|
||||||
|
selectedBangDataProvider(
|
||||||
|
domain: existingTabState.url.host,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
final globalBang = ref.read(
|
||||||
|
selectedBangDataProvider(),
|
||||||
|
);
|
||||||
|
final bang =
|
||||||
|
siteBang ??
|
||||||
|
globalBang ??
|
||||||
|
await ref.read(
|
||||||
|
defaultSearchBangDataProvider.future,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (bang != null) {
|
||||||
|
newUrl = bang.getTemplateUrl(searchQuery);
|
||||||
|
|
||||||
|
if (!privateTabMode) {
|
||||||
|
await ref
|
||||||
|
.read(bangSearchProvider.notifier)
|
||||||
|
.triggerBangSearch(bang, searchQuery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
activeBang: activeBang,
|
if (newUrl != null) {
|
||||||
showSuggestions: true,
|
if (isEditMode) {
|
||||||
),
|
// Load into existing tab
|
||||||
|
await ref
|
||||||
|
.read(tabSessionProvider(tabId: tabId).notifier)
|
||||||
|
.loadUrl(url: newUrl);
|
||||||
|
} else {
|
||||||
|
// Create new tab
|
||||||
|
await ref
|
||||||
|
.read(tabRepositoryProvider.notifier)
|
||||||
|
.addTab(
|
||||||
|
url: newUrl,
|
||||||
|
tabMode: effectiveTabMode,
|
||||||
|
parentId:
|
||||||
|
(selectedTabType.value == TabType.child)
|
||||||
|
? ref.read(selectedTabProvider)
|
||||||
|
: null,
|
||||||
|
launchedFromIntent: launchedFromIntent,
|
||||||
|
selectTab: true,
|
||||||
|
containerSelection: selectedContainer == null
|
||||||
|
? const TabContainerSelection.unassigned()
|
||||||
|
: TabContainerSelection.specific(
|
||||||
|
selectedContainer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
ref
|
||||||
|
.read(bottomSheetControllerProvider.notifier)
|
||||||
|
.requestDismiss();
|
||||||
|
|
||||||
|
const BrowserRoute().go(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeBang: activeBang,
|
||||||
|
showSuggestions: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -107,72 +107,91 @@ class SearchField extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AutoSuggestTextField(
|
final theme = Theme.of(context);
|
||||||
controller: textEditingController,
|
final colorScheme = theme.colorScheme;
|
||||||
suggestion: suggestion.value,
|
|
||||||
enableIMEPersonalizedLearning: !incognitoEnabled,
|
return Container(
|
||||||
focusNode: safeFocusNode,
|
margin: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
maxLines: maxLines,
|
decoration: BoxDecoration(
|
||||||
textFieldKey: textFieldKey,
|
color: colorScheme.surfaceContainerHigh,
|
||||||
textInputAction: (maxLines == null || maxLines! > 1)
|
borderRadius: BorderRadius.circular(16),
|
||||||
? TextInputAction.done
|
border: Border.all(color: colorScheme.outlineVariant),
|
||||||
: null,
|
|
||||||
minLines: minLines,
|
|
||||||
autofocus: autofocus,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
border: InputBorder.none,
|
|
||||||
prefixIcon: (showBangIcon && activeBang != null)
|
|
||||||
? Padding(
|
|
||||||
padding: const EdgeInsetsDirectional.all(12.0),
|
|
||||||
child: UrlIcon([activeBang!.getDefaultUrl()], iconSize: 24.0),
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
label: label,
|
|
||||||
hint: hint,
|
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.always,
|
|
||||||
suffixIcon: hasText
|
|
||||||
? IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
textEditingController.clear();
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.clear),
|
|
||||||
)
|
|
||||||
: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
QrScannerButton(
|
|
||||||
onScanResult: (scanResult) {
|
|
||||||
if (scanResult?.code != null) {
|
|
||||||
textEditingController.text = scanResult!.code!;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SpeechToTextButton(
|
|
||||||
onTextReceived: (data) {
|
|
||||||
textEditingController.text = data;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
onTapOutside: unfocusOnTapOutside
|
child: AutoSuggestTextField(
|
||||||
? (event) {
|
controller: textEditingController,
|
||||||
safeFocusNode.unfocus();
|
suggestion: suggestion.value,
|
||||||
}
|
enableIMEPersonalizedLearning: !incognitoEnabled,
|
||||||
: null,
|
focusNode: safeFocusNode,
|
||||||
onSubmitted: onSubmitted,
|
maxLines: maxLines,
|
||||||
onTap: () {
|
textFieldKey: textFieldKey,
|
||||||
if (suggestion.value != null) {
|
textInputAction: (maxLines == null || maxLines! > 1)
|
||||||
unawaited(HapticFeedback.lightImpact());
|
? TextInputAction.done
|
||||||
|
: null,
|
||||||
|
minLines: minLines,
|
||||||
|
autofocus: autofocus,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: const EdgeInsetsDirectional.fromSTEB(12, 12, 0, 12),
|
||||||
|
prefixIcon: (showBangIcon && activeBang != null)
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.all(12.0),
|
||||||
|
child: UrlIcon([activeBang!.getDefaultUrl()], iconSize: 24.0),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
label: label,
|
||||||
|
hint: hint,
|
||||||
|
floatingLabelBehavior: FloatingLabelBehavior.always,
|
||||||
|
suffixIconConstraints: const BoxConstraints(minHeight: 48),
|
||||||
|
suffixIcon: hasText
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(end: 8.0),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
textEditingController.clear();
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.clear),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.only(end: 8.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
QrScannerButton(
|
||||||
|
onScanResult: (scanResult) {
|
||||||
|
if (scanResult?.code != null) {
|
||||||
|
textEditingController.text = scanResult!.code!;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SpeechToTextButton(
|
||||||
|
onTextReceived: (data) {
|
||||||
|
textEditingController.text = data;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTapOutside: unfocusOnTapOutside
|
||||||
|
? (event) {
|
||||||
|
safeFocusNode.unfocus();
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
onSubmitted: onSubmitted,
|
||||||
|
onTap: () {
|
||||||
|
if (suggestion.value != null) {
|
||||||
|
unawaited(HapticFeedback.lightImpact());
|
||||||
|
|
||||||
textEditingController.text = suggestion.value!;
|
textEditingController.text = suggestion.value!;
|
||||||
textEditingController.selection = TextSelection.collapsed(
|
textEditingController.selection = TextSelection.collapsed(
|
||||||
offset: suggestion.value!.length,
|
offset: suggestion.value!.length,
|
||||||
);
|
);
|
||||||
|
|
||||||
suggestion.value = null;
|
suggestion.value = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user