support private tabs
This commit is contained in:
@@ -5,7 +5,10 @@ part of 'routes.dart';
|
||||
path: '/',
|
||||
routes: [
|
||||
TypedGoRoute<WebPageRoute>(name: 'WebPageRoute', path: 'page/:url'),
|
||||
TypedGoRoute<SearchRoute>(name: 'SearchRoute', path: 'search/:searchText'),
|
||||
TypedGoRoute<SearchRoute>(
|
||||
name: 'SearchRoute',
|
||||
path: 'search/:tabType/:searchText',
|
||||
),
|
||||
TypedGoRoute<TorProxyRoute>(name: 'TorProxyRoute', path: 'tor_proxy'),
|
||||
TypedGoRoute<ContextMenuRoute>(
|
||||
name: 'ContextMenuRoute',
|
||||
@@ -50,17 +53,25 @@ class WebPageRoute extends GoRouteData {
|
||||
}
|
||||
}
|
||||
|
||||
enum TabType { regular, private }
|
||||
|
||||
class SearchRoute extends GoRouteData {
|
||||
static const String emptySearchText = ' ';
|
||||
|
||||
final TabType tabType;
|
||||
|
||||
//This should be nullable but isnt allowed by go_router
|
||||
final String searchText;
|
||||
|
||||
const SearchRoute({this.searchText = SearchRoute.emptySearchText});
|
||||
const SearchRoute({
|
||||
required this.tabType,
|
||||
this.searchText = SearchRoute.emptySearchText,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, GoRouterState state) {
|
||||
return SearchScreen(
|
||||
tabType: tabType,
|
||||
initialSearchText:
|
||||
(searchText.isEmpty || searchText == emptySearchText)
|
||||
? null
|
||||
|
||||
@@ -214,7 +214,7 @@ RouteBase get $browserRoute => GoRouteData.$route(
|
||||
factory: $WebPageRouteExtension._fromState,
|
||||
),
|
||||
GoRouteData.$route(
|
||||
path: 'search/:searchText',
|
||||
path: 'search/:tabType/:searchText',
|
||||
name: 'SearchRoute',
|
||||
|
||||
factory: $SearchRouteExtension._fromState,
|
||||
@@ -292,12 +292,14 @@ extension $WebPageRouteExtension on WebPageRoute {
|
||||
|
||||
extension $SearchRouteExtension on SearchRoute {
|
||||
static SearchRoute _fromState(GoRouterState state) => SearchRoute(
|
||||
tabType: _$TabTypeEnumMap._$fromName(state.pathParameters['tabType']!)!,
|
||||
searchText:
|
||||
state.pathParameters['searchText'] ?? SearchRoute.emptySearchText,
|
||||
);
|
||||
|
||||
String get location =>
|
||||
GoRouteData.$location('/search/${Uri.encodeComponent(searchText)}');
|
||||
String get location => GoRouteData.$location(
|
||||
'/search/${Uri.encodeComponent(_$TabTypeEnumMap[tabType]!)}/${Uri.encodeComponent(searchText)}',
|
||||
);
|
||||
|
||||
void go(BuildContext context) => context.go(location);
|
||||
|
||||
@@ -309,6 +311,11 @@ extension $SearchRouteExtension on SearchRoute {
|
||||
void replace(BuildContext context) => context.replace(location);
|
||||
}
|
||||
|
||||
const _$TabTypeEnumMap = {
|
||||
TabType.regular: 'regular',
|
||||
TabType.private: 'private',
|
||||
};
|
||||
|
||||
extension $TorProxyRouteExtension on TorProxyRoute {
|
||||
static TorProxyRoute _fromState(GoRouterState state) => TorProxyRoute();
|
||||
|
||||
@@ -394,6 +401,11 @@ extension $ContainerEditRouteExtension on ContainerEditRoute {
|
||||
context.replace(location, extra: $extra);
|
||||
}
|
||||
|
||||
extension<T extends Enum> on Map<T, String> {
|
||||
T? _$fromName(String? value) =>
|
||||
entries.where((element) => element.value == value).firstOrNull?.key;
|
||||
}
|
||||
|
||||
RouteBase get $bangCategoriesRoute => GoRouteData.$route(
|
||||
path: '/bangs',
|
||||
name: 'BangRoute',
|
||||
|
||||
@@ -41,7 +41,7 @@ class BangListScreen extends HookConsumerWidget {
|
||||
.read(selectedBangTriggerProvider().notifier)
|
||||
.setTrigger(bang.trigger);
|
||||
|
||||
const SearchRoute().go(context);
|
||||
const SearchRoute(tabType: TabType.regular).go(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers/search.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_session.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/browser/domain/providers.dart';
|
||||
import 'package:lensai/features/geckoview/features/search/domain/providers/search_suggestions.dart';
|
||||
@@ -45,12 +46,21 @@ class SiteSearch extends HookConsumerWidget {
|
||||
|
||||
Future<void> submitSearch(String query) async {
|
||||
if (activeBang != null && (formKey.currentState?.validate() == true)) {
|
||||
final searchUri = await ref
|
||||
.read(bangSearchProvider.notifier)
|
||||
.triggerBangSearch(activeBang, query);
|
||||
final isPrivate =
|
||||
ref.read(selectedTabStateProvider)?.isPrivate ?? false;
|
||||
|
||||
final searchUri = activeBang.getTemplateUrl(query);
|
||||
|
||||
if (!isPrivate) {
|
||||
await ref
|
||||
.read(bangSearchProvider.notifier)
|
||||
.triggerBangSearch(activeBang, query);
|
||||
}
|
||||
|
||||
if (searchInNewTab) {
|
||||
await ref.read(tabRepositoryProvider.notifier).addTab(url: searchUri);
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: searchUri, private: isPrivate);
|
||||
} else {
|
||||
await ref
|
||||
.read(tabSessionProvider(tabId: null).notifier)
|
||||
|
||||
@@ -3,7 +3,7 @@ import 'dart:async';
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:lensai/core/logger.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers/bangs.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:riverpod/riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
@@ -24,13 +24,14 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
|
||||
);
|
||||
|
||||
if (defaultSearchBang != null) {
|
||||
final currentTabId = ref.read(selectedTabProvider);
|
||||
final currentTab = ref.read(selectedTabStateProvider);
|
||||
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(
|
||||
url: defaultSearchBang.getTemplateUrl(text),
|
||||
parentId: currentTabId,
|
||||
parentId: currentTab?.id,
|
||||
private: currentTab?.isPrivate ?? false,
|
||||
);
|
||||
} else {
|
||||
logger.e('No default search bang found');
|
||||
@@ -50,7 +51,7 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
|
||||
// }
|
||||
// }),
|
||||
ShareAction((text) async {
|
||||
await Share.share(text);
|
||||
await SharePlus.instance.share(ShareParams(text: text));
|
||||
}),
|
||||
CallAction((text) async {
|
||||
final uri = Uri.tryParse('tel:${text.replaceAll(' ', '')}');
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'providers.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$selectionActionServiceHash() =>
|
||||
r'd907a3c5ab7efde82bb2cc1fb0409fd3fd13bb25';
|
||||
r'fc7344fa34f0e27772309303083804866336197b';
|
||||
|
||||
/// See also [selectionActionService].
|
||||
@ProviderFor(selectionActionService)
|
||||
|
||||
@@ -161,6 +161,31 @@ class WebPageDialog extends HookConsumerWidget {
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(MdiIcons.tabUnselected),
|
||||
title: const Text('Clone as private tab'),
|
||||
onTap: () async {
|
||||
final tabId = await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: url, private: true);
|
||||
|
||||
if (context.mounted) {
|
||||
//save reference before pop `ref` gets disposed
|
||||
final repo = ref.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
);
|
||||
|
||||
ui_helper.showTabSwitchMessage(
|
||||
context,
|
||||
onSwitch: () {
|
||||
repo.selectTab(tabId);
|
||||
},
|
||||
);
|
||||
|
||||
context.pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.share),
|
||||
title: const Text('Share link'),
|
||||
|
||||
+16
-3
@@ -106,7 +106,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
return child!;
|
||||
},
|
||||
menuChildren: [
|
||||
if (selectedTabId != null)
|
||||
if (selectedTabId != null) ...[
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
@@ -116,11 +116,24 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
child: const Text('Close Tab'),
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await const SearchRoute().push(context);
|
||||
await const SearchRoute(
|
||||
tabType: TabType.private,
|
||||
).push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.add),
|
||||
leadingIcon: const Icon(MdiIcons.tabUnselected),
|
||||
child: const Text('Add Private Tab'),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await const SearchRoute(
|
||||
tabType: TabType.regular,
|
||||
).push(context);
|
||||
},
|
||||
leadingIcon: const Icon(MdiIcons.tabPlus),
|
||||
child: const Text('Add Tab'),
|
||||
),
|
||||
],
|
||||
|
||||
+1
-1
@@ -210,7 +210,7 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
||||
showSuggestNewTabMessage(
|
||||
context,
|
||||
onAdd: () async {
|
||||
await const SearchRoute().push(context);
|
||||
await const SearchRoute(tabType: TabType.regular).push(context);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import 'dart:math' as math;
|
||||
import 'package:collection/collection.dart';
|
||||
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:flutter_reorderable_grid_view/widgets/widgets.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/core/providers/global_drop.dart';
|
||||
@@ -62,7 +63,7 @@ class _TabSheetHeader extends HookConsumerWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.search),
|
||||
icon: const Icon(MdiIcons.tabSearch),
|
||||
label: const Text('Search'),
|
||||
onPressed: () {
|
||||
searchMode.value = true;
|
||||
@@ -410,7 +411,7 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
||||
),
|
||||
child: FloatingActionButton.small(
|
||||
onPressed: () async {
|
||||
await const SearchRoute().push(context);
|
||||
await const SearchRoute(tabType: TabType.regular).push(context);
|
||||
|
||||
onClose();
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/geckoview/domain/entities/states/tab.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
@@ -34,10 +35,13 @@ class TabPreview extends StatelessWidget {
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
),
|
||||
child: Material(
|
||||
color: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
color:
|
||||
tab.isPrivate
|
||||
? const Color(0xFF25003E)
|
||||
: colorScheme.surfaceContainerHighest,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(14.0)),
|
||||
child: InkWell(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(14.0)),
|
||||
onTap: onTap,
|
||||
onDoubleTap: onDoubleTap,
|
||||
child: Column(
|
||||
@@ -46,11 +50,15 @@ class TabPreview extends StatelessWidget {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 6.0),
|
||||
padding: const EdgeInsets.only(left: 6.0, top: 2.0),
|
||||
child: Text(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
tab.title,
|
||||
maxLines: 2,
|
||||
style:
|
||||
tab.isPrivate
|
||||
? const TextStyle(color: Colors.white)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -72,9 +80,16 @@ class TabPreview extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Text(
|
||||
tab.url.authority,
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: tab.isPrivate ? Colors.white : null,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (tab.isPrivate) ...[
|
||||
const SizedBox(width: 6.0),
|
||||
const Icon(MdiIcons.dominoMask, color: Color(0xFF8000D7)),
|
||||
],
|
||||
const SizedBox(width: 8.0),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
@@ -82,8 +97,8 @@ class TabPreview extends StatelessWidget {
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(16.0),
|
||||
bottomRight: Radius.circular(16.0),
|
||||
bottomLeft: Radius.circular(14.0),
|
||||
bottomRight: Radius.circular(14.0),
|
||||
),
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
|
||||
+4
-3
@@ -3,7 +3,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/contextmenu/extensions/hit_result.dart';
|
||||
import 'package:lensai/utils/ui_helper.dart';
|
||||
@@ -23,14 +23,15 @@ class OpenImageInNewTab extends HookConsumerWidget {
|
||||
leading: const Icon(MdiIcons.tabPlus),
|
||||
title: const Text('Open image in new tab'),
|
||||
onTap: () async {
|
||||
final currentTabId = ref.read(selectedTabProvider);
|
||||
final currentTab = ref.read(selectedTabStateProvider);
|
||||
|
||||
final tabId = await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(
|
||||
url: hitResult.tryGetLink(),
|
||||
parentId: currentTabId,
|
||||
parentId: currentTab?.id,
|
||||
selectTab: false,
|
||||
private: currentTab?.isPrivate ?? false,
|
||||
);
|
||||
|
||||
if (context.mounted) {
|
||||
|
||||
+4
-3
@@ -3,7 +3,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart';
|
||||
import 'package:lensai/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:lensai/features/geckoview/domain/repositories/tab.dart';
|
||||
import 'package:lensai/features/geckoview/features/contextmenu/extensions/hit_result.dart';
|
||||
import 'package:lensai/utils/ui_helper.dart';
|
||||
@@ -23,14 +23,15 @@ class OpenInNewTab extends HookConsumerWidget {
|
||||
leading: const Icon(MdiIcons.tabPlus),
|
||||
title: const Text('Open in new tab'),
|
||||
onTap: () async {
|
||||
final currentTabId = ref.read(selectedTabProvider);
|
||||
final currentTab = ref.read(selectedTabStateProvider);
|
||||
|
||||
final tabId = await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(
|
||||
url: hitResult.tryGetLink(),
|
||||
parentId: currentTabId,
|
||||
parentId: currentTab?.id,
|
||||
selectTab: false,
|
||||
private: currentTab?.isPrivate ?? false,
|
||||
);
|
||||
|
||||
if (context.mounted) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
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:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:lensai/core/routing/routes.dart';
|
||||
import 'package:lensai/features/bangs/data/models/bang_data.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers/bangs.dart';
|
||||
import 'package:lensai/features/bangs/domain/providers/search.dart';
|
||||
@@ -18,13 +20,17 @@ import 'package:lensai/utils/uri_parser.dart' as uri_parser;
|
||||
|
||||
class SearchScreen extends HookConsumerWidget {
|
||||
final String? initialSearchText;
|
||||
final TabType tabType;
|
||||
|
||||
const SearchScreen({required this.initialSearchText});
|
||||
const SearchScreen({required this.initialSearchText, required this.tabType});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||
|
||||
final selectedTabType = useState(tabType);
|
||||
final isPrivate = selectedTabType.value == TabType.private;
|
||||
|
||||
final searchTextController = useTextEditingController(
|
||||
text: initialSearchText,
|
||||
);
|
||||
@@ -52,11 +58,17 @@ class SearchScreen extends HookConsumerWidget {
|
||||
|
||||
Future<void> submitSearch(String query) async {
|
||||
if (activeBang != null && (formKey.currentState?.validate() == true)) {
|
||||
final searchUri = await ref
|
||||
.read(bangSearchProvider.notifier)
|
||||
.triggerBangSearch(activeBang, query);
|
||||
final searchUri = activeBang.getTemplateUrl(query);
|
||||
|
||||
await ref.read(tabRepositoryProvider.notifier).addTab(url: searchUri);
|
||||
if (!isPrivate) {
|
||||
await ref
|
||||
.read(bangSearchProvider.notifier)
|
||||
.triggerBangSearch(activeBang, query);
|
||||
}
|
||||
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: searchUri, private: isPrivate);
|
||||
|
||||
if (context.mounted) {
|
||||
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||
@@ -75,43 +87,72 @@ class SearchScreen extends HookConsumerWidget {
|
||||
floating: true,
|
||||
pinned: true,
|
||||
automaticallyImplyLeading: false,
|
||||
title: SearchField(
|
||||
showBangIcon: showBangIcon.value,
|
||||
textEditingController: searchTextController,
|
||||
focusNode: searchFocusNode,
|
||||
autofocus: true,
|
||||
onSubmitted: (value) async {
|
||||
if (value.isNotEmpty) {
|
||||
var newUrl = uri_parser.tryParseUrl(
|
||||
value,
|
||||
eagerParsing: true,
|
||||
);
|
||||
title: Align(
|
||||
child: SegmentedButton(
|
||||
showSelectedIcon: false,
|
||||
segments: const [
|
||||
ButtonSegment(
|
||||
value: TabType.regular,
|
||||
label: Text('Regular'),
|
||||
icon: Icon(MdiIcons.tab),
|
||||
),
|
||||
ButtonSegment(
|
||||
value: TabType.private,
|
||||
label: Text('Private'),
|
||||
icon: Icon(MdiIcons.tabUnselected),
|
||||
),
|
||||
],
|
||||
selected: {selectedTabType.value},
|
||||
onSelectionChanged: (value) {
|
||||
selectedTabType.value = value.first;
|
||||
},
|
||||
),
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(kToolbarHeight),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 16.0),
|
||||
child: SearchField(
|
||||
showBangIcon: showBangIcon.value,
|
||||
textEditingController: searchTextController,
|
||||
focusNode: searchFocusNode,
|
||||
autofocus: true,
|
||||
onSubmitted: (value) async {
|
||||
if (value.isNotEmpty) {
|
||||
var newUrl = uri_parser.tryParseUrl(
|
||||
value,
|
||||
eagerParsing: true,
|
||||
);
|
||||
|
||||
if (newUrl == null) {
|
||||
final defaultSearchBang =
|
||||
ref.read(selectedBangDataProvider()) ??
|
||||
await ref.read(defaultSearchBangDataProvider.future);
|
||||
if (newUrl == null) {
|
||||
final defaultSearchBang =
|
||||
ref.read(selectedBangDataProvider()) ??
|
||||
await ref.read(
|
||||
defaultSearchBangDataProvider.future,
|
||||
);
|
||||
|
||||
newUrl = defaultSearchBang?.getTemplateUrl(value);
|
||||
}
|
||||
newUrl = defaultSearchBang?.getTemplateUrl(value);
|
||||
}
|
||||
|
||||
if (newUrl != null) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: newUrl);
|
||||
if (newUrl != null) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: newUrl, private: isPrivate);
|
||||
|
||||
if (context.mounted) {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.dismiss();
|
||||
if (context.mounted) {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.dismiss();
|
||||
|
||||
context.pop();
|
||||
context.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
activeBang: activeBang,
|
||||
showSuggestions: true,
|
||||
},
|
||||
activeBang: activeBang,
|
||||
showSuggestions: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SliverToBoxAdapter(child: Divider()),
|
||||
@@ -120,10 +161,12 @@ class SearchScreen extends HookConsumerWidget {
|
||||
activeBang: activeBang,
|
||||
submitSearch: submitSearch,
|
||||
),
|
||||
const SliverToBoxAdapter(child: Divider()),
|
||||
TabSearch(searchTextListenable: sampledSearchText),
|
||||
FeedSearch(searchTextNotifier: sampledSearchText),
|
||||
HistorySuggestions(searchTextListenable: sampledSearchText),
|
||||
HistorySuggestions(
|
||||
isPrivate: isPrivate,
|
||||
searchTextListenable: sampledSearchText,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
+7
-2
@@ -15,9 +15,14 @@ import 'package:skeletonizer/skeletonizer.dart';
|
||||
import 'package:sliver_tools/sliver_tools.dart';
|
||||
|
||||
class HistorySuggestions extends HookConsumerWidget {
|
||||
final bool isPrivate;
|
||||
final ValueListenable<TextEditingValue> searchTextListenable;
|
||||
|
||||
const HistorySuggestions({super.key, required this.searchTextListenable});
|
||||
const HistorySuggestions({
|
||||
super.key,
|
||||
required this.isPrivate,
|
||||
required this.searchTextListenable,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -89,7 +94,7 @@ class HistorySuggestions extends HookConsumerWidget {
|
||||
case final Uri url) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.addTab(url: url);
|
||||
.addTab(url: url, private: isPrivate);
|
||||
|
||||
if (context.mounted) {
|
||||
ref
|
||||
|
||||
Reference in New Issue
Block a user