diff --git a/app/build.gradle b/app/build.gradle index 99bd79aab..52526e8b5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,6 +58,8 @@ dependencies { implementation 'org.apache.sanselan:sanselan:0.97-incubator' implementation 'info.androidhive:imagefilters:1.0.7' implementation 'com.squareup.picasso:picasso:2.71828' + implementation 'com.caverock:androidsvg-aar:1.3' + kapt 'com.github.bumptech.glide:compiler:4.8.0' kapt "android.arch.persistence.room:compiler:1.1.1" implementation "android.arch.persistence.room:runtime:1.1.1" diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt index 843554e6d..644db9dde 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/activities/ViewPagerActivity.kt @@ -290,7 +290,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View findItem(R.id.menu_properties).isVisible = visibleBottomActions and BOTTOM_ACTION_PROPERTIES == 0 findItem(R.id.menu_delete).isVisible = visibleBottomActions and BOTTOM_ACTION_DELETE == 0 findItem(R.id.menu_share).isVisible = visibleBottomActions and BOTTOM_ACTION_SHARE == 0 - findItem(R.id.menu_edit).isVisible = visibleBottomActions and BOTTOM_ACTION_EDIT == 0 + findItem(R.id.menu_edit).isVisible = visibleBottomActions and BOTTOM_ACTION_EDIT == 0 && !currentMedium.isSVG() findItem(R.id.menu_rename).isVisible = visibleBottomActions and BOTTOM_ACTION_RENAME == 0 && !currentMedium.getIsInRecycleBin() findItem(R.id.menu_rotate).isVisible = currentMedium.isImage() && visibleBottomActions and BOTTOM_ACTION_ROTATE == 0 findItem(R.id.menu_set_as).isVisible = visibleBottomActions and BOTTOM_ACTION_SET_AS == 0 @@ -459,7 +459,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View private fun scheduleSwipe() { mSlideshowHandler.removeCallbacksAndMessages(null) if (mIsSlideshowActive) { - if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGif()) { + if (getCurrentMedium()!!.isImage() || getCurrentMedium()!!.isGIF()) { mSlideshowHandler.postDelayed({ if (mIsSlideshowActive && !isActivityDestroyed()) { swipeToNextMedium() @@ -482,11 +482,11 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View } if (!config.slideshowIncludeVideos) { - mSlideshowMedia = mSlideshowMedia.filter { it.isImage() || it.isGif() } as MutableList + mSlideshowMedia = mSlideshowMedia.filter { it.isImage() || it.isGIF() } as MutableList } if (!config.slideshowIncludeGIFs) { - mSlideshowMedia = mSlideshowMedia.filter { !it.isGif() } as MutableList + mSlideshowMedia = mSlideshowMedia.filter { !it.isGIF() } as MutableList } if (config.slideshowRandomOrder) { @@ -776,7 +776,7 @@ class ViewPagerActivity : SimpleActivity(), ViewPager.OnPageChangeListener, View toggleFavorite() } - bottom_edit.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_EDIT != 0) + bottom_edit.beVisibleIf(visibleBottomActions and BOTTOM_ACTION_EDIT != 0 && getCurrentMedium()?.isSVG() == false) bottom_edit.setOnClickListener { openEditor(getCurrentPath()) } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/ArrayList.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/ArrayList.kt index 6a25113e7..b72d4cf52 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/ArrayList.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/extensions/ArrayList.kt @@ -13,7 +13,7 @@ fun ArrayList.getDirMediaTypes(): Int { types += TYPE_VIDEOS } - if (any { it.isGif() }) { + if (any { it.isGIF() }) { types += TYPE_GIFS } @@ -21,7 +21,7 @@ fun ArrayList.getDirMediaTypes(): Int { types += TYPE_RAWS } - if (any { it.isSvg() }) { + if (any { it.isSVG() }) { types += TYPE_SVGS } diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt index 1ab3c2ef6..59635ce31 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/fragments/PhotoFragment.kt @@ -8,6 +8,7 @@ import android.graphics.BitmapFactory import android.graphics.Color import android.graphics.Matrix import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.PictureDrawable import android.media.ExifInterface.* import android.net.Uri import android.os.Bundle @@ -36,6 +37,7 @@ import com.simplemobiletools.gallery.activities.ViewPagerActivity import com.simplemobiletools.gallery.extensions.* import com.simplemobiletools.gallery.helpers.* import com.simplemobiletools.gallery.models.Medium +import com.simplemobiletools.gallery.svg.SvgSoftwareLayerSetter import com.squareup.picasso.Callback import com.squareup.picasso.Picasso import it.sephiroth.android.library.exif2.ExifInterface @@ -165,7 +167,7 @@ class PhotoFragment : ViewPagerFragment() { super.setMenuVisibility(menuVisible) isFragmentVisible = menuVisible if (wasInit) { - if (medium.isGif()) { + if (medium.isGIF()) { gifFragmentVisibilityChanged(menuVisible) } else { photoFragmentVisibilityChanged(menuVisible) @@ -233,10 +235,10 @@ class PhotoFragment : ViewPagerFragment() { private fun loadImage() { imageOrientation = getImageOrientation() - if (medium.isGif()) { - loadGif() - } else { - loadBitmap() + when { + medium.isGIF() -> loadGif() + medium.isSVG() -> loadSVG() + else -> loadBitmap() } } @@ -263,6 +265,14 @@ class PhotoFragment : ViewPagerFragment() { } } + private fun loadSVG() { + Glide.with(this) + .`as`(PictureDrawable::class.java) + .listener(SvgSoftwareLayerSetter()) + .load(medium.path) + .into(view.photo_view) + } + private fun loadBitmap(degrees: Int = 0) { var targetWidth = ViewPagerActivity.screenWidth var targetHeight = ViewPagerActivity.screenHeight diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt index 4728a21a5..14d804178 100644 --- a/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/models/Medium.kt @@ -32,7 +32,7 @@ data class Medium( private const val serialVersionUID = -6553149366975655L } - fun isGif() = type == TYPE_GIFS + fun isGIF() = type == TYPE_GIFS fun isImage() = type == TYPE_IMAGES @@ -40,7 +40,7 @@ data class Medium( fun isRaw() = type == TYPE_RAWS - fun isSvg() = type == TYPE_SVGS + fun isSVG() = type == TYPE_SVGS fun isHidden() = name.startsWith('.') diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgDecoder.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgDecoder.kt new file mode 100644 index 000000000..3765db0e3 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgDecoder.kt @@ -0,0 +1,26 @@ +package com.simplemobiletools.gallery.svg + +import com.bumptech.glide.load.Options +import com.bumptech.glide.load.ResourceDecoder +import com.bumptech.glide.load.engine.Resource +import com.bumptech.glide.load.resource.SimpleResource +import com.caverock.androidsvg.SVG +import com.caverock.androidsvg.SVGParseException + +import java.io.IOException +import java.io.InputStream + +class SvgDecoder : ResourceDecoder { + + override fun handles(source: InputStream, options: Options) = true + + @Throws(IOException::class) + override fun decode(source: InputStream, width: Int, height: Int, options: Options): Resource? { + try { + val svg = SVG.getFromInputStream(source) + return SimpleResource(svg) + } catch (ex: SVGParseException) { + throw IOException("Cannot load SVG from stream", ex) + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgDrawableTranscoder.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgDrawableTranscoder.kt new file mode 100644 index 000000000..96dbe3492 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgDrawableTranscoder.kt @@ -0,0 +1,17 @@ +package com.simplemobiletools.gallery.svg + +import android.graphics.drawable.PictureDrawable +import com.bumptech.glide.load.Options +import com.bumptech.glide.load.engine.Resource +import com.bumptech.glide.load.resource.SimpleResource +import com.bumptech.glide.load.resource.transcode.ResourceTranscoder +import com.caverock.androidsvg.SVG + +class SvgDrawableTranscoder : ResourceTranscoder { + override fun transcode(toTranscode: Resource, options: Options): Resource? { + val svg = toTranscode.get() + val picture = svg.renderToPicture() + val drawable = PictureDrawable(picture) + return SimpleResource(drawable) + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgModule.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgModule.kt new file mode 100644 index 000000000..a6e4f3efb --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgModule.kt @@ -0,0 +1,21 @@ +package com.simplemobiletools.gallery.svg + +import android.content.Context +import android.graphics.drawable.PictureDrawable + +import com.bumptech.glide.Glide +import com.bumptech.glide.Registry +import com.bumptech.glide.annotation.GlideModule +import com.bumptech.glide.module.AppGlideModule +import com.caverock.androidsvg.SVG + +import java.io.InputStream + +@GlideModule +class SvgModule : AppGlideModule() { + override fun registerComponents(context: Context, glide: Glide, registry: Registry) { + registry.register(SVG::class.java, PictureDrawable::class.java, SvgDrawableTranscoder()).append(InputStream::class.java, SVG::class.java, SvgDecoder()) + } + + override fun isManifestParsingEnabled() = false +} diff --git a/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgSoftwareLayerSetter.kt b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgSoftwareLayerSetter.kt new file mode 100644 index 000000000..043d26e27 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/gallery/svg/SvgSoftwareLayerSetter.kt @@ -0,0 +1,25 @@ +package com.simplemobiletools.gallery.svg + +import android.graphics.drawable.PictureDrawable +import android.widget.ImageView + +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.ImageViewTarget +import com.bumptech.glide.request.target.Target + +class SvgSoftwareLayerSetter : RequestListener { + + override fun onLoadFailed(e: GlideException?, model: Any, target: Target, isFirstResource: Boolean): Boolean { + val view = (target as ImageViewTarget<*>).view + view.setLayerType(ImageView.LAYER_TYPE_NONE, null) + return false + } + + override fun onResourceReady(resource: PictureDrawable, model: Any, target: Target, dataSource: DataSource, isFirstResource: Boolean): Boolean { + val view = (target as ImageViewTarget<*>).view + view.setLayerType(ImageView.LAYER_TYPE_SOFTWARE, null) + return false + } +}