diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6a08502c..e76779da3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Changed
+
+- Viewer: allow setting default outside video player
+
## [v1.7.7] - 2022-11-27
### Added
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppAdapterHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppAdapterHandler.kt
index 0ac6bf607..bf68b220b 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppAdapterHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AppAdapterHandler.kt
@@ -232,7 +232,8 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
val title = call.argument("title")
val uri = call.argument("uri")?.let { Uri.parse(it) }
val mimeType = call.argument("mimeType")
- if (uri == null) {
+ val forceChooser = call.argument("forceChooser")
+ if (uri == null || forceChooser == null) {
result.error("open-args", "missing arguments", null)
return
}
@@ -240,7 +241,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
val intent = Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setDataAndType(getShareableUri(context, uri), mimeType)
- val started = safeStartActivityChooser(title, intent)
+ val started = if (forceChooser) safeStartActivityChooser(title, intent) else safeStartActivity(intent)
result.success(started)
}
diff --git a/lib/model/actions/entry_actions.dart b/lib/model/actions/entry_actions.dart
index cb6dabebb..a03fa7fc7 100644
--- a/lib/model/actions/entry_actions.dart
+++ b/lib/model/actions/entry_actions.dart
@@ -34,6 +34,7 @@ enum EntryAction {
// external
edit,
open,
+ openVideo,
openMap,
setAs,
// platform
@@ -191,6 +192,7 @@ extension ExtraEntryAction on EntryAction {
case EntryAction.edit:
return context.l10n.entryActionEdit;
case EntryAction.open:
+ case EntryAction.openVideo:
return context.l10n.entryActionOpen;
case EntryAction.openMap:
return context.l10n.entryActionOpenMap;
@@ -302,6 +304,7 @@ extension ExtraEntryAction on EntryAction {
case EntryAction.edit:
return AIcons.edit;
case EntryAction.open:
+ case EntryAction.openVideo:
return AIcons.openOutside;
case EntryAction.openMap:
return AIcons.map;
diff --git a/lib/services/android_app_service.dart b/lib/services/android_app_service.dart
index b21f4ee8d..71ba0ca6e 100644
--- a/lib/services/android_app_service.dart
+++ b/lib/services/android_app_service.dart
@@ -16,7 +16,7 @@ abstract class AndroidAppService {
Future edit(String uri, String mimeType);
- Future open(String uri, String mimeType);
+ Future open(String uri, String mimeType, {required bool forceChooser});
Future openMap(LatLng latLng);
@@ -101,11 +101,12 @@ class PlatformAndroidAppService implements AndroidAppService {
}
@override
- Future open(String uri, String mimeType) async {
+ Future open(String uri, String mimeType, {required bool forceChooser}) async {
try {
final result = await _platform.invokeMethod('open', {
'uri': uri,
'mimeType': mimeType,
+ 'forceChooser': forceChooser,
});
if (result != null) return result as bool;
} on PlatformException catch (e, stack) {
diff --git a/lib/widgets/dialogs/aves_selection_dialog.dart b/lib/widgets/dialogs/aves_selection_dialog.dart
index 9e12b0b02..15dce1fe0 100644
--- a/lib/widgets/dialogs/aves_selection_dialog.dart
+++ b/lib/widgets/dialogs/aves_selection_dialog.dart
@@ -58,12 +58,13 @@ class _AvesSelectionDialogState extends State> {
Widget build(BuildContext context) {
final title = widget.title;
final message = widget.message;
+ final verticalPadding = (title == null && message == null) ? AvesDialog.cornerRadius.y / 2 : .0;
final confirmationButtonLabel = widget.confirmationButtonLabel;
final needConfirmation = confirmationButtonLabel != null;
return AvesDialog(
title: title,
scrollableContent: [
- if (title == null && message == null) SizedBox(height: AvesDialog.cornerRadius.y / 2),
+ if (verticalPadding != 0) SizedBox(height: verticalPadding),
if (message != null)
Padding(
padding: const EdgeInsets.all(16),
@@ -82,6 +83,7 @@ class _AvesSelectionDialogState extends State> {
setGroupValue: (v) => setState(() => _selectedValue = v),
);
}),
+ if (verticalPadding != 0) SizedBox(height: verticalPadding),
],
actions: [
TextButton(
diff --git a/lib/widgets/viewer/action/entry_action_delegate.dart b/lib/widgets/viewer/action/entry_action_delegate.dart
index 9311227db..1e20fcf34 100644
--- a/lib/widgets/viewer/action/entry_action_delegate.dart
+++ b/lib/widgets/viewer/action/entry_action_delegate.dart
@@ -93,6 +93,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
case EntryAction.videoTogglePlay:
case EntryAction.videoReplay10:
case EntryAction.videoSkip10:
+ case EntryAction.openVideo:
return targetEntry.isVideo;
case EntryAction.rotateScreen:
return settings.isRotationLocked;
@@ -225,6 +226,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
case EntryAction.videoTogglePlay:
case EntryAction.videoReplay10:
case EntryAction.videoSkip10:
+ case EntryAction.openVideo:
final controller = context.read().getController(targetEntry);
if (controller != null) {
VideoActionNotification(controller: controller, action: action).dispatch(context);
@@ -236,7 +238,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
});
break;
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);
});
break;
diff --git a/lib/widgets/viewer/embedded/embedded_data_opener.dart b/lib/widgets/viewer/embedded/embedded_data_opener.dart
index 7349fa289..288a9c256 100644
--- a/lib/widgets/viewer/embedded/embedded_data_opener.dart
+++ b/lib/widgets/viewer/embedded/embedded_data_opener.dart
@@ -54,7 +54,7 @@ class EmbeddedDataOpener extends StatelessWidget with FeedbackMixin {
final uri = fields['uri']!;
if (!MimeTypes.isImage(mimeType) && !MimeTypes.isVideo(mimeType)) {
// open with another app
- unawaited(androidAppService.open(uri, mimeType).then((success) {
+ unawaited(androidAppService.open(uri, mimeType, forceChooser: true).then((success) {
if (!success) {
// fallback to sharing, so that the file can be saved somewhere
androidAppService.shareSingle(uri, mimeType).then((success) {
diff --git a/lib/widgets/viewer/overlay/video/controls.dart b/lib/widgets/viewer/overlay/video/controls.dart
index 90f096566..8b06bb2c6 100644
--- a/lib/widgets/viewer/overlay/video/controls.dart
+++ b/lib/widgets/viewer/overlay/video/controls.dart
@@ -66,7 +66,7 @@ class VideoControlRow extends StatelessWidget {
final trashed = controller?.entry.trashed ?? false;
return Padding(
padding: const EdgeInsetsDirectional.only(start: padding),
- child: _buildIconButton(context, EntryAction.open, enabled: !trashed),
+ child: _buildIconButton(context, EntryAction.openVideo, enabled: !trashed),
);
case VideoControls.none:
return const SizedBox();
diff --git a/lib/widgets/viewer/overlay/video/video.dart b/lib/widgets/viewer/overlay/video/video.dart
index e0a2d9e4b..6a57af95e 100644
--- a/lib/widgets/viewer/overlay/video/video.dart
+++ b/lib/widgets/viewer/overlay/video/video.dart
@@ -46,7 +46,7 @@ class _VideoControlOverlayState extends State with SingleTi
final status = controller?.status ?? VideoStatus.idle;
if (status == VideoStatus.error) {
- const action = EntryAction.open;
+ const action = EntryAction.openVideo;
return Align(
alignment: AlignmentDirectional.centerEnd,
child: OverlayButton(
diff --git a/lib/widgets/viewer/video_action_delegate.dart b/lib/widgets/viewer/video_action_delegate.dart
index 5cb382709..a23e5bee0 100644
--- a/lib/widgets/viewer/video_action_delegate.dart
+++ b/lib/widgets/viewer/video_action_delegate.dart
@@ -65,9 +65,9 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
case EntryAction.videoSkip10:
await controller.seekTo(controller.currentPosition + 10000);
break;
- case EntryAction.open:
+ case EntryAction.openVideo:
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);
});
break;