diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/multimedia/MultimediaImageFragment.kt b/AnkiDroid/src/main/java/com/ichi2/anki/multimedia/MultimediaImageFragment.kt index 33c7c64222e1..4a2fb8d00ac3 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/multimedia/MultimediaImageFragment.kt +++ b/AnkiDroid/src/main/java/com/ichi2/anki/multimedia/MultimediaImageFragment.kt @@ -25,6 +25,7 @@ import android.net.Uri import android.os.Bundle import android.provider.MediaStore import android.view.View +import android.webkit.WebView import android.widget.ImageView import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts @@ -68,6 +69,8 @@ import java.io.FileOutputStream import java.io.IOException import java.text.DecimalFormat +private const val SVG_IMAGE = "image/svg+xml" + @NeedsTest("Ensure correct option is executed i.e. gallery or camera") class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_image) { override val title: String @@ -96,7 +99,6 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ } Activity.RESULT_OK -> { - view?.findViewById(R.id.no_image_textview)?.visibility = View.GONE val data = result.data if (data == null) { Timber.w("handleSelectImageIntent() no intent provided") @@ -128,7 +130,6 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ } Activity.RESULT_OK -> { - view?.findViewById(R.id.no_image_textview)?.visibility = View.GONE val intent = result.data ?: return@registerForActivityResult Timber.d("Intent not null, handling the result") handleDrawingResult(intent) @@ -154,7 +155,6 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ isPictureTaken -> { Timber.d("Image successfully captured") - view?.findViewById(R.id.no_image_textview)?.visibility = View.GONE handleTakePictureResult(viewModel.currentMultimediaPath.value) } @@ -274,7 +274,6 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ private fun handleImageUri() { if (imageUri != null) { - view?.findViewById(R.id.no_image_textview)?.visibility = View.GONE handleSelectImageIntent(imageUri) } else { handleSelectedImageOptions() @@ -443,19 +442,6 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ private fun handleSelectImageIntent(imageUri: Uri?) { val mimeType = imageUri?.let { context?.contentResolver?.getType(it) } - if (mimeType == "image/svg+xml") { - Timber.i("Selected image is an SVG.") - view?.findViewById(R.id.no_image_textview)?.apply { - text = resources.getString(R.string.multimedia_editor_svg_preview) - visibility = View.VISIBLE - } - } else { - // reset the no preview text - view?.findViewById(R.id.no_image_textview)?.apply { - text = null - visibility = View.GONE - } - } if (imageUri == null) { Timber.w("handleSelectImageIntent() selectedImage was null") @@ -463,6 +449,28 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ return } + if (mimeType == SVG_IMAGE) { + Timber.i("Selected image is an SVG.") + + view?.findViewById(R.id.image_preview)?.visibility = View.GONE + + view?.findViewById(R.id.multimedia_webview)?.apply { + visibility = View.VISIBLE + + imageUri.let { imageData -> + val svgData = loadSvgFromUri(imageData) + svgData?.let { + loadDataWithBaseURL(null, it, SVG_IMAGE, "UTF-8", null) + } ?: run { + Timber.w("Failed to load SVG from URI") + view?.findViewById(R.id.image_preview)?.setImageResource(R.drawable.ic_image_not_supported) + } + } + } + } else { + view?.findViewById(R.id.image_preview)?.visibility = View.VISIBLE + } + val internalizedPick = internalizeUri(imageUri) if (internalizedPick == null) { Timber.w( @@ -488,6 +496,22 @@ class MultimediaImageFragment : MultimediaFragment(R.layout.fragment_multimedia_ imageCropperLauncher.launch(intent) } + /** + * Loads an SVG file from the given URI and returns its content as a string. + * + * @param uri The URI of the SVG file to be loaded. + * @return The content of the SVG file as a string, or null if an error occurs. + */ + private fun loadSvgFromUri(uri: Uri): String? { + return try { + val inputStream = context?.contentResolver?.openInputStream(uri) + inputStream?.bufferedReader()?.use { it.readText() } + } catch (e: Exception) { + Timber.e(e, "Error reading SVG from URI") + null + } + } + private fun handleCropResultError(error: Exception) { // cropImage can give us more information. Not sure it is actionable so for now just log it. Timber.w(error, "cropImage threw an error") diff --git a/AnkiDroid/src/main/res/layout/fragment_multimedia_image.xml b/AnkiDroid/src/main/res/layout/fragment_multimedia_image.xml index 207fca38f2f9..e2fa8997a5f4 100644 --- a/AnkiDroid/src/main/res/layout/fragment_multimedia_image.xml +++ b/AnkiDroid/src/main/res/layout/fragment_multimedia_image.xml @@ -34,14 +34,6 @@ app:layout_constraintBottom_toTopOf="@id/image_size_textview" style="@style/CardView.PreviewerStyle" > - - + + Something went wrong - SVGs are not available for preview Error converting clipboard image to png: %s Attach multimedia content to the %1$s field