feature extension shortcut
This commit is contained in:
+23
@@ -18,10 +18,12 @@ 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/extension_shortcut_menu.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_creation_menu.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';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
import 'package:weblibre/presentation/hooks/menu_controller.dart';
|
||||||
import 'package:weblibre/presentation/icons/tor_icons.dart';
|
import 'package:weblibre/presentation/icons/tor_icons.dart';
|
||||||
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
import 'package:weblibre/utils/ui_helper.dart' as ui_helper;
|
||||||
@@ -36,6 +38,7 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
|||||||
final addonService = ref.watch(addonServiceProvider);
|
final addonService = ref.watch(addonServiceProvider);
|
||||||
|
|
||||||
final tabMenuController = useMenuController();
|
final tabMenuController = useMenuController();
|
||||||
|
final extensionMenuController = useMenuController();
|
||||||
final trippleDotMenuController = useMenuController();
|
final trippleDotMenuController = useMenuController();
|
||||||
|
|
||||||
final selectedTabId = ref.watch(selectedTabProvider);
|
final selectedTabId = ref.watch(selectedTabProvider);
|
||||||
@@ -43,6 +46,12 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
|||||||
selectedTabStateProvider.select((state) => state?.isPrivate ?? false),
|
selectedTabStateProvider.select((state) => state?.isPrivate ?? false),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final showExtensionShortcut = ref.watch(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(value) => value.showExtensionShortcut,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
final dragStartPosition = useRef(Offset.zero);
|
final dragStartPosition = useRef(Offset.zero);
|
||||||
|
|
||||||
return BottomAppBar(
|
return BottomAppBar(
|
||||||
@@ -97,6 +106,20 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
|||||||
actions: [
|
actions: [
|
||||||
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
||||||
ReaderButton(),
|
ReaderButton(),
|
||||||
|
if (showExtensionShortcut)
|
||||||
|
ExtensionShortcutMenu(
|
||||||
|
controller: extensionMenuController,
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (extensionMenuController.isOpen) {
|
||||||
|
extensionMenuController.close();
|
||||||
|
} else {
|
||||||
|
extensionMenuController.open();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(MdiIcons.puzzle),
|
||||||
|
),
|
||||||
|
),
|
||||||
TabCreationMenu(
|
TabCreationMenu(
|
||||||
controller: tabMenuController,
|
controller: tabMenuController,
|
||||||
selectedTabId: selectedTabId,
|
selectedTabId: selectedTabId,
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/domain/providers.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/domain/providers/web_extensions_state.dart';
|
||||||
|
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart';
|
||||||
|
|
||||||
|
class ExtensionShortcutMenu extends HookConsumerWidget {
|
||||||
|
final Widget child;
|
||||||
|
final MenuController controller;
|
||||||
|
|
||||||
|
const ExtensionShortcutMenu({
|
||||||
|
super.key,
|
||||||
|
required this.child,
|
||||||
|
required this.controller,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final browserExtensions = ref.watch(
|
||||||
|
webExtensionsStateProvider(
|
||||||
|
WebExtensionActionType.browser,
|
||||||
|
).select((value) => value.values.toList()),
|
||||||
|
);
|
||||||
|
|
||||||
|
return MenuAnchor(
|
||||||
|
controller: controller,
|
||||||
|
builder: (context, controller, child) {
|
||||||
|
return child!;
|
||||||
|
},
|
||||||
|
menuChildren: [
|
||||||
|
...browserExtensions.map(
|
||||||
|
(extension) => MenuItemButton(
|
||||||
|
onPressed: () async {
|
||||||
|
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||||
|
await ref
|
||||||
|
.read(addonServiceProvider)
|
||||||
|
.invokeAddonAction(
|
||||||
|
extension.extensionId,
|
||||||
|
WebExtensionActionType.browser,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
leadingIcon: ExtensionBadgeIcon(extension),
|
||||||
|
child: Text(extension.title ?? ''),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
child: Visibility(visible: browserExtensions.isNotEmpty, child: child),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -210,6 +210,22 @@ class GeneralSettingsScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
SwitchListTile.adaptive(
|
||||||
|
title: const Text('Show Extension Shortcut'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'Display an extension menu directly on the tab bar',
|
||||||
|
),
|
||||||
|
secondary: const Icon(MdiIcons.puzzleHeart),
|
||||||
|
value: generalSettings.showExtensionShortcut,
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(saveGeneralSettingsControllerProvider.notifier)
|
||||||
|
.save(
|
||||||
|
(currentSettings) => currentSettings.copyWith
|
||||||
|
.showExtensionShortcut(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
Consumer(
|
Consumer(
|
||||||
builder: (context, ref, child) {
|
builder: (context, ref, child) {
|
||||||
final size = ref.watch(
|
final size = ref.watch(
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
final String defaultSearchProvider;
|
final String defaultSearchProvider;
|
||||||
final SearchSuggestionProviders defaultSearchSuggestionsProvider;
|
final SearchSuggestionProviders defaultSearchSuggestionsProvider;
|
||||||
final bool createChildTabsOption;
|
final bool createChildTabsOption;
|
||||||
|
final bool showExtensionShortcut;
|
||||||
|
|
||||||
final bool proxyPrivateTabsTor;
|
final bool proxyPrivateTabsTor;
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
required this.defaultSearchSuggestionsProvider,
|
required this.defaultSearchSuggestionsProvider,
|
||||||
required this.createChildTabsOption,
|
required this.createChildTabsOption,
|
||||||
required this.proxyPrivateTabsTor,
|
required this.proxyPrivateTabsTor,
|
||||||
|
required this.showExtensionShortcut,
|
||||||
});
|
});
|
||||||
|
|
||||||
GeneralSettings.withDefaults({
|
GeneralSettings.withDefaults({
|
||||||
@@ -56,6 +58,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
SearchSuggestionProviders? defaultSearchSuggestionsProvider,
|
SearchSuggestionProviders? defaultSearchSuggestionsProvider,
|
||||||
bool? createChildTabsOption,
|
bool? createChildTabsOption,
|
||||||
bool? proxyPrivateTabsTor,
|
bool? proxyPrivateTabsTor,
|
||||||
|
bool? showExtensionShortcut,
|
||||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||||
enableReadability = enableReadability ?? true,
|
enableReadability = enableReadability ?? true,
|
||||||
enforceReadability = enforceReadability ?? false,
|
enforceReadability = enforceReadability ?? false,
|
||||||
@@ -63,7 +66,8 @@ class GeneralSettings with FastEquatable {
|
|||||||
defaultSearchSuggestionsProvider =
|
defaultSearchSuggestionsProvider =
|
||||||
defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider,
|
defaultSearchSuggestionsProvider ?? _fallbackAutocompleteProvider,
|
||||||
createChildTabsOption = createChildTabsOption ?? false,
|
createChildTabsOption = createChildTabsOption ?? false,
|
||||||
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false;
|
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
||||||
|
showExtensionShortcut = showExtensionShortcut ?? false;
|
||||||
|
|
||||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
_$GeneralSettingsFromJson(json);
|
_$GeneralSettingsFromJson(json);
|
||||||
@@ -79,6 +83,7 @@ class GeneralSettings with FastEquatable {
|
|||||||
defaultSearchProvider,
|
defaultSearchProvider,
|
||||||
defaultSearchSuggestionsProvider,
|
defaultSearchSuggestionsProvider,
|
||||||
createChildTabsOption,
|
createChildTabsOption,
|
||||||
|
showExtensionShortcut,
|
||||||
proxyPrivateTabsTor,
|
proxyPrivateTabsTor,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
|
|
||||||
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
||||||
|
|
||||||
|
GeneralSettings showExtensionShortcut(bool showExtensionShortcut);
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
/// Usage
|
/// Usage
|
||||||
@@ -42,6 +44,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
SearchSuggestionProviders defaultSearchSuggestionsProvider,
|
SearchSuggestionProviders defaultSearchSuggestionsProvider,
|
||||||
bool createChildTabsOption,
|
bool createChildTabsOption,
|
||||||
bool proxyPrivateTabsTor,
|
bool proxyPrivateTabsTor,
|
||||||
|
bool showExtensionShortcut,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +87,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
||||||
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings showExtensionShortcut(bool showExtensionShortcut) =>
|
||||||
|
this(showExtensionShortcut: showExtensionShortcut);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
@@ -100,6 +107,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? defaultSearchSuggestionsProvider = const $CopyWithPlaceholder(),
|
Object? defaultSearchSuggestionsProvider = const $CopyWithPlaceholder(),
|
||||||
Object? createChildTabsOption = const $CopyWithPlaceholder(),
|
Object? createChildTabsOption = const $CopyWithPlaceholder(),
|
||||||
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||||
|
Object? showExtensionShortcut = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return GeneralSettings(
|
return GeneralSettings(
|
||||||
themeMode: themeMode == const $CopyWithPlaceholder()
|
themeMode: themeMode == const $CopyWithPlaceholder()
|
||||||
@@ -138,6 +146,11 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.proxyPrivateTabsTor
|
? _value.proxyPrivateTabsTor
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: proxyPrivateTabsTor as bool,
|
: proxyPrivateTabsTor as bool,
|
||||||
|
showExtensionShortcut:
|
||||||
|
showExtensionShortcut == const $CopyWithPlaceholder()
|
||||||
|
? _value.showExtensionShortcut
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: showExtensionShortcut as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,6 +181,7 @@ GeneralSettings _$GeneralSettingsFromJson(Map<String, dynamic> json) =>
|
|||||||
),
|
),
|
||||||
createChildTabsOption: json['createChildTabsOption'] as bool?,
|
createChildTabsOption: json['createChildTabsOption'] as bool?,
|
||||||
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
||||||
|
showExtensionShortcut: json['showExtensionShortcut'] as bool?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
||||||
@@ -183,6 +197,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
|||||||
_$SearchSuggestionProvidersEnumMap[instance
|
_$SearchSuggestionProvidersEnumMap[instance
|
||||||
.defaultSearchSuggestionsProvider]!,
|
.defaultSearchSuggestionsProvider]!,
|
||||||
'createChildTabsOption': instance.createChildTabsOption,
|
'createChildTabsOption': instance.createChildTabsOption,
|
||||||
|
'showExtensionShortcut': instance.showExtensionShortcut,
|
||||||
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
DriftSqlType.bool,
|
DriftSqlType.bool,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
),
|
),
|
||||||
|
'showExtensionShortcut': settings['showExtensionShortcut']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'general_settings.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'5335acea5fb175b665b80b2241ce463ae8ad9f89';
|
r'eb5f27e0bd8f5def833e1c703cb42181acc2440f';
|
||||||
|
|
||||||
/// See also [GeneralSettingsRepository].
|
/// See also [GeneralSettingsRepository].
|
||||||
@ProviderFor(GeneralSettingsRepository)
|
@ProviderFor(GeneralSettingsRepository)
|
||||||
|
|||||||
Reference in New Issue
Block a user