#53 viewer: copy to clipboard

This commit is contained in:
Thibault Deckers 2021-08-02 14:11:32 +09:00
parent aa577c8bc6
commit 888c5e567f
9 changed files with 56 additions and 8 deletions

View file

@ -1,8 +1,6 @@
package deckers.thibault.aves.channel.calls package deckers.thibault.aves.channel.calls
import android.content.ContentResolver import android.content.*
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.net.Uri import android.net.Uri
@ -32,6 +30,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
when (call.method) { when (call.method) {
"getPackages" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getPackages) } "getPackages" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::getPackages) }
"getAppIcon" -> GlobalScope.launch(Dispatchers.IO) { safesus(call, result, ::getAppIcon) } "getAppIcon" -> GlobalScope.launch(Dispatchers.IO) { safesus(call, result, ::getAppIcon) }
"copyToClipboard" -> GlobalScope.launch(Dispatchers.IO) { safe(call, result, ::copyToClipboard) }
"edit" -> { "edit" -> {
val title = call.argument<String>("title") val title = call.argument<String>("title")
val uri = call.argument<String>("uri")?.let { Uri.parse(it) } val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
@ -156,6 +155,24 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
} }
} }
private fun copyToClipboard(call: MethodCall, result: MethodChannel.Result) {
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
val label = call.argument<String>("label")
if (uri == null) {
result.error("copyToClipboard-args", "failed because of missing arguments", null)
return
}
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
if (clipboard != null) {
val clip = ClipData.newUri(context.contentResolver, label, getShareableUri(uri))
clipboard.setPrimaryClip(clip)
result.success(true)
} else {
result.success(false)
}
}
private fun edit(title: String?, uri: Uri?, mimeType: String?): Boolean { private fun edit(title: String?, uri: Uri?, mimeType: String?): Boolean {
uri ?: return false uri ?: return false

View file

@ -62,6 +62,8 @@
"chipActionCreateAlbum": "Create album", "chipActionCreateAlbum": "Create album",
"@chipActionCreateAlbum": {}, "@chipActionCreateAlbum": {},
"entryActionCopyToClipboard": "Copy to clipboard",
"@entryActionCopyToClipboard": {},
"entryActionDelete": "Delete", "entryActionDelete": "Delete",
"@entryActionDelete": {}, "@entryActionDelete": {},
"entryActionExport": "Export", "entryActionExport": "Export",

View file

@ -31,6 +31,7 @@
"chipActionSetCover": "대표 이미지 변경", "chipActionSetCover": "대표 이미지 변경",
"chipActionCreateAlbum": "앨범 만들기", "chipActionCreateAlbum": "앨범 만들기",
"entryActionCopyToClipboard": "클립보드에 복사",
"entryActionDelete": "삭제", "entryActionDelete": "삭제",
"entryActionExport": "내보내기", "entryActionExport": "내보내기",
"entryActionInfo": "상세정보", "entryActionInfo": "상세정보",

View file

@ -19,6 +19,7 @@ enum EntryAction {
// motion photo, // motion photo,
viewMotionPhotoVideo, viewMotionPhotoVideo,
// external // external
copyToClipboard,
edit, edit,
open, open,
openMap, openMap,
@ -42,6 +43,7 @@ class EntryActions {
EntryAction.delete, EntryAction.delete,
EntryAction.rename, EntryAction.rename,
EntryAction.export, EntryAction.export,
EntryAction.copyToClipboard,
EntryAction.print, EntryAction.print,
EntryAction.viewSource, EntryAction.viewSource,
EntryAction.viewMotionPhotoVideo, EntryAction.viewMotionPhotoVideo,
@ -68,6 +70,8 @@ extension ExtraEntryAction on EntryAction {
case EntryAction.toggleFavourite: case EntryAction.toggleFavourite:
// different data depending on toggle state // different data depending on toggle state
return context.l10n.entryActionAddFavourite; return context.l10n.entryActionAddFavourite;
case EntryAction.copyToClipboard:
return context.l10n.entryActionCopyToClipboard;
case EntryAction.delete: case EntryAction.delete:
return context.l10n.entryActionDelete; return context.l10n.entryActionDelete;
case EntryAction.export: case EntryAction.export:
@ -116,6 +120,8 @@ extension ExtraEntryAction on EntryAction {
case EntryAction.toggleFavourite: case EntryAction.toggleFavourite:
// different data depending on toggle state // different data depending on toggle state
return AIcons.favourite; return AIcons.favourite;
case EntryAction.copyToClipboard:
return AIcons.clipboard;
case EntryAction.delete: case EntryAction.delete:
return AIcons.delete; return AIcons.delete;
case EntryAction.export: case EntryAction.export:

View file

@ -38,6 +38,19 @@ class AndroidAppService {
return Uint8List(0); return Uint8List(0);
} }
static Future<bool> copyToClipboard(String uri, String? label) async {
try {
final result = await platform.invokeMethod('copyToClipboard', <String, dynamic>{
'uri': uri,
'label': label,
});
if (result != null) return result as bool;
} on PlatformException catch (e) {
debugPrint('copyToClipboard failed with code=${e.code}, exception=${e.message}, details=${e.details}');
}
return false;
}
static Future<bool> edit(String uri, String mimeType) async { static Future<bool> edit(String uri, String mimeType) async {
try { try {
final result = await platform.invokeMethod('edit', <String, dynamic>{ final result = await platform.invokeMethod('edit', <String, dynamic>{

View file

@ -36,6 +36,7 @@ class AIcons {
static const IconData skip10 = Icons.forward_10_outlined; static const IconData skip10 = Icons.forward_10_outlined;
static const IconData captureFrame = Icons.screenshot_outlined; static const IconData captureFrame = Icons.screenshot_outlined;
static const IconData clear = Icons.clear_outlined; static const IconData clear = Icons.clear_outlined;
static const IconData clipboard = Icons.content_copy_outlined;
static const IconData createAlbum = Icons.add_circle_outline; static const IconData createAlbum = Icons.add_circle_outline;
static const IconData debug = Icons.whatshot_outlined; static const IconData debug = Icons.whatshot_outlined;
static const IconData delete = Icons.delete_outlined; static const IconData delete = Icons.delete_outlined;

View file

@ -36,6 +36,7 @@ class ViewerActionEditorPage extends StatelessWidget {
EntryAction.delete, EntryAction.delete,
EntryAction.rename, EntryAction.rename,
EntryAction.export, EntryAction.export,
EntryAction.copyToClipboard,
EntryAction.print, EntryAction.print,
EntryAction.rotateScreen, EntryAction.rotateScreen,
EntryAction.flip, EntryAction.flip,

View file

@ -37,6 +37,11 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
case EntryAction.toggleFavourite: case EntryAction.toggleFavourite:
entry.toggleFavourite(); entry.toggleFavourite();
break; break;
case EntryAction.copyToClipboard:
AndroidAppService.copyToClipboard(entry.uri, entry.bestTitle).then((success) {
showFeedback(context, success ? context.l10n.genericSuccessFeedback : context.l10n.genericFailureFeedback);
});
break;
case EntryAction.delete: case EntryAction.delete:
_showDeleteDialog(context, entry); _showDeleteDialog(context, entry);
break; break;
@ -46,12 +51,12 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
case EntryAction.info: case EntryAction.info:
ShowInfoNotification().dispatch(context); ShowInfoNotification().dispatch(context);
break; break;
case EntryAction.rename:
_showRenameDialog(context, entry);
break;
case EntryAction.print: case EntryAction.print:
EntryPrinter(entry).print(context); EntryPrinter(entry).print(context);
break; break;
case EntryAction.rename:
_showRenameDialog(context, entry);
break;
case EntryAction.rotateCCW: case EntryAction.rotateCCW:
_rotate(context, entry, clockwise: false); _rotate(context, entry, clockwise: false);
break; break;

View file

@ -86,11 +86,12 @@ class ViewerTopOverlay extends StatelessWidget {
return targetEntry.isMotionPhoto; return targetEntry.isMotionPhoto;
case EntryAction.rotateScreen: case EntryAction.rotateScreen:
return settings.isRotationLocked; return settings.isRotationLocked;
case EntryAction.share: case EntryAction.copyToClipboard:
case EntryAction.edit:
case EntryAction.info: case EntryAction.info:
case EntryAction.open: case EntryAction.open:
case EntryAction.edit:
case EntryAction.setAs: case EntryAction.setAs:
case EntryAction.share:
return true; return true;
case EntryAction.debug: case EntryAction.debug:
return kDebugMode; return kDebugMode;
@ -197,6 +198,7 @@ class _TopOverlayRow extends StatelessWidget {
onPressed: onPressed, onPressed: onPressed,
); );
break; break;
case EntryAction.copyToClipboard:
case EntryAction.delete: case EntryAction.delete:
case EntryAction.export: case EntryAction.export:
case EntryAction.flip: case EntryAction.flip: