Browse Source

Merge pull request #779 from nextcloud/feature/share-file-native

feat(neon_files): Implement sharing file natively
pull/873/head
Kate 1 year ago committed by GitHub
parent
commit
c6be3a77e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      packages/neon/neon/lib/src/platform/android.dart
  2. 3
      packages/neon/neon/lib/src/platform/linux.dart
  3. 2
      packages/neon/neon/lib/src/platform/platform.dart
  4. 40
      packages/neon/neon_files/lib/blocs/files.dart
  5. 1
      packages/neon/neon_files/lib/l10n/en.arb
  6. 6
      packages/neon/neon_files/lib/l10n/localizations.dart
  7. 3
      packages/neon/neon_files/lib/l10n/localizations_en.dart
  8. 1
      packages/neon/neon_files/lib/neon_files.dart
  9. 10
      packages/neon/neon_files/lib/widgets/actions.dart
  10. 1
      packages/neon/neon_files/pubspec.yaml

3
packages/neon/neon/lib/src/platform/android.dart

@ -28,6 +28,9 @@ class AndroidNeonPlatform implements NeonPlatform {
@override @override
bool get canUseWindowManager => false; bool get canUseWindowManager => false;
@override
bool get canUseSharing => true;
@override @override
Future<String> get userAccessibleAppDataPath async { Future<String> get userAccessibleAppDataPath async {
if (!await Permission.storage.request().isGranted) { if (!await Permission.storage.request().isGranted) {

3
packages/neon/neon/lib/src/platform/linux.dart

@ -28,6 +28,9 @@ class LinuxNeonPlatform implements NeonPlatform {
@override @override
bool get canUsePushNotifications => false; bool get canUsePushNotifications => false;
@override
bool get canUseSharing => false;
@override @override
String get userAccessibleAppDataPath => p.join(Platform.environment['HOME']!, 'Neon'); String get userAccessibleAppDataPath => p.join(Platform.environment['HOME']!, 'Neon');

2
packages/neon/neon/lib/src/platform/platform.dart

@ -57,6 +57,8 @@ abstract interface class NeonPlatform {
abstract final bool canUsePushNotifications; abstract final bool canUsePushNotifications;
abstract final bool canUseSharing;
FutureOr<String> get userAccessibleAppDataPath; FutureOr<String> get userAccessibleAppDataPath;
FutureOr<void> init(); FutureOr<void> init();

40
packages/neon/neon_files/lib/blocs/files.dart

@ -7,6 +7,8 @@ abstract interface class FilesBlocEvents {
void openFile(final List<String> path, final String etag, final String? mimeType); void openFile(final List<String> path, final String etag, final String? mimeType);
void shareFileNative(final List<String> path, final String etag);
void delete(final List<String> path); void delete(final List<String> path);
void rename(final List<String> path, final String name); void rename(final List<String> path, final String name);
@ -84,15 +86,8 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
void openFile(final List<String> path, final String etag, final String? mimeType) { void openFile(final List<String> path, final String etag, final String? mimeType) {
wrapAction( wrapAction(
() async { () async {
final cacheDir = await getApplicationCacheDirectory(); final file = await _cacheFile(path, etag);
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 result = await OpenFile.open(file.path, type: mimeType); final result = await OpenFile.open(file.path, type: mimeType);
if (result.type != ResultType.done) { if (result.type != ResultType.done) {
throw const UnableToOpenFileException(); throw const UnableToOpenFileException();
@ -102,6 +97,18 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
); );
} }
@override
void shareFileNative(final List<String> path, final String etag) {
wrapAction(
() async {
final file = await _cacheFile(path, etag);
await Share.shareXFiles([XFile(file.path)]);
},
disableTimeout: true,
);
}
@override @override
Future<void> refresh() async { Future<void> refresh() async {
await browser.refresh(); await browser.refresh();
@ -164,6 +171,21 @@ class FilesBloc extends InteractiveBloc implements FilesBlocEvents, FilesBlocSta
); );
} }
Future<File> _cacheFile(final List<String> 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<void> _downloadFile( Future<void> _downloadFile(
final List<String> path, final List<String> path,
final File file, final File file,

1
packages/neon/neon_files/lib/l10n/en.arb

@ -7,6 +7,7 @@
"actionMove": "Move", "actionMove": "Move",
"actionCopy": "Copy", "actionCopy": "Copy",
"actionSync": "Sync", "actionSync": "Sync",
"actionShare": "Share",
"errorUnableToOpenFile": "Unable to open the file", "errorUnableToOpenFile": "Unable to open the file",
"general": "General", "general": "General",
"goToPath": "Go to /{path}", "goToPath": "Go to /{path}",

6
packages/neon/neon_files/lib/l10n/localizations.dart

@ -131,6 +131,12 @@ abstract class AppLocalizations {
/// **'Sync'** /// **'Sync'**
String get actionSync; String get actionSync;
/// No description provided for @actionShare.
///
/// In en, this message translates to:
/// **'Share'**
String get actionShare;
/// No description provided for @errorUnableToOpenFile. /// No description provided for @errorUnableToOpenFile.
/// ///
/// In en, this message translates to: /// In en, this message translates to:

3
packages/neon/neon_files/lib/l10n/localizations_en.dart

@ -25,6 +25,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get actionSync => 'Sync'; String get actionSync => 'Sync';
@override
String get actionShare => 'Share';
@override @override
String get errorUnableToOpenFile => 'Unable to open the file'; String get errorUnableToOpenFile => 'Unable to open the file';

1
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:path_provider/path_provider.dart';
import 'package:queue/queue.dart'; import 'package:queue/queue.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
import 'package:share_plus/share_plus.dart';
part 'blocs/browser.dart'; part 'blocs/browser.dart';
part 'blocs/files.dart'; part 'blocs/files.dart';

10
packages/neon/neon_files/lib/widgets/actions.dart

@ -1,5 +1,6 @@
import 'package:filesize/filesize.dart'; import 'package:filesize/filesize.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:neon/platform.dart';
import 'package:neon/utils.dart'; import 'package:neon/utils.dart';
import 'package:neon_files/l10n/localizations.dart'; import 'package:neon_files/l10n/localizations.dart';
import 'package:neon_files/neon_files.dart'; import 'package:neon_files/neon_files.dart';
@ -16,6 +17,8 @@ class FileActions extends StatelessWidget {
final bloc = NeonProvider.of<FilesBloc>(context); final bloc = NeonProvider.of<FilesBloc>(context);
final browserBloc = bloc.browser; final browserBloc = bloc.browser;
switch (action) { switch (action) {
case FilesFileAction.share:
bloc.shareFileNative(details.path, details.etag!);
case FilesFileAction.toggleFavorite: case FilesFileAction.toggleFavorite:
if (details.isFavorite ?? false) { if (details.isFavorite ?? false) {
bloc.removeFavorite(details.path); bloc.removeFavorite(details.path);
@ -115,6 +118,12 @@ class FileActions extends StatelessWidget {
@override @override
Widget build(final BuildContext context) => PopupMenuButton<FilesFileAction>( Widget build(final BuildContext context) => PopupMenuButton<FilesFileAction>(
itemBuilder: (final context) => [ itemBuilder: (final context) => [
if (!details.isDirectory && NeonPlatform.instance.canUseSharing) ...[
PopupMenuItem(
value: FilesFileAction.share,
child: Text(AppLocalizations.of(context).actionShare),
),
],
if (details.isFavorite != null) ...[ if (details.isFavorite != null) ...[
PopupMenuItem( PopupMenuItem(
value: FilesFileAction.toggleFavorite, value: FilesFileAction.toggleFavorite,
@ -158,6 +167,7 @@ class FileActions extends StatelessWidget {
} }
enum FilesFileAction { enum FilesFileAction {
share,
toggleFavorite, toggleFavorite,
details, details,
rename, rename,

1
packages/neon/neon_files/pubspec.yaml

@ -33,6 +33,7 @@ dependencies:
provider: ^6.0.5 provider: ^6.0.5
queue: ^3.1.0+2 queue: ^3.1.0+2
rxdart: ^0.27.7 rxdart: ^0.27.7
share_plus: ^7.1.0
dev_dependencies: dev_dependencies:
build_runner: ^2.4.6 build_runner: ^2.4.6

Loading…
Cancel
Save