reorganize menus

This commit is contained in:
Fabian Freund
2025-12-01 11:23:40 +01:00
parent cb6cb2ba62
commit 73fd816efc
2 changed files with 239 additions and 217 deletions
@@ -349,13 +349,6 @@ class BrowserBottomAppBar extends HookConsumerWidget {
leadingIcon: const Icon(Icons.settings), leadingIcon: const Icon(Icons.settings),
child: const Text('Settings'), child: const Text('Settings'),
), ),
MenuItemButton(
onPressed: () async {
await const HistoryRoute().push(context);
},
leadingIcon: const Icon(Icons.history),
child: const Text('History'),
),
Consumer( Consumer(
builder: (context, childRef, child) { builder: (context, childRef, child) {
final browserExtensions = childRef.watch( final browserExtensions = childRef.watch(
@@ -437,6 +430,13 @@ class BrowserBottomAppBar extends HookConsumerWidget {
), ),
), ),
const Divider(), const Divider(),
MenuItemButton(
onPressed: () async {
await const HistoryRoute().push(context);
},
leadingIcon: const Icon(Icons.history),
child: const Text('History'),
),
MenuItemButton( MenuItemButton(
onPressed: () async { onPressed: () async {
await BookmarkListRoute( await BookmarkListRoute(
@@ -130,41 +130,17 @@ class TabMenu extends HookConsumerWidget {
}, },
), ),
const Divider(), const Divider(),
MenuItemButton( Visibility(
onPressed: () async { visible: showFeeds.value,
await ref replacement: MenuItemButton(
.read(tabRepositoryProvider.notifier) closeOnActivate: false,
.closeTab(selectedTabId); leadingIcon: const Icon(Icons.rss_feed),
child: const Text('Fetch Feeds'),
if (context.mounted) { onPressed: () {
ui_helper.showTabUndoClose( showFeeds.value = true;
context, },
ref.read(tabRepositoryProvider.notifier).undoClose, ),
); child: WebsiteFeedMenuButton(selectedTabId),
}
},
leadingIcon: const Icon(Icons.close),
child: const Text('Close Tab'),
),
MenuItemButton(
leadingIcon: const Icon(MdiIcons.contentCopy),
child: const Text('Copy address'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await Clipboard.setData(
ClipboardData(text: tabState.url.toString()),
);
},
),
MenuItemButton(
leadingIcon: const Icon(Icons.open_in_browser),
child: const Text('Launch External'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await ui_helper.launchUrlFeedback(context, tabState.url);
},
), ),
MenuItemButton( MenuItemButton(
leadingIcon: const Icon(MdiIcons.bookmarkPlus), leadingIcon: const Icon(MdiIcons.bookmarkPlus),
@@ -182,205 +158,251 @@ class TabMenu extends HookConsumerWidget {
).push(context); ).push(context);
}, },
), ),
MenuItemButton( SubmenuButton(
leadingIcon: const Icon(MdiIcons.tabPlus), menuChildren: [
child: const Text('Clone tab'), MenuItemButton(
onPressed: () async { leadingIcon: const Icon(MdiIcons.tabPlus),
final tabState = ref.read(tabStateProvider(selectedTabId))!; child: const Text('Regular'),
onPressed: () async {
final tabId = await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: tabState.url, private: false, selectTab: false);
if (context.mounted) {
//save reference before pop `ref` gets disposed
final repo = ref.read(tabRepositoryProvider.notifier);
ui_helper.showTabSwitchMessage(
context,
onSwitch: () async {
await repo.selectTab(tabId);
},
);
}
},
),
MenuItemButton(
leadingIcon: const Icon(MdiIcons.tabUnselected),
child: const Text('Clone as private tab'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
final tabId = await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: tabState.url, private: true, selectTab: false);
if (context.mounted) {
//save reference before pop `ref` gets disposed
final repo = ref.read(tabRepositoryProvider.notifier);
ui_helper.showTabSwitchMessage(
context,
onSwitch: () async {
await repo.selectTab(tabId);
},
);
}
},
),
MenuItemButton(
leadingIcon: const Icon(MdiIcons.folderArrowUpDownOutline),
child: const Text('Assign container'),
onPressed: () async {
final targetContainerId = await const ContainerSelectionRoute()
.push<String?>(context);
if (targetContainerId != null) {
final containerData = await ref
.read(containerRepositoryProvider.notifier)
.getContainerData(targetContainerId);
if (containerData != null) {
final tabState = ref.read(tabStateProvider(selectedTabId))!; final tabState = ref.read(tabStateProvider(selectedTabId))!;
await ref final tabId = await ref
.read(tabDataRepositoryProvider.notifier) .read(tabRepositoryProvider.notifier)
.assignContainer(tabState.id, containerData); .addTab(
} url: tabState.url,
} private: false,
}, selectTab: false,
);
if (context.mounted) {
//save reference before pop `ref` gets disposed
final repo = ref.read(tabRepositoryProvider.notifier);
ui_helper.showTabSwitchMessage(
context,
onSwitch: () async {
await repo.selectTab(tabId);
},
);
}
},
),
MenuItemButton(
leadingIcon: const Icon(MdiIcons.tabUnselected),
child: const Text('Private'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
final tabId = await ref
.read(tabRepositoryProvider.notifier)
.addTab(url: tabState.url, private: true, selectTab: false);
if (context.mounted) {
//save reference before pop `ref` gets disposed
final repo = ref.read(tabRepositoryProvider.notifier);
ui_helper.showTabSwitchMessage(
context,
onSwitch: () async {
await repo.selectTab(tabId);
},
);
}
},
),
],
leadingIcon: const Icon(MdiIcons.tabPlus),
child: const Text('Clone Tab'),
), ),
Consumer( SubmenuButton(
child: MenuItemButton( menuChildren: [
leadingIcon: const Icon(MdiIcons.webPlus), MenuItemButton(
child: const Text('Assign Site to Container'), leadingIcon: const Icon(MdiIcons.folderArrowUpDownOutline),
onPressed: () async { child: const Text('Assign Container'),
final targetContainerId = await const ContainerSelectionRoute() onPressed: () async {
.push<String?>(context); final targetContainerId = await const ContainerSelectionRoute()
.push<String?>(context);
if (targetContainerId != null) { if (targetContainerId != null) {
final containerData = await ref final containerData = await ref
.read(containerRepositoryProvider.notifier) .read(containerRepositoryProvider.notifier)
.getContainerData(targetContainerId); .getContainerData(targetContainerId);
if (containerData != null) { if (containerData != null) {
final tabState = ref.read(tabStateProvider(selectedTabId)); final tabState = ref.read(tabStateProvider(selectedTabId))!;
final origin = tabState?.url.origin.mapNotNull(Uri.parse);
if (origin != null) {
await ref await ref
.read(containerRepositoryProvider.notifier) .read(tabDataRepositoryProvider.notifier)
.replaceContainer( .assignContainer(tabState.id, containerData);
containerData.copyWith.metadata(
containerData.metadata.copyWith.assignedSites([
...?containerData.metadata.assignedSites,
origin,
]),
),
);
} }
} }
} },
}, ),
), Consumer(
builder: (context, ref, child) { child: MenuItemButton(
final isSiteAssigned = ref.watch( leadingIcon: const Icon(MdiIcons.webPlus),
watchIsCurrentSiteAssignedToContainerProvider, child: const Text('URL relation'),
); onPressed: () async {
final targetContainerId =
await const ContainerSelectionRoute().push<String?>(
context,
);
return Visibility( if (targetContainerId != null) {
visible: isSiteAssigned.hasValue && !isSiteAssigned.requireValue, final containerData = await ref
child: child!, .read(containerRepositoryProvider.notifier)
); .getContainerData(targetContainerId);
},
),
Consumer(
child: MenuItemButton(
leadingIcon: const Icon(MdiIcons.folderCancelOutline),
child: const Text('Unassign container'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await ref if (containerData != null) {
.read(tabDataRepositoryProvider.notifier) final tabState = ref.read(
.unassignContainer(tabState.id); tabStateProvider(selectedTabId),
}, );
), final origin = tabState?.url.origin.mapNotNull(Uri.parse);
builder: (context, ref, child) {
final containerId = ref.watch(
watchContainerTabIdProvider(
selectedTabId,
).select((value) => value.value),
);
return Visibility(visible: containerId != null, child: child!); if (origin != null) {
}, await ref
), .read(containerRepositoryProvider.notifier)
MenuItemButton( .replaceContainer(
leadingIcon: const Icon(Icons.share), containerData.copyWith.metadata(
onPressed: () async { containerData.metadata.copyWith.assignedSites([
final tabState = ref.read(tabStateProvider(selectedTabId))!; ...?containerData.metadata.assignedSites,
origin,
]),
),
);
}
}
}
},
),
builder: (context, ref, child) {
final isSiteAssigned = ref.watch(
watchIsCurrentSiteAssignedToContainerProvider,
);
await SharePlus.instance.share(ShareParams(uri: tabState.url)); return Visibility(
}, visible:
trailingIcon: Row( isSiteAssigned.hasValue && !isSiteAssigned.requireValue,
mainAxisSize: MainAxisSize.min, child: child!,
children: [ );
const VerticalDivider(indent: 4, endIndent: 4), },
IconButton( ),
icon: const Icon(Icons.qr_code), Consumer(
child: MenuItemButton(
leadingIcon: const Icon(MdiIcons.folderCancelOutline),
child: const Text('Unassign Container'),
onPressed: () async { onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!; final tabState = ref.read(tabStateProvider(selectedTabId))!;
await showQrCode(context, tabState.url.toString()); await ref
controller.close(); .read(tabDataRepositoryProvider.notifier)
.unassignContainer(tabState.id);
}, },
), ),
], builder: (context, ref, child) {
), final containerId = ref.watch(
child: const Text('Share link'), watchContainerTabIdProvider(
), selectedTabId,
MenuItemButton( ).select((value) => value.value),
leadingIcon: const Icon(Icons.mobile_screen_share),
child: const Text('Share screenshot'),
onPressed: () async {
final screenshot = await ref
.read(selectedTabSessionProvider)
.requestScreenshot();
final tabState = ref.read(tabStateProvider(selectedTabId))!;
if (screenshot != null) {
ui.decodeImageFromList(screenshot, (result) async {
final png = await result.toByteData(
format: ui.ImageByteFormat.png,
); );
if (png != null) { return Visibility(visible: containerId != null, child: child!);
final file = XFile.fromData( },
png.buffer.asUint8List(), ),
mimeType: 'image/png', ],
); leadingIcon: const Icon(MdiIcons.folder),
child: const Text('Container'),
),
SubmenuButton(
menuChildren: [
MenuItemButton(
leadingIcon: const Icon(Icons.open_in_browser),
child: const Text('Launch External'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await SharePlus.instance.share( await ui_helper.launchUrlFeedback(context, tabState.url);
ShareParams(files: [file], subject: tabState.title), },
); ),
MenuItemButton(
leadingIcon: const Icon(Icons.mobile_screen_share),
child: const Text('Share Screenshot'),
onPressed: () async {
final screenshot = await ref
.read(selectedTabSessionProvider)
.requestScreenshot();
final tabState = ref.read(tabStateProvider(selectedTabId))!;
if (screenshot != null) {
ui.decodeImageFromList(screenshot, (result) async {
final png = await result.toByteData(
format: ui.ImageByteFormat.png,
);
if (png != null) {
final file = XFile.fromData(
png.buffer.asUint8List(),
mimeType: 'image/png',
);
await SharePlus.instance.share(
ShareParams(files: [file], subject: tabState.title),
);
}
});
} }
}); },
} ),
MenuItemButton(
leadingIcon: const Icon(Icons.share),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await SharePlus.instance.share(ShareParams(uri: tabState.url));
},
child: const Text('Share Link'),
),
MenuItemButton(
leadingIcon: const Icon(Icons.qr_code),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await showQrCode(context, tabState.url.toString());
controller.close();
},
child: const Text('Show QR Code'),
),
],
leadingIcon: const Icon(Icons.share),
child: const Text('Share'),
),
MenuItemButton(
leadingIcon: const Icon(MdiIcons.contentCopy),
child: const Text('Copy Address'),
onPressed: () async {
final tabState = ref.read(tabStateProvider(selectedTabId))!;
await Clipboard.setData(
ClipboardData(text: tabState.url.toString()),
);
}, },
), ),
Visibility( MenuItemButton(
visible: showFeeds.value, onPressed: () async {
replacement: MenuItemButton( await ref
closeOnActivate: false, .read(tabRepositoryProvider.notifier)
leadingIcon: const Icon(Icons.rss_feed), .closeTab(selectedTabId);
child: const Text('Fetch Feeds'),
onPressed: () { if (context.mounted) {
showFeeds.value = true; ui_helper.showTabUndoClose(
}, context,
), ref.read(tabRepositoryProvider.notifier).undoClose,
child: WebsiteFeedMenuButton(selectedTabId), );
}
},
leadingIcon: const Icon(Icons.close),
child: const Text('Close Tab'),
), ),
], ],
child: child, child: child,