From e4853281f1972e7c17784d84393cdf8ac8c1c547 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Sat, 2 May 2026 05:58:56 +0200 Subject: [PATCH] export screenshot --- .../widgets/browser_menu_sheet.dart | 36 +++++++++++++ .../widgets/menu_item_buttons.dart | 51 +++++++++++++++++++ .../presentation/widgets/tab_menu.dart | 1 + 3 files changed, 88 insertions(+) diff --git a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_menu_sheet.dart b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_menu_sheet.dart index 9f50dbd7..b7e16422 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_menu_sheet.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_menu_sheet.dart @@ -1650,6 +1650,42 @@ class _ExportExpansion extends ConsumerWidget { }, ), + // Export as PNG + _buildSubTile( + 'Export as PNG', + icon: MdiIcons.fileImage, + onTap: () async { + final screenshot = await ref + .read(selectedTabSessionProvider) + .requestScreenshot(); + + final ts = ref.read(tabStateProvider(selectedTabId))!; + + if (screenshot != null) { + ui.decodeImageFromList(screenshot, (result) async { + try { + final png = await result.toByteData( + format: ui.ImageByteFormat.png, + ); + + if (png != null) { + await FilePicker.saveFile( + fileName: '${ts.titleOrAuthority}.png', + type: FileType.custom, + allowedExtensions: ['png'], + bytes: png.buffer.asUint8List(), + ); + } + } finally { + result.dispose(); + } + }); + } + + if (context.mounted) Navigator.pop(context); + }, + ), + // Print _buildSubTile( 'Print', diff --git a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart index 1cedc0aa..b530a751 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/menu_item_buttons.dart @@ -19,6 +19,7 @@ */ import 'dart:ui' as ui; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; @@ -260,6 +261,56 @@ class ShareScreenshotMenuItemButton extends HookConsumerWidget { } } +class ExportScreenshotMenuItemButton extends HookConsumerWidget { + const ExportScreenshotMenuItemButton({ + super.key, + required this.selectedTabId, + }); + + final String? selectedTabId; + + @override + Widget build(BuildContext context, WidgetRef ref) { + return MenuItemButton( + leadingIcon: const Icon(MdiIcons.fileImage), + closeOnActivate: false, + child: const Text('Export as PNG'), + onPressed: () async { + final screenshot = await ref + .read(selectedTabSessionProvider) + .requestScreenshot(); + + final tabState = ref.read(tabStateProvider(selectedTabId))!; + + if (screenshot != null) { + ui.decodeImageFromList(screenshot, (result) async { + try { + final png = await result.toByteData( + format: ui.ImageByteFormat.png, + ); + + if (png != null) { + await FilePicker.saveFile( + fileName: '${tabState.titleOrAuthority}.png', + type: FileType.custom, + allowedExtensions: ['png'], + bytes: png.buffer.asUint8List(), + ); + } + } finally { + result.dispose(); + } + }); + } + + if (context.mounted) { + MenuController.maybeOf(context)?.close(); + } + }, + ); + } +} + class OpenInAppMenuItemButton extends HookConsumerWidget { const OpenInAppMenuItemButton({super.key, required this.selectedTabId}); diff --git a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/tab_menu.dart b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/tab_menu.dart index 2de6b2f5..7594b276 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/tab_menu.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/tab_menu.dart @@ -586,6 +586,7 @@ class TabMenu extends HookConsumerWidget { }, ), SaveToPdfMenuItemButton(selectedTabId: selectedTabId), + ExportScreenshotMenuItemButton(selectedTabId: selectedTabId), PrintMenuItemButton(selectedTabId: selectedTabId), ], leadingIcon: const Icon(MdiIcons.fileExport),