refactor bottom app abr title
This commit is contained in:
+79
-90
@@ -1,108 +1,97 @@
|
||||
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:skeletonizer/skeletonizer.dart';
|
||||
import 'package:text_scroll/text_scroll.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/entities/states/tab.dart';
|
||||
import 'package:weblibre/features/geckoview/domain/providers/tab_state.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/presentation/widgets/tab_icon.dart';
|
||||
|
||||
class AppBarTitle extends StatelessWidget {
|
||||
final TabState tab;
|
||||
|
||||
final VoidCallback? onTap;
|
||||
final VoidCallback? onLongPress;
|
||||
final GestureDragStartCallback? onHorizontalDragStart;
|
||||
final GestureDragEndCallback? onHorizontalDragEnd;
|
||||
|
||||
const AppBarTitle({
|
||||
required this.tab,
|
||||
this.onTap,
|
||||
this.onLongPress,
|
||||
this.onHorizontalDragStart,
|
||||
this.onHorizontalDragEnd,
|
||||
super.key,
|
||||
});
|
||||
|
||||
Icon _securityStatusIcon(BuildContext context) {
|
||||
if (tab.url.isScheme('http')) {
|
||||
return Icon(
|
||||
MdiIcons.lockOff,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
size: 14,
|
||||
);
|
||||
} else if (!tab.securityInfoState.secure) {
|
||||
return Icon(
|
||||
MdiIcons.lockAlert,
|
||||
color: Theme.of(context).colorScheme.errorContainer,
|
||||
size: 14,
|
||||
);
|
||||
} else if (!tab.isLoading) {
|
||||
return const Icon(MdiIcons.lock, size: 14);
|
||||
} else {
|
||||
return const Icon(MdiIcons.timerSand, size: 14);
|
||||
}
|
||||
}
|
||||
class AppBarTitle extends HookConsumerWidget {
|
||||
const AppBarTitle({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final theme = Theme.of(context);
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
onLongPress: onLongPress,
|
||||
onHorizontalDragStart: onHorizontalDragStart,
|
||||
onHorizontalDragEnd: onHorizontalDragEnd,
|
||||
child: Row(
|
||||
children: [
|
||||
TabIcon(state: tab),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Skeletonizer(
|
||||
enabled: tab.title.isEmpty,
|
||||
child: Skeleton.replace(
|
||||
replacement: const Padding(
|
||||
padding: EdgeInsets.only(right: 4, top: 1, bottom: 1),
|
||||
child: Bone.text(),
|
||||
),
|
||||
child: TextScroll(
|
||||
key: ValueKey(tab.title),
|
||||
tab.title,
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
// mode: TextScrollMode.bouncing,
|
||||
velocity: const Velocity(pixelsPerSecond: Offset(75, 0)),
|
||||
delayBefore: const Duration(milliseconds: 500),
|
||||
pauseBetween: const Duration(milliseconds: 5000),
|
||||
fadedBorder: true,
|
||||
fadeBorderSide: FadeBorderSide.right,
|
||||
fadedBorderWidth: 0.05,
|
||||
intervalSpaces: 4,
|
||||
numberOfReps: 2,
|
||||
|
||||
final tabState = ref.watch(selectedTabStateProvider);
|
||||
|
||||
if (tabState == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final icon = useMemoized(() {
|
||||
if (tabState.url.isScheme('http')) {
|
||||
return Icon(
|
||||
MdiIcons.lockOff,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
size: 14,
|
||||
);
|
||||
} else if (!tabState.securityInfoState.secure) {
|
||||
return Icon(
|
||||
MdiIcons.lockAlert,
|
||||
color: Theme.of(context).colorScheme.errorContainer,
|
||||
size: 14,
|
||||
);
|
||||
} else if (!tabState.isLoading) {
|
||||
return const Icon(MdiIcons.lock, size: 14);
|
||||
} else {
|
||||
return const Icon(MdiIcons.timerSand, size: 14);
|
||||
}
|
||||
}, [tabState]);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
TabIcon(state: tabState),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Skeletonizer(
|
||||
enabled: tabState.title.isEmpty,
|
||||
child: Skeleton.replace(
|
||||
replacement: const Padding(
|
||||
padding: EdgeInsets.only(right: 4, top: 1, bottom: 1),
|
||||
child: Bone.text(),
|
||||
),
|
||||
child: TextScroll(
|
||||
key: ValueKey(tabState.title),
|
||||
tabState.title,
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
// mode: TextScrollMode.bouncing,
|
||||
velocity: const Velocity(pixelsPerSecond: Offset(75, 0)),
|
||||
delayBefore: const Duration(milliseconds: 500),
|
||||
pauseBetween: const Duration(milliseconds: 5000),
|
||||
fadedBorder: true,
|
||||
fadeBorderSide: FadeBorderSide.right,
|
||||
fadedBorderWidth: 0.05,
|
||||
intervalSpaces: 4,
|
||||
numberOfReps: 2,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
_securityStatusIcon(context),
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: Text(
|
||||
tab.url.authority,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
icon,
|
||||
const SizedBox(width: 4),
|
||||
Expanded(
|
||||
child: Text(
|
||||
tabState.url.authority,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+340
-342
@@ -41,375 +41,373 @@ class BrowserBottomAppBar extends HookConsumerWidget {
|
||||
selectedTabStateProvider.select((state) => state?.isPrivate ?? false),
|
||||
);
|
||||
|
||||
final dragStartPosition = useRef(Offset.zero);
|
||||
|
||||
return BottomAppBar(
|
||||
height: AppBar().preferredSize.height,
|
||||
padding: EdgeInsets.zero,
|
||||
child: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 8.0,
|
||||
backgroundColor:
|
||||
(isPrivateTab && displayedSheet is! ViewTabsSheet)
|
||||
? const Color(0x648000D7)
|
||||
: null,
|
||||
title:
|
||||
(selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
||||
? HookConsumer(
|
||||
builder: (context, ref, child) {
|
||||
final tabState = ref.watch(selectedTabStateProvider);
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
final tabState = ref.read(selectedTabStateProvider);
|
||||
|
||||
final dragStartPosition = useRef(Offset.zero);
|
||||
if (tabState != null) {
|
||||
await WebPageRoute(
|
||||
url: tabState.url.toString(),
|
||||
$extra: tabState,
|
||||
).push(context);
|
||||
}
|
||||
},
|
||||
onLongPress: () async {
|
||||
final tabState = ref.read(selectedTabStateProvider);
|
||||
|
||||
return (tabState != null)
|
||||
? AppBarTitle(
|
||||
tab: tabState,
|
||||
onTap: () async {
|
||||
await WebPageRoute(
|
||||
url: tabState.url.toString(),
|
||||
$extra: tabState,
|
||||
).push(context);
|
||||
},
|
||||
onLongPress: () async {
|
||||
final newUrl = await showDialog<Uri?>(
|
||||
context: context,
|
||||
builder:
|
||||
(context) =>
|
||||
EditUrlDialog(initialUrl: tabState.url),
|
||||
);
|
||||
if (tabState != null) {
|
||||
final newUrl = await showDialog<Uri?>(
|
||||
context: context,
|
||||
builder: (context) => EditUrlDialog(initialUrl: tabState.url),
|
||||
);
|
||||
|
||||
if (newUrl != null) {
|
||||
await ref
|
||||
.read(
|
||||
tabSessionProvider(tabId: null).notifier,
|
||||
)
|
||||
.loadUrl(url: newUrl);
|
||||
}
|
||||
},
|
||||
onHorizontalDragStart: (details) {
|
||||
dragStartPosition.value = details.globalPosition;
|
||||
},
|
||||
onHorizontalDragEnd: (details) async {
|
||||
final distance =
|
||||
dragStartPosition.value -
|
||||
details.globalPosition;
|
||||
if (newUrl != null) {
|
||||
await ref
|
||||
.read(tabSessionProvider(tabId: null).notifier)
|
||||
.loadUrl(url: newUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
onHorizontalDragStart: (details) {
|
||||
dragStartPosition.value = details.globalPosition;
|
||||
},
|
||||
onHorizontalDragEnd: (details) async {
|
||||
final distance = dragStartPosition.value - details.globalPosition;
|
||||
|
||||
if (distance.dx.abs() > 50) {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.selectPreviousTab();
|
||||
}
|
||||
},
|
||||
)
|
||||
: const SizedBox.shrink();
|
||||
},
|
||||
)
|
||||
: null,
|
||||
actions: [
|
||||
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
||||
ReaderButton(),
|
||||
MenuAnchor(
|
||||
controller: tabMenuController,
|
||||
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.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(
|
||||
isActive: displayedSheet is ViewTabsSheet,
|
||||
onTap: () {
|
||||
if (displayedSheet case ViewTabsSheet()) {
|
||||
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||
} else {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.show(ViewTabsSheet());
|
||||
}
|
||||
if (distance.dx.abs() > 50) {
|
||||
await ref.read(tabRepositoryProvider.notifier).selectPreviousTab();
|
||||
}
|
||||
},
|
||||
child: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 8.0,
|
||||
backgroundColor:
|
||||
(isPrivateTab && displayedSheet is! ViewTabsSheet)
|
||||
? const Color(0x648000D7)
|
||||
: null,
|
||||
title:
|
||||
(selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
||||
? const AppBarTitle()
|
||||
: null,
|
||||
actions: [
|
||||
if (selectedTabId != null && displayedSheet is! ViewTabsSheet)
|
||||
ReaderButton(),
|
||||
MenuAnchor(
|
||||
controller: tabMenuController,
|
||||
builder: (context, controller, child) {
|
||||
return child!;
|
||||
},
|
||||
onLongPress: () {
|
||||
if (tabMenuController.isOpen) {
|
||||
tabMenuController.close();
|
||||
} else {
|
||||
tabMenuController.open();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
MenuAnchor(
|
||||
controller: trippleDotMenuController,
|
||||
builder: (context, controller, child) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.open();
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 15.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Icon(Icons.more_vert),
|
||||
menuChildren: [
|
||||
if (selectedTabId != null) ...[
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.closeTab(selectedTabId);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.close),
|
||||
child: const Text('Close Tab'),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
menuChildren: [
|
||||
Consumer(
|
||||
builder: (context, childRef, child) {
|
||||
final pageExtensions = childRef.watch(
|
||||
webExtensionsStateProvider(
|
||||
WebExtensionActionType.page,
|
||||
).select((value) => value.values.toList()),
|
||||
);
|
||||
|
||||
return Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
...pageExtensions.map(
|
||||
(extension) => IconButton(
|
||||
onPressed: () async {
|
||||
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||
await addonService.invokeAddonAction(
|
||||
extension.extensionId,
|
||||
WebExtensionActionType.page,
|
||||
);
|
||||
},
|
||||
icon: ExtensionBadgeIcon(extension),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await AboutRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.info),
|
||||
child: const Text('About'),
|
||||
),
|
||||
const Divider(),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await SettingsRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.settings),
|
||||
child: const Text('Settings'),
|
||||
),
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final browserExtensions = ref.watch(
|
||||
webExtensionsStateProvider(
|
||||
WebExtensionActionType.browser,
|
||||
).select((value) => value.values.toList()),
|
||||
);
|
||||
|
||||
return SubmenuButton(
|
||||
menuChildren: [
|
||||
...browserExtensions.map(
|
||||
(extension) => MenuItemButton(
|
||||
onPressed: () async {
|
||||
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||
await addonService.invokeAddonAction(
|
||||
extension.extensionId,
|
||||
WebExtensionActionType.browser,
|
||||
);
|
||||
},
|
||||
leadingIcon: ExtensionBadgeIcon(extension),
|
||||
child: Text(extension.title ?? ''),
|
||||
),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await addonService.startAddonManagerActivity();
|
||||
},
|
||||
leadingIcon: const Icon(MdiIcons.puzzleEdit),
|
||||
child: const Text('Addon Manager'),
|
||||
),
|
||||
],
|
||||
leadingIcon: const Icon(MdiIcons.puzzle),
|
||||
child: const Text('Addons'),
|
||||
);
|
||||
},
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await TorProxyRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(TorIcons.onionAlt),
|
||||
child: const Text('Tor'),
|
||||
),
|
||||
const Divider(),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await BangCategoriesRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(MdiIcons.exclamationThick),
|
||||
child: const Text('Bangs'),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await context.push(FeedListRoute().location);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.rss_feed),
|
||||
child: const Text('Feeds'),
|
||||
),
|
||||
const Divider(),
|
||||
if (selectedTabId != null)
|
||||
const Divider(),
|
||||
],
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final tabState = ref.read(tabStateProvider(selectedTabId));
|
||||
|
||||
if (tabState?.url case final Uri url) {
|
||||
await ui_helper.launchUrlFeedback(context, url);
|
||||
}
|
||||
await const SearchRoute(
|
||||
tabType: TabType.private,
|
||||
).push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.open_in_browser),
|
||||
child: const Text('Launch External'),
|
||||
leadingIcon: const Icon(MdiIcons.tabUnselected),
|
||||
child: const Text('Add Private Tab'),
|
||||
),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final tabState = ref.read(tabStateProvider(selectedTabId));
|
||||
|
||||
if (tabState?.url case final Uri url) {
|
||||
await SharePlus.instance.share(ShareParams(uri: url));
|
||||
}
|
||||
await const SearchRoute(
|
||||
tabType: TabType.regular,
|
||||
).push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.share),
|
||||
child: const Text('Share'),
|
||||
leadingIcon: const Icon(MdiIcons.tabPlus),
|
||||
child: const Text('Add Tab'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () {
|
||||
ref.read(findInPageControllerProvider.notifier).show();
|
||||
},
|
||||
leadingIcon: const Icon(Icons.search),
|
||||
child: const Text('Find in page'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
await controller.reload();
|
||||
trippleDotMenuController.close();
|
||||
},
|
||||
leadingIcon: const Icon(Icons.refresh),
|
||||
child: const Text('Reload'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null)
|
||||
],
|
||||
child: TabsActionButton(
|
||||
isActive: displayedSheet is ViewTabsSheet,
|
||||
onTap: () {
|
||||
if (displayedSheet case ViewTabsSheet()) {
|
||||
ref.read(bottomSheetControllerProvider.notifier).dismiss();
|
||||
} else {
|
||||
ref
|
||||
.read(bottomSheetControllerProvider.notifier)
|
||||
.show(ViewTabsSheet());
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
if (tabMenuController.isOpen) {
|
||||
tabMenuController.close();
|
||||
} else {
|
||||
tabMenuController.open();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
MenuAnchor(
|
||||
controller: trippleDotMenuController,
|
||||
builder: (context, controller, child) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (controller.isOpen) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.open();
|
||||
}
|
||||
},
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
vertical: 15.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
child: Icon(Icons.more_vert),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
menuChildren: [
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(
|
||||
tabStateProvider(
|
||||
selectedTabId,
|
||||
).select((value) => value?.historyState),
|
||||
builder: (context, childRef, child) {
|
||||
final pageExtensions = childRef.watch(
|
||||
webExtensionsStateProvider(
|
||||
WebExtensionActionType.page,
|
||||
).select((value) => value.values.toList()),
|
||||
);
|
||||
|
||||
final isLoading = ref.watch(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.isLoading ?? false,
|
||||
),
|
||||
);
|
||||
|
||||
return Row(
|
||||
return Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child:
|
||||
(history?.canGoBack == true || isLoading)
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(
|
||||
tabId: selectedTabId,
|
||||
).notifier,
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
await controller.stopLoading();
|
||||
} else {
|
||||
await controller.goBack();
|
||||
}
|
||||
|
||||
trippleDotMenuController.close();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
)
|
||||
: IconButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(tabRepositoryProvider.notifier)
|
||||
.closeTab(selectedTabId);
|
||||
trippleDotMenuController.close();
|
||||
},
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48, child: VerticalDivider()),
|
||||
Expanded(
|
||||
child: IconButton(
|
||||
onPressed:
|
||||
(history?.canGoForward == true)
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(
|
||||
tabId: selectedTabId,
|
||||
).notifier,
|
||||
);
|
||||
|
||||
await controller.goForward();
|
||||
trippleDotMenuController.close();
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.arrow_forward),
|
||||
...pageExtensions.map(
|
||||
(extension) => IconButton(
|
||||
onPressed: () async {
|
||||
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||
await addonService.invokeAddonAction(
|
||||
extension.extensionId,
|
||||
WebExtensionActionType.page,
|
||||
);
|
||||
},
|
||||
icon: ExtensionBadgeIcon(extension),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await AboutRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.info),
|
||||
child: const Text('About'),
|
||||
),
|
||||
const Divider(),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await SettingsRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.settings),
|
||||
child: const Text('Settings'),
|
||||
),
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final browserExtensions = ref.watch(
|
||||
webExtensionsStateProvider(
|
||||
WebExtensionActionType.browser,
|
||||
).select((value) => value.values.toList()),
|
||||
);
|
||||
|
||||
return SubmenuButton(
|
||||
menuChildren: [
|
||||
...browserExtensions.map(
|
||||
(extension) => MenuItemButton(
|
||||
onPressed: () async {
|
||||
//Use parents .ref because after onPressed this consumer gets disposed already
|
||||
await addonService.invokeAddonAction(
|
||||
extension.extensionId,
|
||||
WebExtensionActionType.browser,
|
||||
);
|
||||
},
|
||||
leadingIcon: ExtensionBadgeIcon(extension),
|
||||
child: Text(extension.title ?? ''),
|
||||
),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await addonService.startAddonManagerActivity();
|
||||
},
|
||||
leadingIcon: const Icon(MdiIcons.puzzleEdit),
|
||||
child: const Text('Addon Manager'),
|
||||
),
|
||||
],
|
||||
leadingIcon: const Icon(MdiIcons.puzzle),
|
||||
child: const Text('Addons'),
|
||||
);
|
||||
},
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await TorProxyRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(TorIcons.onionAlt),
|
||||
child: const Text('Tor'),
|
||||
),
|
||||
const Divider(),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await BangCategoriesRoute().push(context);
|
||||
},
|
||||
leadingIcon: const Icon(MdiIcons.exclamationThick),
|
||||
child: const Text('Bangs'),
|
||||
),
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
await context.push(FeedListRoute().location);
|
||||
},
|
||||
leadingIcon: const Icon(Icons.rss_feed),
|
||||
child: const Text('Feeds'),
|
||||
),
|
||||
const Divider(),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final tabState = ref.read(
|
||||
tabStateProvider(selectedTabId),
|
||||
);
|
||||
|
||||
if (tabState?.url case final Uri url) {
|
||||
await ui_helper.launchUrlFeedback(context, url);
|
||||
}
|
||||
},
|
||||
leadingIcon: const Icon(Icons.open_in_browser),
|
||||
child: const Text('Launch External'),
|
||||
),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final tabState = ref.read(
|
||||
tabStateProvider(selectedTabId),
|
||||
);
|
||||
|
||||
if (tabState?.url case final Uri url) {
|
||||
await SharePlus.instance.share(ShareParams(uri: url));
|
||||
}
|
||||
},
|
||||
leadingIcon: const Icon(Icons.share),
|
||||
child: const Text('Share'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () {
|
||||
ref.read(findInPageControllerProvider.notifier).show();
|
||||
},
|
||||
leadingIcon: const Icon(Icons.search),
|
||||
child: const Text('Find in page'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null)
|
||||
MenuItemButton(
|
||||
onPressed: () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(tabId: selectedTabId).notifier,
|
||||
);
|
||||
|
||||
await controller.reload();
|
||||
trippleDotMenuController.close();
|
||||
},
|
||||
leadingIcon: const Icon(Icons.refresh),
|
||||
child: const Text('Reload'),
|
||||
),
|
||||
if (selectedTabId != null) const Divider(),
|
||||
if (selectedTabId != null)
|
||||
Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final history = ref.watch(
|
||||
tabStateProvider(
|
||||
selectedTabId,
|
||||
).select((value) => value?.historyState),
|
||||
);
|
||||
|
||||
final isLoading = ref.watch(
|
||||
selectedTabStateProvider.select(
|
||||
(state) => state?.isLoading ?? false,
|
||||
),
|
||||
);
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child:
|
||||
(history?.canGoBack == true || isLoading)
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(
|
||||
tabId: selectedTabId,
|
||||
).notifier,
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
await controller.stopLoading();
|
||||
} else {
|
||||
await controller.goBack();
|
||||
}
|
||||
|
||||
trippleDotMenuController.close();
|
||||
},
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
)
|
||||
: IconButton(
|
||||
onPressed: () async {
|
||||
await ref
|
||||
.read(
|
||||
tabRepositoryProvider.notifier,
|
||||
)
|
||||
.closeTab(selectedTabId);
|
||||
trippleDotMenuController.close();
|
||||
},
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 48, child: VerticalDivider()),
|
||||
Expanded(
|
||||
child: IconButton(
|
||||
onPressed:
|
||||
(history?.canGoForward == true)
|
||||
? () async {
|
||||
final controller = ref.read(
|
||||
tabSessionProvider(
|
||||
tabId: selectedTabId,
|
||||
).notifier,
|
||||
);
|
||||
|
||||
await controller.goForward();
|
||||
trippleDotMenuController.close();
|
||||
}
|
||||
: null,
|
||||
icon: const Icon(Icons.arrow_forward),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user