fix: image sharing fails due to coroutine scope cancellation
The share media dialog used `rememberCoroutineScope()` which shadowed the outer `accountViewModel.viewModelScope`. When onDismiss() was called immediately after launching the share coroutine, the dialog-scoped coroutine was cancelled, causing CancellationException to be caught as a generic error and showing "Unable to share image" toast. Fix: use viewModelScope for share operations so they survive dialog dismissal, and re-throw CancellationException in shareImageFile. https://claude.ai/code/session_01Euj5mXfjneNCx9m49YTp92
This commit is contained in:
+5
-4
@@ -762,7 +762,7 @@ fun ShareMediaAction(
|
|||||||
content: BaseMediaContent? = null,
|
content: BaseMediaContent? = null,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
) {
|
) {
|
||||||
val scope = accountViewModel.viewModelScope
|
val viewModelScope = accountViewModel.viewModelScope
|
||||||
|
|
||||||
// Track if video is downloading - hoisted here to block menu dismiss during download
|
// Track if video is downloading - hoisted here to block menu dismiss during download
|
||||||
val isDownloadingVideo = remember { mutableStateOf(false) }
|
val isDownloadingVideo = remember { mutableStateOf(false) }
|
||||||
@@ -817,7 +817,7 @@ fun ShareMediaAction(
|
|||||||
videoUri?.let {
|
videoUri?.let {
|
||||||
if (videoUri.isNotEmpty()) {
|
if (videoUri.isNotEmpty()) {
|
||||||
M3ActionRow(icon = Icons.Outlined.Share, text = stringRes(R.string.share_image)) {
|
M3ActionRow(icon = Icons.Outlined.Share, text = stringRes(R.string.share_image)) {
|
||||||
scope.launch { shareImageFile(context, videoUri, mimeType) }
|
viewModelScope.launch { shareImageFile(context, videoUri, mimeType) }
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -833,7 +833,7 @@ fun ShareMediaAction(
|
|||||||
enabled = !isDownloadingVideo.value,
|
enabled = !isDownloadingVideo.value,
|
||||||
) {
|
) {
|
||||||
isDownloadingVideo.value = true
|
isDownloadingVideo.value = true
|
||||||
scope.launch {
|
viewModelScope.launch {
|
||||||
shareVideoFile(
|
shareVideoFile(
|
||||||
context = context,
|
context = context,
|
||||||
videoUrl = videoUri,
|
videoUrl = videoUri,
|
||||||
@@ -858,7 +858,7 @@ fun ShareMediaAction(
|
|||||||
is MediaLocalVideo -> {
|
is MediaLocalVideo -> {
|
||||||
content.localFile?.let { localFile ->
|
content.localFile?.let { localFile ->
|
||||||
M3ActionRow(icon = Icons.Outlined.Share, text = stringRes(R.string.share_video)) {
|
M3ActionRow(icon = Icons.Outlined.Share, text = stringRes(R.string.share_video)) {
|
||||||
scope.launch { shareLocalVideoFile(context, localFile, mimeType) }
|
viewModelScope.launch { shareLocalVideoFile(context, localFile, mimeType) }
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -894,6 +894,7 @@ private suspend fun shareImageFile(
|
|||||||
|
|
||||||
context.startActivity(Intent.createChooser(shareIntent, null))
|
context.startActivity(Intent.createChooser(shareIntent, null))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
if (e is CancellationException) throw e
|
||||||
Log.w("ZoomableContentView", "Failed to share image: $videoUri", e)
|
Log.w("ZoomableContentView", "Failed to share image: $videoUri", e)
|
||||||
Toast.makeText(context, context.getString(R.string.unable_to_share_image), Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, context.getString(R.string.unable_to_share_image), Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user