Merge pull request #2133 from davotoula/fix-image-sharing-error

Fix image sharing error
This commit is contained in:
Vitor Pamplona
2026-04-05 11:42:41 -04:00
committed by GitHub
3 changed files with 121 additions and 8 deletions
@@ -85,11 +85,11 @@ object ShareHelper {
} ?: throw IOException("Unable to open snapshot for: $imageUrl")
}
private fun getImageExtension(file: File): String = getMediaExtension(file, isVideo = false)
internal fun getImageExtension(file: File): String = getMediaExtension(file, isVideo = false)
private fun getVideoExtension(file: File): String = getMediaExtension(file, isVideo = true)
internal fun getVideoExtension(file: File): String = getMediaExtension(file, isVideo = true)
private fun getMediaExtension(
internal fun getMediaExtension(
file: File,
isVideo: Boolean,
): String {
@@ -762,8 +762,6 @@ fun ShareMediaAction(
content: BaseMediaContent? = null,
accountViewModel: AccountViewModel,
) {
val scope = accountViewModel.viewModelScope
// Track if video is downloading - hoisted here to block menu dismiss during download
val isDownloadingVideo = remember { mutableStateOf(false) }
@@ -817,7 +815,7 @@ fun ShareMediaAction(
videoUri?.let {
if (videoUri.isNotEmpty()) {
M3ActionRow(icon = Icons.Outlined.Share, text = stringRes(R.string.share_image)) {
scope.launch { shareImageFile(context, videoUri, mimeType) }
accountViewModel.viewModelScope.launch { shareImageFile(context, videoUri, mimeType) }
onDismiss()
}
}
@@ -834,7 +832,7 @@ fun ShareMediaAction(
) {
isDownloadingVideo.value = true
accountViewModel.toastManager.toast(R.string.share_video, R.string.downloading_video_for_sharing)
scope.launch {
accountViewModel.viewModelScope.launch {
shareVideoFile(
context = context,
videoUrl = videoUri,
@@ -859,7 +857,7 @@ fun ShareMediaAction(
is MediaLocalVideo -> {
content.localFile?.let { localFile ->
M3ActionRow(icon = Icons.Outlined.Share, text = stringRes(R.string.share_video)) {
scope.launch { shareLocalVideoFile(context, localFile, mimeType) }
accountViewModel.viewModelScope.launch { shareLocalVideoFile(context, localFile, mimeType) }
onDismiss()
}
}
@@ -895,6 +893,7 @@ private suspend fun shareImageFile(
context.startActivity(Intent.createChooser(shareIntent, null))
} catch (e: Exception) {
if (e is CancellationException) throw 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()
}
@@ -49,4 +49,118 @@ class ShareHelperTest {
targetFile.delete()
tempDir.delete()
}
@Test
fun getImageExtension_jpeg() {
val file = createTempFileWithBytes(byteArrayOf(0xFF.toByte(), 0xD8.toByte(), 0x00, 0x00))
assertEquals("jpg", ShareHelper.getImageExtension(file))
file.delete()
}
@Test
fun getImageExtension_png() {
val file = createTempFileWithBytes(byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A))
assertEquals("png", ShareHelper.getImageExtension(file))
file.delete()
}
@Test
fun getImageExtension_gif() {
val file = createTempFileWithBytes("GIF89a".toByteArray())
assertEquals("gif", ShareHelper.getImageExtension(file))
file.delete()
}
@Test
fun getImageExtension_webp() {
// RIFF....WEBP
val header = ByteArray(12)
"RIFF".toByteArray().copyInto(header, 0)
"WEBP".toByteArray().copyInto(header, 8)
val file = createTempFileWithBytes(header)
assertEquals("webp", ShareHelper.getImageExtension(file))
file.delete()
}
@Test
fun getImageExtension_unknownDefaultsToJpg() {
val file = createTempFileWithBytes(byteArrayOf(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07))
assertEquals("jpg", ShareHelper.getImageExtension(file))
file.delete()
}
@Test
fun getImageExtension_tooShortDefaultsToJpg() {
val file = createTempFileWithBytes(byteArrayOf(0x00, 0x01))
assertEquals("jpg", ShareHelper.getImageExtension(file))
file.delete()
}
@Test
fun getVideoExtension_webm() {
val file = createTempFileWithBytes(byteArrayOf(0x1A, 0x45, 0xDF.toByte(), 0xA3.toByte(), 0x00, 0x00))
assertEquals("webm", ShareHelper.getVideoExtension(file))
file.delete()
}
@Test
fun getVideoExtension_avi() {
// RIFF....AVI
val header = ByteArray(12)
"RIFF".toByteArray().copyInto(header, 0)
"AVI ".toByteArray().copyInto(header, 8)
val file = createTempFileWithBytes(header)
assertEquals("avi", ShareHelper.getVideoExtension(file))
file.delete()
}
@Test
fun getVideoExtension_mp4Isom() {
// ....ftypisom
val header = ByteArray(12)
"ftyp".toByteArray().copyInto(header, 4)
"isom".toByteArray().copyInto(header, 8)
val file = createTempFileWithBytes(header)
assertEquals("mp4", ShareHelper.getVideoExtension(file))
file.delete()
}
@Test
fun getVideoExtension_mov() {
// ....ftypqt__
val header = ByteArray(12)
"ftyp".toByteArray().copyInto(header, 4)
"qt ".toByteArray().copyInto(header, 8)
val file = createTempFileWithBytes(header)
assertEquals("mov", ShareHelper.getVideoExtension(file))
file.delete()
}
@Test
fun getVideoExtension_unknownDefaultsToMp4() {
val file = createTempFileWithBytes(byteArrayOf(0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07))
assertEquals("mp4", ShareHelper.getVideoExtension(file))
file.delete()
}
@Test
fun getMediaExtension_emptyFileDefaultsToImage() {
val file = createTempFileWithBytes(byteArrayOf())
assertEquals("jpg", ShareHelper.getMediaExtension(file, isVideo = false))
file.delete()
}
@Test
fun getMediaExtension_emptyFileDefaultsToVideo() {
val file = createTempFileWithBytes(byteArrayOf())
assertEquals("mp4", ShareHelper.getMediaExtension(file, isVideo = true))
file.delete()
}
private fun createTempFileWithBytes(bytes: ByteArray): File {
val file = File.createTempFile("sharehelpertest", ".tmp")
file.deleteOnExit()
file.writeBytes(bytes)
return file
}
}