allow setting default outside video player
This commit is contained in:
parent
25a8c1145c
commit
f9c2156fed
10 changed files with 24 additions and 11 deletions
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <a id="unreleased"></a>[Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Viewer: allow setting default outside video player
|
||||||
|
|
||||||
## <a id="v1.7.7"></a>[v1.7.7] - 2022-11-27
|
## <a id="v1.7.7"></a>[v1.7.7] - 2022-11-27
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -232,7 +232,8 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
||||||
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) }
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
if (uri == null) {
|
val forceChooser = call.argument<Boolean>("forceChooser")
|
||||||
|
if (uri == null || forceChooser == null) {
|
||||||
result.error("open-args", "missing arguments", null)
|
result.error("open-args", "missing arguments", null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -240,7 +241,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
||||||
val intent = Intent(Intent.ACTION_VIEW)
|
val intent = Intent(Intent.ACTION_VIEW)
|
||||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||||
.setDataAndType(getShareableUri(context, uri), mimeType)
|
.setDataAndType(getShareableUri(context, uri), mimeType)
|
||||||
val started = safeStartActivityChooser(title, intent)
|
val started = if (forceChooser) safeStartActivityChooser(title, intent) else safeStartActivity(intent)
|
||||||
|
|
||||||
result.success(started)
|
result.success(started)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ enum EntryAction {
|
||||||
// external
|
// external
|
||||||
edit,
|
edit,
|
||||||
open,
|
open,
|
||||||
|
openVideo,
|
||||||
openMap,
|
openMap,
|
||||||
setAs,
|
setAs,
|
||||||
// platform
|
// platform
|
||||||
|
@ -191,6 +192,7 @@ extension ExtraEntryAction on EntryAction {
|
||||||
case EntryAction.edit:
|
case EntryAction.edit:
|
||||||
return context.l10n.entryActionEdit;
|
return context.l10n.entryActionEdit;
|
||||||
case EntryAction.open:
|
case EntryAction.open:
|
||||||
|
case EntryAction.openVideo:
|
||||||
return context.l10n.entryActionOpen;
|
return context.l10n.entryActionOpen;
|
||||||
case EntryAction.openMap:
|
case EntryAction.openMap:
|
||||||
return context.l10n.entryActionOpenMap;
|
return context.l10n.entryActionOpenMap;
|
||||||
|
@ -302,6 +304,7 @@ extension ExtraEntryAction on EntryAction {
|
||||||
case EntryAction.edit:
|
case EntryAction.edit:
|
||||||
return AIcons.edit;
|
return AIcons.edit;
|
||||||
case EntryAction.open:
|
case EntryAction.open:
|
||||||
|
case EntryAction.openVideo:
|
||||||
return AIcons.openOutside;
|
return AIcons.openOutside;
|
||||||
case EntryAction.openMap:
|
case EntryAction.openMap:
|
||||||
return AIcons.map;
|
return AIcons.map;
|
||||||
|
|
|
@ -16,7 +16,7 @@ abstract class AndroidAppService {
|
||||||
|
|
||||||
Future<bool> edit(String uri, String mimeType);
|
Future<bool> edit(String uri, String mimeType);
|
||||||
|
|
||||||
Future<bool> open(String uri, String mimeType);
|
Future<bool> open(String uri, String mimeType, {required bool forceChooser});
|
||||||
|
|
||||||
Future<bool> openMap(LatLng latLng);
|
Future<bool> openMap(LatLng latLng);
|
||||||
|
|
||||||
|
@ -101,11 +101,12 @@ class PlatformAndroidAppService implements AndroidAppService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> open(String uri, String mimeType) async {
|
Future<bool> open(String uri, String mimeType, {required bool forceChooser}) async {
|
||||||
try {
|
try {
|
||||||
final result = await _platform.invokeMethod('open', <String, dynamic>{
|
final result = await _platform.invokeMethod('open', <String, dynamic>{
|
||||||
'uri': uri,
|
'uri': uri,
|
||||||
'mimeType': mimeType,
|
'mimeType': mimeType,
|
||||||
|
'forceChooser': forceChooser,
|
||||||
});
|
});
|
||||||
if (result != null) return result as bool;
|
if (result != null) return result as bool;
|
||||||
} on PlatformException catch (e, stack) {
|
} on PlatformException catch (e, stack) {
|
||||||
|
|
|
@ -58,12 +58,13 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final title = widget.title;
|
final title = widget.title;
|
||||||
final message = widget.message;
|
final message = widget.message;
|
||||||
|
final verticalPadding = (title == null && message == null) ? AvesDialog.cornerRadius.y / 2 : .0;
|
||||||
final confirmationButtonLabel = widget.confirmationButtonLabel;
|
final confirmationButtonLabel = widget.confirmationButtonLabel;
|
||||||
final needConfirmation = confirmationButtonLabel != null;
|
final needConfirmation = confirmationButtonLabel != null;
|
||||||
return AvesDialog(
|
return AvesDialog(
|
||||||
title: title,
|
title: title,
|
||||||
scrollableContent: [
|
scrollableContent: [
|
||||||
if (title == null && message == null) SizedBox(height: AvesDialog.cornerRadius.y / 2),
|
if (verticalPadding != 0) SizedBox(height: verticalPadding),
|
||||||
if (message != null)
|
if (message != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
|
@ -82,6 +83,7 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
|
||||||
setGroupValue: (v) => setState(() => _selectedValue = v),
|
setGroupValue: (v) => setState(() => _selectedValue = v),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
if (verticalPadding != 0) SizedBox(height: verticalPadding),
|
||||||
],
|
],
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
|
|
|
@ -93,6 +93,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
case EntryAction.videoTogglePlay:
|
case EntryAction.videoTogglePlay:
|
||||||
case EntryAction.videoReplay10:
|
case EntryAction.videoReplay10:
|
||||||
case EntryAction.videoSkip10:
|
case EntryAction.videoSkip10:
|
||||||
|
case EntryAction.openVideo:
|
||||||
return targetEntry.isVideo;
|
return targetEntry.isVideo;
|
||||||
case EntryAction.rotateScreen:
|
case EntryAction.rotateScreen:
|
||||||
return settings.isRotationLocked;
|
return settings.isRotationLocked;
|
||||||
|
@ -225,6 +226,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
case EntryAction.videoTogglePlay:
|
case EntryAction.videoTogglePlay:
|
||||||
case EntryAction.videoReplay10:
|
case EntryAction.videoReplay10:
|
||||||
case EntryAction.videoSkip10:
|
case EntryAction.videoSkip10:
|
||||||
|
case EntryAction.openVideo:
|
||||||
final controller = context.read<VideoConductor>().getController(targetEntry);
|
final controller = context.read<VideoConductor>().getController(targetEntry);
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
VideoActionNotification(controller: controller, action: action).dispatch(context);
|
VideoActionNotification(controller: controller, action: action).dispatch(context);
|
||||||
|
@ -236,7 +238,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case EntryAction.open:
|
case EntryAction.open:
|
||||||
androidAppService.open(targetEntry.uri, targetEntry.mimeTypeAnySubtype).then((success) {
|
androidAppService.open(targetEntry.uri, targetEntry.mimeTypeAnySubtype, forceChooser: true).then((success) {
|
||||||
if (!success) showNoMatchingAppDialog(context);
|
if (!success) showNoMatchingAppDialog(context);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -54,7 +54,7 @@ class EmbeddedDataOpener extends StatelessWidget with FeedbackMixin {
|
||||||
final uri = fields['uri']!;
|
final uri = fields['uri']!;
|
||||||
if (!MimeTypes.isImage(mimeType) && !MimeTypes.isVideo(mimeType)) {
|
if (!MimeTypes.isImage(mimeType) && !MimeTypes.isVideo(mimeType)) {
|
||||||
// open with another app
|
// open with another app
|
||||||
unawaited(androidAppService.open(uri, mimeType).then((success) {
|
unawaited(androidAppService.open(uri, mimeType, forceChooser: true).then((success) {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// fallback to sharing, so that the file can be saved somewhere
|
// fallback to sharing, so that the file can be saved somewhere
|
||||||
androidAppService.shareSingle(uri, mimeType).then((success) {
|
androidAppService.shareSingle(uri, mimeType).then((success) {
|
||||||
|
|
|
@ -66,7 +66,7 @@ class VideoControlRow extends StatelessWidget {
|
||||||
final trashed = controller?.entry.trashed ?? false;
|
final trashed = controller?.entry.trashed ?? false;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsetsDirectional.only(start: padding),
|
padding: const EdgeInsetsDirectional.only(start: padding),
|
||||||
child: _buildIconButton(context, EntryAction.open, enabled: !trashed),
|
child: _buildIconButton(context, EntryAction.openVideo, enabled: !trashed),
|
||||||
);
|
);
|
||||||
case VideoControls.none:
|
case VideoControls.none:
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
|
|
|
@ -46,7 +46,7 @@ class _VideoControlOverlayState extends State<VideoControlOverlay> with SingleTi
|
||||||
final status = controller?.status ?? VideoStatus.idle;
|
final status = controller?.status ?? VideoStatus.idle;
|
||||||
|
|
||||||
if (status == VideoStatus.error) {
|
if (status == VideoStatus.error) {
|
||||||
const action = EntryAction.open;
|
const action = EntryAction.openVideo;
|
||||||
return Align(
|
return Align(
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: OverlayButton(
|
child: OverlayButton(
|
||||||
|
|
|
@ -65,9 +65,9 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
||||||
case EntryAction.videoSkip10:
|
case EntryAction.videoSkip10:
|
||||||
await controller.seekTo(controller.currentPosition + 10000);
|
await controller.seekTo(controller.currentPosition + 10000);
|
||||||
break;
|
break;
|
||||||
case EntryAction.open:
|
case EntryAction.openVideo:
|
||||||
final entry = controller.entry;
|
final entry = controller.entry;
|
||||||
await androidAppService.open(entry.uri, entry.mimeTypeAnySubtype).then((success) {
|
await androidAppService.open(entry.uri, entry.mimeTypeAnySubtype, forceChooser: false).then((success) {
|
||||||
if (!success) showNoMatchingAppDialog(context);
|
if (!success) showNoMatchingAppDialog(context);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue