diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 9971e8f..67624a1 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 58 (29 per locale) +/// Strings: 68 (34 per locale) /// -/// Built on 2024-02-22 at 21:08 UTC +/// Built on 2024-02-22 at 21:21 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -226,6 +226,11 @@ class _StringsWebviewEn { // Translations String get goBack => 'Go back'; String get goForward => 'Go forward'; + String get reload => 'Reload'; + String get openInSystemBrowser => 'Open in system browser'; + String get copyLinkClipboard => 'Copy link to clipboard'; + String get linkCopiedClipboard => 'Link copied to the clipboard.'; + String get share => 'Share'; } // Path: links.dates @@ -341,6 +346,11 @@ class _StringsWebviewEs implements _StringsWebviewEn { // Translations @override String get goBack => 'Ir atrás'; @override String get goForward => 'Ir adelante'; + @override String get reload => 'Recargar'; + @override String get openInSystemBrowser => 'Abrir en el navegador del sistema'; + @override String get copyLinkClipboard => 'Copiar enlace al portapapeles'; + @override String get linkCopiedClipboard => 'Enlace copiado al portapapeles.'; + @override String get share => 'Compartir'; } // Path: links.dates @@ -389,6 +399,11 @@ extension on Translations { case 'settings.disconnectFromServer': return 'Disconnect from server'; case 'webview.goBack': return 'Go back'; case 'webview.goForward': return 'Go forward'; + case 'webview.reload': return 'Reload'; + case 'webview.openInSystemBrowser': return 'Open in system browser'; + case 'webview.copyLinkClipboard': return 'Copy link to clipboard'; + case 'webview.linkCopiedClipboard': return 'Link copied to the clipboard.'; + case 'webview.share': return 'Share'; default: return null; } } @@ -426,6 +441,11 @@ extension on _StringsEs { case 'settings.disconnectFromServer': return 'Desconectar del servidor'; case 'webview.goBack': return 'Ir atrás'; case 'webview.goForward': return 'Ir adelante'; + case 'webview.reload': return 'Recargar'; + case 'webview.openInSystemBrowser': return 'Abrir en el navegador del sistema'; + case 'webview.copyLinkClipboard': return 'Copiar enlace al portapapeles'; + case 'webview.linkCopiedClipboard': return 'Enlace copiado al portapapeles.'; + case 'webview.share': return 'Compartir'; default: return null; } } diff --git a/lib/i18n/strings_en.i18n.json b/lib/i18n/strings_en.i18n.json index ed35a23..16f8fed 100644 --- a/lib/i18n/strings_en.i18n.json +++ b/lib/i18n/strings_en.i18n.json @@ -38,6 +38,11 @@ }, "webview": { "goBack": "Go back", - "goForward": "Go forward" + "goForward": "Go forward", + "reload": "Reload", + "openInSystemBrowser": "Open in system browser", + "copyLinkClipboard": "Copy link to clipboard", + "linkCopiedClipboard": "Link copied to the clipboard.", + "share": "Share" } } \ No newline at end of file diff --git a/lib/i18n/strings_es.i18n.json b/lib/i18n/strings_es.i18n.json index 1e2720a..9c6a14f 100644 --- a/lib/i18n/strings_es.i18n.json +++ b/lib/i18n/strings_es.i18n.json @@ -38,6 +38,11 @@ }, "webview": { "goBack": "Ir atrás", - "goForward": "Ir adelante" + "goForward": "Ir adelante", + "reload": "Recargar", + "openInSystemBrowser": "Abrir en el navegador del sistema", + "copyLinkClipboard": "Copiar enlace al portapapeles", + "linkCopiedClipboard": "Enlace copiado al portapapeles.", + "share": "Compartir" } } \ No newline at end of file diff --git a/lib/screens/webview/ui/webview.dart b/lib/screens/webview/ui/webview.dart index a9eefc6..cd86d76 100644 --- a/lib/screens/webview/ui/webview.dart +++ b/lib/screens/webview/ui/webview.dart @@ -1,11 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:share_plus/share_plus.dart'; import 'package:linkdy/screens/webview/provider/webview.provider.dart'; import 'package:linkdy/models/data/bookmarks.dart'; import 'package:linkdy/i18n/strings.g.dart'; +import 'package:linkdy/utils/copy_clipboard.dart'; +import 'package:linkdy/utils/open_url.dart'; class WebView extends ConsumerWidget { final Bookmark bookmark; @@ -81,21 +84,69 @@ class WebView extends ConsumerWidget { Padding( padding: const EdgeInsets.all(8.0), child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - IconButton( - onPressed: ref.watch(webViewProvider).canGoBack == true - ? () => ref.watch(webViewProvider).inAppWebViewController?.goBack() - : null, - icon: const Icon(Icons.arrow_back_rounded), - tooltip: t.webview.goForward, + Row( + children: [ + IconButton( + onPressed: ref.watch(webViewProvider).canGoBack == true + ? () => ref.watch(webViewProvider).inAppWebViewController?.goBack() + : null, + icon: const Icon(Icons.arrow_back_rounded), + tooltip: t.webview.goForward, + ), + const SizedBox(width: 8), + IconButton( + onPressed: ref.watch(webViewProvider).canGoForward == true + ? () => ref.watch(webViewProvider).inAppWebViewController?.goForward() + : null, + icon: const Icon(Icons.arrow_forward_rounded), + tooltip: t.webview.goForward, + ), + const SizedBox(width: 16), + IconButton( + onPressed: () => ref.watch(webViewProvider).inAppWebViewController?.reload(), + icon: const Icon(Icons.refresh_rounded), + tooltip: t.webview.reload, + ), + ], ), - const SizedBox(width: 8), - IconButton( - onPressed: ref.watch(webViewProvider).canGoForward == true - ? () => ref.watch(webViewProvider).inAppWebViewController?.goForward() - : null, - icon: const Icon(Icons.arrow_forward_rounded), - tooltip: t.webview.goForward, + PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + onTap: () => Share.shareUri(Uri.parse(bookmark.url!)), + child: Row( + children: [ + const Icon(Icons.share_rounded), + const SizedBox(width: 8), + Text(t.webview.share), + ], + ), + ), + PopupMenuItem( + onTap: () => copyToClipboard( + value: bookmark.url!, + successMessage: t.webview.linkCopiedClipboard, + ), + child: Row( + children: [ + const Icon(Icons.copy_rounded), + const SizedBox(width: 8), + Text(t.webview.copyLinkClipboard), + ], + ), + ), + PopupMenuItem( + onTap: () => openUrl(bookmark.url!), + child: Row( + children: [ + const Icon(Icons.open_in_browser_rounded), + const SizedBox(width: 8), + Text(t.webview.openInSystemBrowser), + ], + ), + ), + ], ), ], ), diff --git a/lib/utils/copy_clipboard.dart b/lib/utils/copy_clipboard.dart new file mode 100644 index 0000000..8cb0e8e --- /dev/null +++ b/lib/utils/copy_clipboard.dart @@ -0,0 +1,23 @@ +// ignore_for_file: use_build_context_synchronously + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'package:linkdy/constants/global_keys.dart'; + +void copyToClipboard({ + required String value, + required String successMessage, +}) async { + if (scaffoldMessengerGlobalKey.currentState != null) { + await Clipboard.setData( + ClipboardData(text: value), + ); + scaffoldMessengerGlobalKey.currentState!.showSnackBar( + SnackBar( + content: Text(successMessage), + backgroundColor: Colors.green, + ), + ); + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 440eb3c..17c0f0f 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,12 +7,16 @@ import Foundation import dynamic_color import flutter_inappwebview_macos +import path_provider_foundation +import share_plus import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index d27ac5f..e358e2d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e + url: "https://pub.dev" + source: hosted + version: "0.3.3+8" crypto: dependency: transitive description: @@ -661,6 +669,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -797,6 +829,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + share_plus: + dependency: "direct main" + description: + name: share_plus + sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900" + url: "https://pub.dev" + source: hosted + version: "7.2.2" + share_plus_platform_interface: + dependency: transitive + description: + name: share_plus_platform_interface + sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 + url: "https://pub.dev" + source: hosted + version: "3.3.1" shared_preferences: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 130665b..8b94c2f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,6 +48,7 @@ dependencies: flutter_svg: ^2.0.9 flutter_custom_tabs: ^2.0.0+1 flutter_inappwebview: ^6.0.0 + share_plus: ^7.2.2 dev_dependencies: build_runner: ^2.4.8 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 5ec53c0..1a40a84 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,11 +7,14 @@ #include "generated_plugin_registrant.h" #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { DynamicColorPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); + SharePlusWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index a311f66..9feb042 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST dynamic_color + share_plus url_launcher_windows )