mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 16:56:19 +01:00
Share enhanced photos
This commit is contained in:
parent
65d8825b6b
commit
e088b1dbaa
6 changed files with 151 additions and 13 deletions
|
@ -102,6 +102,13 @@ class LocalFileRepo {
|
|||
}) =>
|
||||
dataSrc.deleteFiles(files, onFailure: onFailure);
|
||||
|
||||
/// See [LocalFileDataSource.shareFiles]
|
||||
Future<void> shareFiles(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
}) =>
|
||||
dataSrc.shareFiles(files, onFailure: onFailure);
|
||||
|
||||
final LocalFileDataSource dataSrc;
|
||||
}
|
||||
|
||||
|
@ -114,4 +121,10 @@ abstract class LocalFileDataSource {
|
|||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
});
|
||||
|
||||
/// Share files
|
||||
Future<void> shareFiles(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:nc_photos/entity/local_file.dart';
|
|||
import 'package:nc_photos/iterable_extension.dart';
|
||||
import 'package:nc_photos/mobile/android/android_info.dart';
|
||||
import 'package:nc_photos/mobile/android/k.dart' as android;
|
||||
import 'package:nc_photos/mobile/share.dart';
|
||||
import 'package:nc_photos/object_extension.dart';
|
||||
import 'package:nc_photos/stream_extension.dart';
|
||||
import 'package:nc_photos_plugin/nc_photos_plugin.dart';
|
||||
|
@ -28,19 +29,9 @@ class LocalFileMediaStoreDataSource implements LocalFileDataSource {
|
|||
LocalFileOnFailureListener? onFailure,
|
||||
}) async {
|
||||
_log.info("[deleteFiles] ${files.map((f) => f.logTag).toReadableString()}");
|
||||
final uriFiles = files
|
||||
.where((f) {
|
||||
if (f is! LocalUriFile) {
|
||||
_log.warning(
|
||||
"[deleteFiles] Can't remove file not returned by this data source: $f");
|
||||
onFailure?.call(f, ArgumentError("File not supported"), null);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.cast<LocalUriFile>()
|
||||
.toList();
|
||||
final uriFiles = _filterUriFiles(files, (f) {
|
||||
onFailure?.call(f, ArgumentError("File not supported"), null);
|
||||
});
|
||||
if (AndroidInfo().sdkInt >= AndroidVersion.R) {
|
||||
await _deleteFiles30(uriFiles, onFailure);
|
||||
} else {
|
||||
|
@ -48,6 +39,27 @@ class LocalFileMediaStoreDataSource implements LocalFileDataSource {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
shareFiles(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
}) async {
|
||||
_log.info("[shareFiles] ${files.map((f) => f.logTag).toReadableString()}");
|
||||
final uriFiles = _filterUriFiles(files, (f) {
|
||||
onFailure?.call(f, ArgumentError("File not supported"), null);
|
||||
});
|
||||
|
||||
final share = AndroidFileShare(uriFiles.map((e) => e.uri).toList(),
|
||||
uriFiles.map((e) => e.mime).toList());
|
||||
try {
|
||||
await share.share();
|
||||
} catch (e, stackTrace) {
|
||||
for (final f in uriFiles) {
|
||||
onFailure?.call(f, e, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _deleteFiles30(
|
||||
List<LocalUriFile> files, LocalFileOnFailureListener? onFailure) async {
|
||||
assert(AndroidInfo().sdkInt >= AndroidVersion.R);
|
||||
|
@ -79,6 +91,25 @@ class LocalFileMediaStoreDataSource implements LocalFileDataSource {
|
|||
}
|
||||
}
|
||||
|
||||
List<LocalUriFile> _filterUriFiles(
|
||||
List<LocalFile> files, [
|
||||
void Function(LocalFile)? nonUriFileCallback,
|
||||
]) {
|
||||
return files
|
||||
.where((f) {
|
||||
if (f is! LocalUriFile) {
|
||||
_log.warning(
|
||||
"[deleteFiles] Can't remove file not returned by this data source: $f");
|
||||
nonUriFileCallback?.call(f);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.cast<LocalUriFile>()
|
||||
.toList();
|
||||
}
|
||||
|
||||
static LocalFile _toLocalFile(MediaStoreQueryResult r) => LocalUriFile(
|
||||
uri: r.uri,
|
||||
displayName: r.displayName,
|
||||
|
|
|
@ -3,12 +3,16 @@ import 'dart:math';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:kiwi/kiwi.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/app_db.dart';
|
||||
import 'package:nc_photos/app_localizations.dart';
|
||||
import 'package:nc_photos/debug_util.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/file.dart';
|
||||
import 'package:nc_photos/entity/file/data_source.dart';
|
||||
import 'package:nc_photos/entity/local_file.dart';
|
||||
import 'package:nc_photos/entity/share.dart';
|
||||
import 'package:nc_photos/entity/share/data_source.dart';
|
||||
import 'package:nc_photos/exception_util.dart' as exception_util;
|
||||
|
@ -22,6 +26,7 @@ import 'package:nc_photos/use_case/copy.dart';
|
|||
import 'package:nc_photos/use_case/create_dir.dart';
|
||||
import 'package:nc_photos/use_case/create_share.dart';
|
||||
import 'package:nc_photos/use_case/download_file.dart';
|
||||
import 'package:nc_photos/use_case/share_local.dart';
|
||||
import 'package:nc_photos/widget/processing_dialog.dart';
|
||||
import 'package:nc_photos/widget/share_link_multiple_files_dialog.dart';
|
||||
import 'package:nc_photos/widget/share_method_dialog.dart';
|
||||
|
@ -36,6 +41,32 @@ class ShareHandler {
|
|||
this.clearSelection,
|
||||
});
|
||||
|
||||
Future<void> shareLocalFiles(List<LocalFile> files) async {
|
||||
if (!isSelectionCleared) {
|
||||
clearSelection?.call();
|
||||
}
|
||||
final c = KiwiContainer().resolve<DiContainer>();
|
||||
var hasShownError = false;
|
||||
await ShareLocal(c)(
|
||||
files,
|
||||
onFailure: (f, e, stackTrace) {
|
||||
if (e != null) {
|
||||
_log.shout(
|
||||
"[shareLocalFiles] Failed while sharing file: ${logFilename(f.logTag)}",
|
||||
e,
|
||||
stackTrace);
|
||||
if (!hasShownError) {
|
||||
SnackBarManager().showSnackBar(SnackBar(
|
||||
content: Text(exception_util.toUserString(e)),
|
||||
duration: k.snackBarDurationNormal,
|
||||
));
|
||||
hasShownError = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shareFiles(Account account, List<File> files) async {
|
||||
try {
|
||||
final method = await _askShareMethod();
|
||||
|
|
26
app/lib/use_case/share_local.dart
Normal file
26
app/lib/use_case/share_local.dart
Normal file
|
@ -0,0 +1,26 @@
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/di_container.dart';
|
||||
import 'package:nc_photos/entity/local_file.dart';
|
||||
|
||||
class ShareLocal {
|
||||
ShareLocal(this._c) : assert(require(_c));
|
||||
|
||||
static bool require(DiContainer c) =>
|
||||
DiContainer.has(c, DiType.localFileRepo);
|
||||
|
||||
Future<void> call(
|
||||
List<LocalFile> files, {
|
||||
LocalFileOnFailureListener? onFailure,
|
||||
}) async {
|
||||
var count = files.length;
|
||||
await _c.localFileRepo.shareFiles(files, onFailure: (f, e, stackTrace) {
|
||||
--count;
|
||||
onFailure?.call(f, e, stackTrace);
|
||||
});
|
||||
_log.info("[call] Shared $count files successfully");
|
||||
}
|
||||
|
||||
final DiContainer _c;
|
||||
|
||||
static final _log = Logger("use_case.share_local.ShareLocal");
|
||||
}
|
|
@ -11,6 +11,7 @@ import 'package:nc_photos/iterable_extension.dart';
|
|||
import 'package:nc_photos/k.dart' as k;
|
||||
import 'package:nc_photos/mobile/android/content_uri_image_provider.dart';
|
||||
import 'package:nc_photos/pref.dart';
|
||||
import 'package:nc_photos/share_handler.dart';
|
||||
import 'package:nc_photos/snack_bar_manager.dart';
|
||||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/widget/empty_list_indicator.dart';
|
||||
|
@ -160,6 +161,13 @@ class _EnhancedPhotoBrowserState extends State<EnhancedPhotoBrowser>
|
|||
});
|
||||
},
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.share),
|
||||
tooltip: L10n.global().shareTooltip,
|
||||
onPressed: () {
|
||||
_onSelectionSharePressed(context);
|
||||
},
|
||||
),
|
||||
PopupMenuButton<_SelectionMenuOption>(
|
||||
tooltip: MaterialLocalizations.of(context).moreButtonTooltip,
|
||||
itemBuilder: (context) => [
|
||||
|
@ -198,6 +206,21 @@ class _EnhancedPhotoBrowserState extends State<EnhancedPhotoBrowser>
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> _onSelectionSharePressed(BuildContext context) async {
|
||||
final selected = selectedListItems
|
||||
.whereType<_FileListItem>()
|
||||
.map((e) => e.file)
|
||||
.toList();
|
||||
await ShareHandler(
|
||||
context: context,
|
||||
clearSelection: () {
|
||||
setState(() {
|
||||
clearSelectedItems();
|
||||
});
|
||||
},
|
||||
).shareLocalFiles(selected);
|
||||
}
|
||||
|
||||
void _onSelectionMenuSelected(
|
||||
BuildContext context, _SelectionMenuOption option) {
|
||||
switch (option) {
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:logging/logging.dart';
|
|||
import 'package:nc_photos/app_localizations.dart';
|
||||
import 'package:nc_photos/entity/file_util.dart' as file_util;
|
||||
import 'package:nc_photos/entity/local_file.dart';
|
||||
import 'package:nc_photos/share_handler.dart';
|
||||
import 'package:nc_photos/theme.dart';
|
||||
import 'package:nc_photos/widget/handler/delete_local_selection_handler.dart';
|
||||
import 'package:nc_photos/widget/horizontal_page_viewer.dart';
|
||||
|
@ -108,6 +109,13 @@ class _LocalFileViewerState extends State<LocalFileViewer> {
|
|||
shadowColor: Colors.transparent,
|
||||
foregroundColor: Colors.white.withOpacity(.87),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.share),
|
||||
tooltip: L10n.global().shareTooltip,
|
||||
onPressed: () {
|
||||
_onSharePressed(context);
|
||||
},
|
||||
),
|
||||
PopupMenuButton<_AppBarMenuOption>(
|
||||
tooltip: MaterialLocalizations.of(context).moreButtonTooltip,
|
||||
itemBuilder: (context) => [
|
||||
|
@ -126,6 +134,12 @@ class _LocalFileViewerState extends State<LocalFileViewer> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _onSharePressed(BuildContext context) async {
|
||||
final file = widget.streamFiles[_viewerController.currentPage];
|
||||
_log.info("[_onSharePressed] Sharing file: ${file.logTag}");
|
||||
await ShareHandler(context: context).shareLocalFiles([file]);
|
||||
}
|
||||
|
||||
void _onMenuSelected(BuildContext context, _AppBarMenuOption option) {
|
||||
switch (option) {
|
||||
case _AppBarMenuOption.delete:
|
||||
|
|
Loading…
Reference in a new issue