improve search flow
This commit is contained in:
+36
-15
@@ -23,7 +23,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:weblibre/core/design/app_colors.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||
@@ -844,16 +843,27 @@ class SingleGridTabPreview extends HookConsumerWidget {
|
||||
depth: depth,
|
||||
onTap: () async {
|
||||
if (tabId != activeTabId) {
|
||||
// Offer to locate the match within the page instead of opening
|
||||
// Find in Page unprompted (see #421). Shown before onClose so it
|
||||
// surfaces on the root messenger and survives the tray closing.
|
||||
final query = sourceSearchQuery;
|
||||
if (query != null &&
|
||||
query.isNotEmpty &&
|
||||
ref.read(findInPageControllerProvider(tabId)) ==
|
||||
FindInPageState.hidden()) {
|
||||
final findController = ref.read(
|
||||
findInPageControllerProvider(tabId).notifier,
|
||||
);
|
||||
ui_helper.showFindInPageSuggestion(
|
||||
context,
|
||||
query: query,
|
||||
onFind: () => findController.findAll(text: query),
|
||||
);
|
||||
}
|
||||
|
||||
//Close first to avoid rebuilds
|
||||
onClose();
|
||||
await ref.read(tabRepositoryProvider.notifier).selectTab(tabId);
|
||||
if (sourceSearchQuery.isNotEmpty &&
|
||||
ref.read(findInPageControllerProvider(tabId)) ==
|
||||
FindInPageState.hidden()) {
|
||||
await ref
|
||||
.read(findInPageControllerProvider(tabId).notifier)
|
||||
.findAll(text: sourceSearchQuery!);
|
||||
}
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
@@ -989,16 +999,27 @@ class SingleListTabPreview extends HookConsumerWidget {
|
||||
depth: depth,
|
||||
onTap: () async {
|
||||
if (tabId != activeTabId) {
|
||||
// Offer to locate the match within the page instead of opening
|
||||
// Find in Page unprompted (see #421). Shown before onClose so it
|
||||
// surfaces on the root messenger and survives the tray closing.
|
||||
final query = sourceSearchQuery;
|
||||
if (query != null &&
|
||||
query.isNotEmpty &&
|
||||
ref.read(findInPageControllerProvider(tabId)) ==
|
||||
FindInPageState.hidden()) {
|
||||
final findController = ref.read(
|
||||
findInPageControllerProvider(tabId).notifier,
|
||||
);
|
||||
ui_helper.showFindInPageSuggestion(
|
||||
context,
|
||||
query: query,
|
||||
onFind: () => findController.findAll(text: query),
|
||||
);
|
||||
}
|
||||
|
||||
//Close first to avoid rebuilds
|
||||
onClose();
|
||||
await ref.read(tabRepositoryProvider.notifier).selectTab(tabId);
|
||||
if (sourceSearchQuery.isNotEmpty &&
|
||||
ref.read(findInPageControllerProvider(tabId)) ==
|
||||
FindInPageState.hidden()) {
|
||||
await ref
|
||||
.read(findInPageControllerProvider(tabId).notifier)
|
||||
.findAll(text: sourceSearchQuery!);
|
||||
}
|
||||
} else {
|
||||
onClose();
|
||||
}
|
||||
|
||||
+23
@@ -17,6 +17,7 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
@@ -268,6 +269,28 @@ class TabViewHeader extends HookConsumerWidget {
|
||||
return null;
|
||||
}, [tabsReorderable, canManualReorder]);
|
||||
|
||||
// Keep the in-place tab filter in lockstep with the search field. The
|
||||
// preview query lives in a provider whose lifetime is independent of this
|
||||
// header and of [searchMode], so it can outlive the search UI and leave the
|
||||
// tab list filtered with no visible search box (#421). Whenever we are not
|
||||
// searching, drop any lingering query so all tabs are shown again.
|
||||
useEffect(() {
|
||||
if (!searchMode.value &&
|
||||
ref.exists(
|
||||
tabSearchRepositoryProvider(TabSearchPartition.preview),
|
||||
)) {
|
||||
unawaited(
|
||||
ref
|
||||
.read(
|
||||
tabSearchRepositoryProvider(TabSearchPartition.preview).notifier,
|
||||
)
|
||||
.addQuery(''),
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [searchMode.value]);
|
||||
|
||||
useOnListenableChange(searchTextController, () async {
|
||||
if (ref.exists(tabSearchRepositoryProvider(TabSearchPartition.preview))) {
|
||||
await ref
|
||||
|
||||
+17
-7
@@ -45,6 +45,7 @@ import 'package:weblibre/presentation/widgets/safe_raw_image.dart';
|
||||
import 'package:weblibre/presentation/widgets/uri_breadcrumb.dart';
|
||||
import 'package:weblibre/presentation/widgets/url_icon.dart';
|
||||
import 'package:weblibre/utils/text_highlight.dart';
|
||||
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||
|
||||
class TabSearch extends HookConsumerWidget {
|
||||
static const _matchPrefix = '***';
|
||||
@@ -247,14 +248,23 @@ class TabSearch extends HookConsumerWidget {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectTab(result.id);
|
||||
if (result.sourceSearchQuery.isNotEmpty &&
|
||||
|
||||
// Offer to locate the match within the page instead of
|
||||
// opening Find in Page unprompted (see #421).
|
||||
final query = result.sourceSearchQuery;
|
||||
if (query != null &&
|
||||
query.isNotEmpty &&
|
||||
ref.read(findInPageControllerProvider(result.id)) ==
|
||||
FindInPageState.hidden()) {
|
||||
await ref
|
||||
.read(
|
||||
findInPageControllerProvider(result.id).notifier,
|
||||
)
|
||||
.findAll(text: result.sourceSearchQuery!);
|
||||
FindInPageState.hidden() &&
|
||||
context.mounted) {
|
||||
final findController = ref.read(
|
||||
findInPageControllerProvider(result.id).notifier,
|
||||
);
|
||||
ui_helper.showFindInPageSuggestion(
|
||||
context,
|
||||
query: query,
|
||||
onFind: () => findController.findAll(text: query),
|
||||
);
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
|
||||
@@ -101,6 +101,27 @@ void showInfoMessage(
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
void showFindInPageSuggestion(
|
||||
BuildContext context, {
|
||||
required String query,
|
||||
required VoidCallback onFind,
|
||||
Duration duration = const Duration(seconds: 5),
|
||||
bool persist = false,
|
||||
}) {
|
||||
final snackBar = _createFloatingSnackBar(
|
||||
content: Text(
|
||||
'Find "${_truncateForSnackBar(query)}" on this page?',
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
action: SnackBarAction(label: 'Find', onPressed: onFind),
|
||||
duration: duration,
|
||||
persist: persist,
|
||||
);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
void showOpenedTabsFromAnotherDeviceMessage(
|
||||
BuildContext context,
|
||||
int openedTabs, {
|
||||
|
||||
Reference in New Issue
Block a user