diff --git a/packages/neon/neon/lib/src/platform/android.dart b/packages/neon/neon/lib/src/platform/android.dart index 93c27089..d4d905c5 100644 --- a/packages/neon/neon/lib/src/platform/android.dart +++ b/packages/neon/neon/lib/src/platform/android.dart @@ -28,6 +28,9 @@ class AndroidNeonPlatform implements NeonPlatform { @override bool get canUseWindowManager => false; + @override + bool get canUseSharing => true; + @override Future get userAccessibleAppDataPath async { if (!await Permission.storage.request().isGranted) { diff --git a/packages/neon/neon/lib/src/platform/linux.dart b/packages/neon/neon/lib/src/platform/linux.dart index 594124a4..144f0072 100644 --- a/packages/neon/neon/lib/src/platform/linux.dart +++ b/packages/neon/neon/lib/src/platform/linux.dart @@ -28,6 +28,9 @@ class LinuxNeonPlatform implements NeonPlatform { @override bool get canUsePushNotifications => false; + @override + bool get canUseSharing => false; + @override String get userAccessibleAppDataPath => p.join(Platform.environment['HOME']!, 'Neon'); diff --git a/packages/neon/neon/lib/src/platform/platform.dart b/packages/neon/neon/lib/src/platform/platform.dart index d4e53fd6..283be64f 100644 --- a/packages/neon/neon/lib/src/platform/platform.dart +++ b/packages/neon/neon/lib/src/platform/platform.dart @@ -57,6 +57,8 @@ abstract interface class NeonPlatform { abstract final bool canUsePushNotifications; + abstract final bool canUseSharing; + FutureOr get userAccessibleAppDataPath; FutureOr init(); diff --git a/packages/neon/neon_files/lib/blocs/files.dart b/packages/neon/neon_files/lib/blocs/files.dart index b8aae030..476c9152 100644 --- a/packages/neon/neon_files/lib/blocs/files.dart +++ b/packages/neon/neon_files/lib/blocs/files.dart @@ -7,6 +7,8 @@ abstract interface class FilesBlocEvents { void openFile(final List path, final String etag, final String? mimeType); + void shareFileNative(final List path, final String etag); + void delete(final List path); void rename(final List path, final String name); @@ -84,15 +86,8 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta void openFile(final List path, final String etag, final String? mimeType) { wrapAction( () async { - final cacheDir = await getApplicationCacheDirectory(); - final file = File(p.join(cacheDir.path, 'files', etag.replaceAll('"', ''), path.last)); - if (!file.existsSync()) { - debugPrint('Downloading ${Uri(pathSegments: path)} since it does not exist'); - if (!file.parent.existsSync()) { - await file.parent.create(recursive: true); - } - await _downloadFile(path, file); - } + final file = await _cacheFile(path, etag); + final result = await OpenFile.open(file.path, type: mimeType); if (result.type != ResultType.done) { throw const UnableToOpenFileException(); @@ -102,6 +97,18 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta ); } + @override + void shareFileNative(final List path, final String etag) { + wrapAction( + () async { + final file = await _cacheFile(path, etag); + + await Share.shareXFiles([XFile(file.path)]); + }, + disableTimeout: true, + ); + } + @override Future refresh() async { await browser.refresh(); @@ -164,6 +171,21 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta ); } + Future _cacheFile(final List path, final String etag) async { + final cacheDir = await getApplicationCacheDirectory(); + final file = File(p.join(cacheDir.path, 'files', etag.replaceAll('"', ''), path.last)); + + if (!file.existsSync()) { + debugPrint('Downloading ${Uri(pathSegments: path)} since it does not exist'); + if (!file.parent.existsSync()) { + await file.parent.create(recursive: true); + } + await _downloadFile(path, file); + } + + return file; + } + Future _downloadFile( final List path, final File file, diff --git a/packages/neon/neon_files/lib/l10n/en.arb b/packages/neon/neon_files/lib/l10n/en.arb index 8a347043..5ec332df 100644 --- a/packages/neon/neon_files/lib/l10n/en.arb +++ b/packages/neon/neon_files/lib/l10n/en.arb @@ -7,6 +7,7 @@ "actionMove": "Move", "actionCopy": "Copy", "actionSync": "Sync", + "actionShare": "Share", "errorUnableToOpenFile": "Unable to open the file", "general": "General", "goToPath": "Go to /{path}", diff --git a/packages/neon/neon_files/lib/l10n/localizations.dart b/packages/neon/neon_files/lib/l10n/localizations.dart index 1914ad2c..3ddbf98c 100644 --- a/packages/neon/neon_files/lib/l10n/localizations.dart +++ b/packages/neon/neon_files/lib/l10n/localizations.dart @@ -131,6 +131,12 @@ abstract class AppLocalizations { /// **'Sync'** String get actionSync; + /// No description provided for @actionShare. + /// + /// In en, this message translates to: + /// **'Share'** + String get actionShare; + /// No description provided for @errorUnableToOpenFile. /// /// In en, this message translates to: diff --git a/packages/neon/neon_files/lib/l10n/localizations_en.dart b/packages/neon/neon_files/lib/l10n/localizations_en.dart index adb1bd35..1db3c6f2 100644 --- a/packages/neon/neon_files/lib/l10n/localizations_en.dart +++ b/packages/neon/neon_files/lib/l10n/localizations_en.dart @@ -25,6 +25,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get actionSync => 'Sync'; + @override + String get actionShare => 'Share'; + @override String get errorUnableToOpenFile => 'Unable to open the file'; diff --git a/packages/neon/neon_files/lib/neon_files.dart b/packages/neon/neon_files/lib/neon_files.dart index e7563c43..92681aae 100644 --- a/packages/neon/neon_files/lib/neon_files.dart +++ b/packages/neon/neon_files/lib/neon_files.dart @@ -29,6 +29,7 @@ import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:queue/queue.dart'; import 'package:rxdart/rxdart.dart'; +import 'package:share_plus/share_plus.dart'; part 'blocs/browser.dart'; part 'blocs/files.dart'; diff --git a/packages/neon/neon_files/lib/widgets/actions.dart b/packages/neon/neon_files/lib/widgets/actions.dart index c0612de4..751aa5fb 100644 --- a/packages/neon/neon_files/lib/widgets/actions.dart +++ b/packages/neon/neon_files/lib/widgets/actions.dart @@ -1,5 +1,6 @@ import 'package:filesize/filesize.dart'; import 'package:flutter/material.dart'; +import 'package:neon/platform.dart'; import 'package:neon/utils.dart'; import 'package:neon_files/l10n/localizations.dart'; import 'package:neon_files/neon_files.dart'; @@ -16,6 +17,8 @@ class FileActions extends StatelessWidget { final bloc = NeonProvider.of(context); final browserBloc = bloc.browser; switch (action) { + case FilesFileAction.share: + bloc.shareFileNative(details.path, details.etag!); case FilesFileAction.toggleFavorite: if (details.isFavorite ?? false) { bloc.removeFavorite(details.path); @@ -115,6 +118,12 @@ class FileActions extends StatelessWidget { @override Widget build(final BuildContext context) => PopupMenuButton( itemBuilder: (final context) => [ + if (!details.isDirectory && NeonPlatform.instance.canUseSharing) ...[ + PopupMenuItem( + value: FilesFileAction.share, + child: Text(AppLocalizations.of(context).actionShare), + ), + ], if (details.isFavorite != null) ...[ PopupMenuItem( value: FilesFileAction.toggleFavorite, @@ -158,6 +167,7 @@ class FileActions extends StatelessWidget { } enum FilesFileAction { + share, toggleFavorite, details, rename, diff --git a/packages/neon/neon_files/pubspec.yaml b/packages/neon/neon_files/pubspec.yaml index 63240df8..bf234bde 100644 --- a/packages/neon/neon_files/pubspec.yaml +++ b/packages/neon/neon_files/pubspec.yaml @@ -33,6 +33,7 @@ dependencies: provider: ^6.0.5 queue: ^3.1.0+2 rxdart: ^0.27.7 + share_plus: ^7.1.0 dev_dependencies: build_runner: ^2.4.6