possibility to inject child tabs
This commit is contained in:
@@ -57,7 +57,7 @@ class WebPageRoute extends GoRouteData with _$WebPageRoute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TabType { regular, private }
|
enum TabType { regular, private, child }
|
||||||
|
|
||||||
class SearchRoute extends GoRouteData with _$SearchRoute {
|
class SearchRoute extends GoRouteData with _$SearchRoute {
|
||||||
static const String emptySearchText = ' ';
|
static const String emptySearchText = ' ';
|
||||||
|
|||||||
@@ -388,6 +388,7 @@ mixin _$SearchRoute on GoRouteData {
|
|||||||
const _$TabTypeEnumMap = {
|
const _$TabTypeEnumMap = {
|
||||||
TabType.regular: 'regular',
|
TabType.regular: 'regular',
|
||||||
TabType.private: 'private',
|
TabType.private: 'private',
|
||||||
|
TabType.child: 'child',
|
||||||
};
|
};
|
||||||
|
|
||||||
mixin _$TorProxyRoute on GoRouteData {
|
mixin _$TorProxyRoute on GoRouteData {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:nullability/nullability.dart';
|
|||||||
import 'package:weblibre/core/routing/routes.dart';
|
import 'package:weblibre/core/routing/routes.dart';
|
||||||
import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
|
import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
|
||||||
import 'package:weblibre/features/bangs/presentation/widgets/bang_details.dart';
|
import 'package:weblibre/features/bangs/presentation/widgets/bang_details.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart';
|
||||||
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
import 'package:weblibre/presentation/widgets/failure_widget.dart';
|
||||||
|
|
||||||
@@ -41,7 +42,11 @@ class BangListScreen extends HookConsumerWidget {
|
|||||||
.read(selectedBangTriggerProvider().notifier)
|
.read(selectedBangTriggerProvider().notifier)
|
||||||
.setTrigger(bang.trigger);
|
.setTrigger(bang.trigger);
|
||||||
|
|
||||||
const SearchRoute(tabType: TabType.regular).go(context);
|
SearchRoute(
|
||||||
|
tabType:
|
||||||
|
ref.read(selectedTabTypeProvider) ??
|
||||||
|
TabType.regular,
|
||||||
|
).go(context);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,10 +23,8 @@ GeckoSelectionActionService selectionActionService(Ref ref) {
|
|||||||
service.setActions([
|
service.setActions([
|
||||||
SearchAction((text) async {
|
SearchAction((text) async {
|
||||||
final router = await ref.read(routerProvider.future);
|
final router = await ref.read(routerProvider.future);
|
||||||
final isCurrentPrivate =
|
|
||||||
ref.read(selectedTabStateProvider)?.isPrivate ?? false;
|
|
||||||
final route = SearchRoute(
|
final route = SearchRoute(
|
||||||
tabType: isCurrentPrivate ? TabType.private : TabType.regular,
|
tabType: ref.read(selectedTabTypeProvider) ?? TabType.regular,
|
||||||
searchText: text,
|
searchText: text,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'providers.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$selectionActionServiceHash() =>
|
String _$selectionActionServiceHash() =>
|
||||||
r'456bab83920ae78969bece514d5524e2445e06b6';
|
r'a3682b3f97d9798aadbca3be882d5be74085b762';
|
||||||
|
|
||||||
/// See also [selectionActionService].
|
/// See also [selectionActionService].
|
||||||
@ProviderFor(selectionActionService)
|
@ProviderFor(selectionActionService)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import 'package:riverpod/riverpod.dart';
|
|||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:weblibre/core/logger.dart';
|
import 'package:weblibre/core/logger.dart';
|
||||||
|
import 'package:weblibre/core/routing/routes.dart';
|
||||||
import 'package:weblibre/features/geckoview/domain/entities/states/find_result.dart';
|
import 'package:weblibre/features/geckoview/domain/entities/states/find_result.dart';
|
||||||
import 'package:weblibre/features/geckoview/domain/entities/states/history.dart';
|
import 'package:weblibre/features/geckoview/domain/entities/states/history.dart';
|
||||||
import 'package:weblibre/features/geckoview/domain/entities/states/readerable.dart';
|
import 'package:weblibre/features/geckoview/domain/entities/states/readerable.dart';
|
||||||
@@ -204,3 +205,14 @@ TabState? selectedTabState(Ref ref) {
|
|||||||
final tabId = ref.watch(selectedTabProvider);
|
final tabId = ref.watch(selectedTabProvider);
|
||||||
return ref.watch(tabStateProvider(tabId));
|
return ref.watch(tabStateProvider(tabId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Riverpod()
|
||||||
|
TabType? selectedTabType(Ref ref) {
|
||||||
|
final isPrivate = ref.watch(
|
||||||
|
selectedTabStateProvider.select((value) => value?.isPrivate),
|
||||||
|
);
|
||||||
|
|
||||||
|
return isPrivate.mapNotNull(
|
||||||
|
(isCurrentPrivate) => isCurrentPrivate ? TabType.private : TabType.regular,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -158,6 +158,23 @@ final selectedTabStateProvider = AutoDisposeProvider<TabState?>.internal(
|
|||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
typedef SelectedTabStateRef = AutoDisposeProviderRef<TabState?>;
|
||||||
|
String _$selectedTabTypeHash() => r'53093fc6db8becde7500163661e087fb0a2eb955';
|
||||||
|
|
||||||
|
/// See also [selectedTabType].
|
||||||
|
@ProviderFor(selectedTabType)
|
||||||
|
final selectedTabTypeProvider = AutoDisposeProvider<TabType?>.internal(
|
||||||
|
selectedTabType,
|
||||||
|
name: r'selectedTabTypeProvider',
|
||||||
|
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$selectedTabTypeHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
typedef SelectedTabTypeRef = AutoDisposeProviderRef<TabType?>;
|
||||||
String _$tabStatesHash() => r'e4d2f2b4ddd65beac8a1fd0d22bad1e0a26b41bd';
|
String _$tabStatesHash() => r'e4d2f2b4ddd65beac8a1fd0d22bad1e0a26b41bd';
|
||||||
|
|
||||||
/// See also [TabStates].
|
/// See also [TabStates].
|
||||||
|
|||||||
+3
-36
@@ -17,6 +17,7 @@ import 'package:weblibre/features/geckoview/features/browser/domain/entities/she
|
|||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart';
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/browser_modules/app_bar_title.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/edit_url_dialog.dart';
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/edit_url_dialog.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart';
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_creation_menu.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart';
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart';
|
import 'package:weblibre/features/geckoview/features/find_in_page/presentation/controllers/find_in_page.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
|
import 'package:weblibre/features/geckoview/features/readerview/presentation/widgets/reader_button.dart';
|
||||||
@@ -95,43 +96,9 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
|||||||
actions: [
|
actions: [
|
||||||
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
||||||
ReaderButton(),
|
ReaderButton(),
|
||||||
MenuAnchor(
|
TabCreationMenu(
|
||||||
controller: tabMenuController,
|
controller: tabMenuController,
|
||||||
builder: (context, controller, child) {
|
selectedTabId: selectedTabId,
|
||||||
return child!;
|
|
||||||
},
|
|
||||||
menuChildren: [
|
|
||||||
if (selectedTabId != null) ...[
|
|
||||||
MenuItemButton(
|
|
||||||
onPressed: () async {
|
|
||||||
await ref
|
|
||||||
.read(tabRepositoryProvider.notifier)
|
|
||||||
.closeTab(selectedTabId);
|
|
||||||
},
|
|
||||||
leadingIcon: const Icon(Icons.close),
|
|
||||||
child: const Text('Close Tab'),
|
|
||||||
),
|
|
||||||
const Divider(),
|
|
||||||
],
|
|
||||||
MenuItemButton(
|
|
||||||
onPressed: () async {
|
|
||||||
await const SearchRoute(
|
|
||||||
tabType: TabType.private,
|
|
||||||
).push(context);
|
|
||||||
},
|
|
||||||
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'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: TabsActionButton(
|
child: TabsActionButton(
|
||||||
isActive: displayedSheet is ViewTabsSheet,
|
isActive: displayedSheet is ViewTabsSheet,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|||||||
+2
-1
@@ -299,7 +299,8 @@ class _BrowserViewState extends ConsumerState<BrowserView>
|
|||||||
context,
|
context,
|
||||||
onAdd: (searchText) async {
|
onAdd: (searchText) async {
|
||||||
await SearchRoute(
|
await SearchRoute(
|
||||||
tabType: TabType.regular,
|
tabType:
|
||||||
|
ref.read(selectedTabTypeProvider) ?? TabType.regular,
|
||||||
searchText: searchText ?? SearchRoute.emptySearchText,
|
searchText: searchText ?? SearchRoute.emptySearchText,
|
||||||
).push(context);
|
).push(context);
|
||||||
},
|
},
|
||||||
|
|||||||
+3
-7
@@ -79,7 +79,7 @@ class _TabSheetHeader extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(MdiIcons.graph),
|
icon: const Icon(MdiIcons.familyTree),
|
||||||
selectedIcon: const Icon(MdiIcons.table),
|
selectedIcon: const Icon(MdiIcons.table),
|
||||||
isSelected: treeViewEnabled,
|
isSelected: treeViewEnabled,
|
||||||
iconSize: 18,
|
iconSize: 18,
|
||||||
@@ -443,10 +443,8 @@ class ViewTabsSheetWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
child: FloatingActionButton.small(
|
child: FloatingActionButton.small(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final isCurrentPrivate =
|
|
||||||
ref.read(selectedTabStateProvider)?.isPrivate ?? false;
|
|
||||||
await SearchRoute(
|
await SearchRoute(
|
||||||
tabType: isCurrentPrivate ? TabType.private : TabType.regular,
|
tabType: ref.read(selectedTabTypeProvider) ?? TabType.regular,
|
||||||
).push(context);
|
).push(context);
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
@@ -618,10 +616,8 @@ class ViewTabTreesSheetWidget extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
child: FloatingActionButton.small(
|
child: FloatingActionButton.small(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final isCurrentPrivate =
|
|
||||||
ref.read(selectedTabStateProvider)?.isPrivate ?? false;
|
|
||||||
await SearchRoute(
|
await SearchRoute(
|
||||||
tabType: isCurrentPrivate ? TabType.private : TabType.regular,
|
tabType: ref.read(selectedTabTypeProvider) ?? TabType.regular,
|
||||||
).push(context);
|
).push(context);
|
||||||
|
|
||||||
onClose();
|
onClose();
|
||||||
|
|||||||
+72
@@ -0,0 +1,72 @@
|
|||||||
|
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:weblibre/core/routing/routes.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
|
|
||||||
|
class TabCreationMenu extends HookConsumerWidget {
|
||||||
|
final Widget child;
|
||||||
|
final MenuController controller;
|
||||||
|
final String? selectedTabId;
|
||||||
|
|
||||||
|
const TabCreationMenu({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
required this.controller,
|
||||||
|
required this.selectedTabId,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final createChildTabsOption = ref.watch(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(value) => value.createChildTabsOption,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return MenuAnchor(
|
||||||
|
controller: controller,
|
||||||
|
builder: (context, controller, child) {
|
||||||
|
return child!;
|
||||||
|
},
|
||||||
|
menuChildren: [
|
||||||
|
if (selectedTabId != null) ...[
|
||||||
|
MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await ref
|
||||||
|
.read(tabRepositoryProvider.notifier)
|
||||||
|
.closeTab(selectedTabId!);
|
||||||
|
},
|
||||||
|
leadingIcon: const Icon(Icons.close),
|
||||||
|
child: const Text('Close Tab'),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await const SearchRoute(tabType: TabType.regular).push(context);
|
||||||
|
},
|
||||||
|
leadingIcon: const Icon(MdiIcons.tabPlus),
|
||||||
|
child: const Text('Add Regular Tab'),
|
||||||
|
),
|
||||||
|
MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await const SearchRoute(tabType: TabType.private).push(context);
|
||||||
|
},
|
||||||
|
leadingIcon: const Icon(MdiIcons.tabUnselected),
|
||||||
|
child: const Text('Add Private Tab'),
|
||||||
|
),
|
||||||
|
if (createChildTabsOption)
|
||||||
|
MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
await const SearchRoute(tabType: TabType.child).push(context);
|
||||||
|
},
|
||||||
|
leadingIcon: const Icon(MdiIcons.fileTree),
|
||||||
|
child: const Text('Add Child Tab'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ import 'package:weblibre/features/bangs/data/models/bang_data.dart';
|
|||||||
import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
|
import 'package:weblibre/features/bangs/domain/providers/bangs.dart';
|
||||||
import 'package:weblibre/features/bangs/domain/providers/search.dart';
|
import 'package:weblibre/features/bangs/domain/providers/search.dart';
|
||||||
import 'package:weblibre/features/geckoview/domain/controllers/bottom_sheet.dart';
|
import 'package:weblibre/features/geckoview/domain/controllers/bottom_sheet.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||||
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
|
import 'package:weblibre/features/geckoview/domain/repositories/tab.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/features/browser/domain/providers.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/clipboard_fill.dart';
|
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/clipboard_fill.dart';
|
||||||
@@ -16,6 +18,7 @@ import 'package:weblibre/features/geckoview/features/search/presentation/widgets
|
|||||||
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart';
|
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/search_modules/history_suggestions.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/search_modules/search_suggestions.dart';
|
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/search_modules/search_suggestions.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/search_modules/tab_search.dart';
|
import 'package:weblibre/features/geckoview/features/search/presentation/widgets/search_modules/tab_search.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/hooks/sampled_value_notifier.dart';
|
import 'package:weblibre/presentation/hooks/sampled_value_notifier.dart';
|
||||||
import 'package:weblibre/utils/uri_parser.dart' as uri_parser;
|
import 'package:weblibre/utils/uri_parser.dart' as uri_parser;
|
||||||
|
|
||||||
@@ -29,8 +32,20 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final formKey = useMemoized(() => GlobalKey<FormState>());
|
final formKey = useMemoized(() => GlobalKey<FormState>());
|
||||||
|
|
||||||
|
final createChildTabsOption = ref.watch(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(value) => value.createChildTabsOption,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final selectedTabType = useState(tabType);
|
final selectedTabType = useState(tabType);
|
||||||
final isPrivate = selectedTabType.value == TabType.private;
|
final currentTabTabType = ref.watch(selectedTabTypeProvider);
|
||||||
|
|
||||||
|
final privateTabMode = switch (selectedTabType.value) {
|
||||||
|
TabType.regular => false,
|
||||||
|
TabType.private => true,
|
||||||
|
TabType.child => currentTabTabType == TabType.private,
|
||||||
|
};
|
||||||
|
|
||||||
final searchTextController = useTextEditingController(
|
final searchTextController = useTextEditingController(
|
||||||
text: initialSearchText,
|
text: initialSearchText,
|
||||||
@@ -61,7 +76,7 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
if (activeBang != null && (formKey.currentState?.validate() == true)) {
|
if (activeBang != null && (formKey.currentState?.validate() == true)) {
|
||||||
final searchUri = activeBang.getTemplateUrl(query);
|
final searchUri = activeBang.getTemplateUrl(query);
|
||||||
|
|
||||||
if (!isPrivate) {
|
if (!privateTabMode) {
|
||||||
await ref
|
await ref
|
||||||
.read(bangSearchProvider.notifier)
|
.read(bangSearchProvider.notifier)
|
||||||
.triggerBangSearch(activeBang, query);
|
.triggerBangSearch(activeBang, query);
|
||||||
@@ -69,7 +84,13 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
await ref
|
await ref
|
||||||
.read(tabRepositoryProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.addTab(url: searchUri, private: isPrivate);
|
.addTab(
|
||||||
|
url: searchUri,
|
||||||
|
private: privateTabMode,
|
||||||
|
parentId: (selectedTabType.value == TabType.child)
|
||||||
|
? ref.read(selectedTabProvider)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||||
@@ -93,17 +114,23 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
canRequestFocus: false,
|
canRequestFocus: false,
|
||||||
child: SegmentedButton(
|
child: SegmentedButton(
|
||||||
showSelectedIcon: false,
|
showSelectedIcon: false,
|
||||||
segments: const [
|
segments: [
|
||||||
ButtonSegment(
|
const ButtonSegment(
|
||||||
value: TabType.regular,
|
value: TabType.regular,
|
||||||
label: Text('Regular'),
|
label: Text('Regular'),
|
||||||
icon: Icon(MdiIcons.tab),
|
icon: Icon(MdiIcons.tab),
|
||||||
),
|
),
|
||||||
ButtonSegment(
|
const ButtonSegment(
|
||||||
value: TabType.private,
|
value: TabType.private,
|
||||||
label: Text('Private'),
|
label: Text('Private'),
|
||||||
icon: Icon(MdiIcons.tabUnselected),
|
icon: Icon(MdiIcons.tabUnselected),
|
||||||
),
|
),
|
||||||
|
if (createChildTabsOption)
|
||||||
|
const ButtonSegment(
|
||||||
|
value: TabType.child,
|
||||||
|
label: Text('Child'),
|
||||||
|
icon: Icon(MdiIcons.fileTree),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
selected: {selectedTabType.value},
|
selected: {selectedTabType.value},
|
||||||
onSelectionChanged: (value) {
|
onSelectionChanged: (value) {
|
||||||
@@ -118,6 +145,14 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
TabType.private => SegmentedButton.styleFrom(
|
TabType.private => SegmentedButton.styleFrom(
|
||||||
selectedBackgroundColor: const Color(0x648000D7),
|
selectedBackgroundColor: const Color(0x648000D7),
|
||||||
),
|
),
|
||||||
|
TabType.child =>
|
||||||
|
(currentTabTabType == TabType.private)
|
||||||
|
? SegmentedButton.styleFrom(
|
||||||
|
selectedBackgroundColor: const Color(
|
||||||
|
0x648000D7,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -151,7 +186,14 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
if (newUrl != null) {
|
if (newUrl != null) {
|
||||||
await ref
|
await ref
|
||||||
.read(tabRepositoryProvider.notifier)
|
.read(tabRepositoryProvider.notifier)
|
||||||
.addTab(url: newUrl, private: isPrivate);
|
.addTab(
|
||||||
|
url: newUrl,
|
||||||
|
private: privateTabMode,
|
||||||
|
parentId:
|
||||||
|
(selectedTabType.value == TabType.child)
|
||||||
|
? ref.read(selectedTabProvider)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
ref
|
ref
|
||||||
@@ -181,7 +223,7 @@ class SearchScreen extends HookConsumerWidget {
|
|||||||
TabSearch(searchTextListenable: sampledSearchText),
|
TabSearch(searchTextListenable: sampledSearchText),
|
||||||
FeedSearch(searchTextNotifier: sampledSearchText),
|
FeedSearch(searchTextNotifier: sampledSearchText),
|
||||||
HistorySuggestions(
|
HistorySuggestions(
|
||||||
isPrivate: isPrivate,
|
isPrivate: privateTabMode,
|
||||||
searchTextListenable: sampledSearchText,
|
searchTextListenable: sampledSearchText,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -131,6 +131,22 @@ class GeneralSettingsScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
|
SwitchListTile.adaptive(
|
||||||
|
title: const Text('Create Child Tabs'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Display a button to create a child tab under the current tab (tree view only)',
|
||||||
|
),
|
||||||
|
secondary: const Icon(MdiIcons.fileTree),
|
||||||
|
value: generalSettings.createChildTabsOption,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||||
|
.save(
|
||||||
|
(currentSettings) => currentSettings.copyWith
|
||||||
|
.createChildTabsOption(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
Consumer(
|
Consumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final size = ref.watch(
|
final size = ref.watch(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
final bool enforceReadability;
|
final bool enforceReadability;
|
||||||
final Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit;
|
final Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit;
|
||||||
final String defaultSearchProvider;
|
final String defaultSearchProvider;
|
||||||
|
final bool createChildTabsOption;
|
||||||
|
|
||||||
final bool proxyPrivateTabsTor;
|
final bool proxyPrivateTabsTor;
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
required this.enforceReadability,
|
required this.enforceReadability,
|
||||||
required this.deleteBrowsingDataOnQuit,
|
required this.deleteBrowsingDataOnQuit,
|
||||||
required this.defaultSearchProvider,
|
required this.defaultSearchProvider,
|
||||||
|
required this.createChildTabsOption,
|
||||||
required this.proxyPrivateTabsTor,
|
required this.proxyPrivateTabsTor,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -45,11 +47,13 @@ class GeneralSettings with FastEquatable {
|
|||||||
bool? enforceReadability,
|
bool? enforceReadability,
|
||||||
this.deleteBrowsingDataOnQuit,
|
this.deleteBrowsingDataOnQuit,
|
||||||
String? defaultSearchProvider,
|
String? defaultSearchProvider,
|
||||||
|
bool? createChildTabsOption,
|
||||||
bool? proxyPrivateTabsTor,
|
bool? proxyPrivateTabsTor,
|
||||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||||
enableReadability = enableReadability ?? true,
|
enableReadability = enableReadability ?? true,
|
||||||
enforceReadability = enforceReadability ?? false,
|
enforceReadability = enforceReadability ?? false,
|
||||||
defaultSearchProvider = defaultSearchProvider ?? 'lais',
|
defaultSearchProvider = defaultSearchProvider ?? 'lais',
|
||||||
|
createChildTabsOption = createChildTabsOption ?? false,
|
||||||
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false;
|
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false;
|
||||||
|
|
||||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -64,6 +68,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
enforceReadability,
|
enforceReadability,
|
||||||
deleteBrowsingDataOnQuit,
|
deleteBrowsingDataOnQuit,
|
||||||
defaultSearchProvider,
|
defaultSearchProvider,
|
||||||
|
createChildTabsOption,
|
||||||
proxyPrivateTabsTor,
|
proxyPrivateTabsTor,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
|
|
||||||
GeneralSettings defaultSearchProvider(String defaultSearchProvider);
|
GeneralSettings defaultSearchProvider(String defaultSearchProvider);
|
||||||
|
|
||||||
|
GeneralSettings createChildTabsOption(bool createChildTabsOption);
|
||||||
|
|
||||||
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
@@ -33,6 +35,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
bool enforceReadability,
|
bool enforceReadability,
|
||||||
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
||||||
String defaultSearchProvider,
|
String defaultSearchProvider,
|
||||||
|
bool createChildTabsOption,
|
||||||
bool proxyPrivateTabsTor,
|
bool proxyPrivateTabsTor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -63,6 +66,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
GeneralSettings defaultSearchProvider(String defaultSearchProvider) =>
|
GeneralSettings defaultSearchProvider(String defaultSearchProvider) =>
|
||||||
this(defaultSearchProvider: defaultSearchProvider);
|
this(defaultSearchProvider: defaultSearchProvider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings createChildTabsOption(bool createChildTabsOption) =>
|
||||||
|
this(createChildTabsOption: createChildTabsOption);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
||||||
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
||||||
@@ -80,6 +87,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? enforceReadability = const $CopyWithPlaceholder(),
|
Object? enforceReadability = const $CopyWithPlaceholder(),
|
||||||
Object? deleteBrowsingDataOnQuit = const $CopyWithPlaceholder(),
|
Object? deleteBrowsingDataOnQuit = const $CopyWithPlaceholder(),
|
||||||
Object? defaultSearchProvider = const $CopyWithPlaceholder(),
|
Object? defaultSearchProvider = const $CopyWithPlaceholder(),
|
||||||
|
Object? createChildTabsOption = const $CopyWithPlaceholder(),
|
||||||
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return GeneralSettings(
|
return GeneralSettings(
|
||||||
@@ -105,6 +113,11 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.defaultSearchProvider
|
? _value.defaultSearchProvider
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: defaultSearchProvider as String,
|
: defaultSearchProvider as String,
|
||||||
|
createChildTabsOption:
|
||||||
|
createChildTabsOption == const $CopyWithPlaceholder()
|
||||||
|
? _value.createChildTabsOption
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: createChildTabsOption as bool,
|
||||||
proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder()
|
proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder()
|
||||||
? _value.proxyPrivateTabsTor
|
? _value.proxyPrivateTabsTor
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
@@ -133,6 +146,7 @@ GeneralSettings _$GeneralSettingsFromJson(Map<String, dynamic> json) =>
|
|||||||
?.map((e) => $enumDecode(_$DeleteBrowsingDataTypeEnumMap, e))
|
?.map((e) => $enumDecode(_$DeleteBrowsingDataTypeEnumMap, e))
|
||||||
.toSet(),
|
.toSet(),
|
||||||
defaultSearchProvider: json['defaultSearchProvider'] as String?,
|
defaultSearchProvider: json['defaultSearchProvider'] as String?,
|
||||||
|
createChildTabsOption: json['createChildTabsOption'] as bool?,
|
||||||
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -145,6 +159,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
|||||||
?.map((e) => _$DeleteBrowsingDataTypeEnumMap[e]!)
|
?.map((e) => _$DeleteBrowsingDataTypeEnumMap[e]!)
|
||||||
.toList(),
|
.toList(),
|
||||||
'defaultSearchProvider': instance.defaultSearchProvider,
|
'defaultSearchProvider': instance.defaultSearchProvider,
|
||||||
|
'createChildTabsOption': instance.createChildTabsOption,
|
||||||
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
),
|
),
|
||||||
|
'createChildTabsOption': settings['createChildTabsOption']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
'proxyPrivateTabsTor': settings['proxyPrivateTabsTor']?.readAs(
|
'proxyPrivateTabsTor': settings['proxyPrivateTabsTor']?.readAs(
|
||||||
DriftSqlType.bool,
|
DriftSqlType.bool,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'general_settings.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'e16ce010f5feb692bd9f3a394c9502f959ded589';
|
r'4aea6ef10e883aa715141cc314d02d8af90dbdb5';
|
||||||
|
|
||||||
/// See also [GeneralSettingsRepository].
|
/// See also [GeneralSettingsRepository].
|
||||||
@ProviderFor(GeneralSettingsRepository)
|
@ProviderFor(GeneralSettingsRepository)
|
||||||
|
|||||||
Reference in New Issue
Block a user