From 040c845c15b0cf96940356e391ac8a8c556b4824 Mon Sep 17 00:00:00 2001 From: davidoskky Date: Fri, 18 Dec 2020 23:45:34 +0100 Subject: [PATCH] Store article images in cache in background. --- .../api/selfoss/SelfossModels.kt | 29 +++++++++++++++ .../readerforselfoss/background/background.kt | 1 + .../fragments/ArticleFragment.kt | 32 +++++++++++++++-- .../fragments/ImageFragment.kt | 35 +++++++++++++++++++ .../utils/glide/GlideUtils.kt | 10 ++++++ 5 files changed, 104 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt index eac6397..b11e475 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt @@ -5,10 +5,15 @@ import android.net.Uri import android.os.Parcel import android.os.Parcelable import android.text.Html +import android.util.Log +import android.webkit.URLUtil import org.jsoup.Jsoup import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions import com.google.gson.annotations.SerializedName private fun constructUrl(config: Config?, path: String, file: String?): String { @@ -138,6 +143,30 @@ data class Item( return allImages } + fun preloadImages(context: Context) : Boolean { + val imageUrls = this.getImages() + Log.d("Carica", "Caricando immagini") + + val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL) + + + try { + for (url in imageUrls) { + Log.d("Carica", url) + if ( URLUtil.isValidUrl(url)) { + val image = Glide.with(context).asBitmap() + .apply(glideOptions) + .load(url).submit().get() + } + Log.d("Carica", "Immagine presa") + } + } catch (e : Error) { + return false + } + + return true + } + fun getTitleDecoded(): String { return Html.fromHtml(title).toString() } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/background/background.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/background/background.kt index a3d18d5..1cfb88c 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/background/background.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/background/background.kt @@ -104,6 +104,7 @@ class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(con notificationManager.notify(2, newItemsNotification.build()) } } + apiItems.map {it.preloadImages(context)} } Timer("", false).schedule(4000) { notificationManager.cancel(1) diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt index 9f4fc63..6daa8a6 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ArticleFragment.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.content.SharedPreferences import android.content.res.ColorStateList import android.content.res.TypedArray +import android.graphics.Bitmap import android.graphics.Typeface import android.graphics.drawable.ColorDrawable import android.net.Uri @@ -12,12 +13,12 @@ import android.os.Build import android.os.Bundle import android.preference.PreferenceManager import android.view.* +import android.webkit.* import androidx.browser.customtabs.CustomTabsIntent import com.google.android.material.floatingactionbutton.FloatingActionButton import androidx.fragment.app.Fragment import androidx.core.content.ContextCompat import androidx.core.widget.NestedScrollView -import android.webkit.WebSettings import androidx.appcompat.app.AlertDialog import androidx.core.content.res.ResourcesCompat import androidx.room.Room @@ -36,15 +37,15 @@ import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.glide.loadMaybeBasicAuth +import apps.amine.bou.readerforselfoss.utils.glide.getBitmapInputStream import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible import apps.amine.bou.readerforselfoss.utils.openItemUrl import apps.amine.bou.readerforselfoss.utils.shareLink import apps.amine.bou.readerforselfoss.utils.sourceAndDateText import apps.amine.bou.readerforselfoss.utils.succeeded -import android.webkit.WebView -import android.webkit.WebViewClient import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.request.RequestOptions import com.github.rubensousa.floatingtoolbar.FloatingToolbar import kotlinx.android.synthetic.main.fragment_article.view.* @@ -53,6 +54,7 @@ import retrofit2.Callback import retrofit2.Response import java.net.MalformedURLException import java.net.URL +import java.util.concurrent.ExecutionException import kotlin.collections.ArrayList import kotlin.concurrent.thread @@ -420,6 +422,30 @@ class ArticleFragment : Fragment() { } return true } + + override fun shouldInterceptRequest(view: WebView?, url: String): WebResourceResponse? { + val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL) + if (url.toLowerCase().contains(".jpg") || url.toLowerCase().contains(".jpeg")) { + try { + val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() + return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.JPEG)) + }catch ( e : ExecutionException) {} + } + else if (url.toLowerCase().contains(".png")) { + try { + val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() + return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.PNG)) + }catch ( e : ExecutionException) {} + } + else if (url.toLowerCase().contains(".webp")) { + try { + val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() + return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.WEBP)) + }catch ( e : ExecutionException) {} + } + + return super.shouldInterceptRequest(view, url) + } } val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt index f241169..1b4df1b 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/fragments/ImageFragment.kt @@ -1,11 +1,20 @@ package apps.amine.bou.readerforselfoss.fragments +import android.graphics.Bitmap import android.os.Bundle import android.view.* +import android.webkit.WebResourceResponse +import android.webkit.WebView +import android.webkit.WebViewClient import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import apps.amine.bou.readerforselfoss.R +import apps.amine.bou.readerforselfoss.utils.glide.getBitmapInputStream +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.RequestOptions import kotlinx.android.synthetic.main.fragment_article.view.webcontent +import java.util.concurrent.ExecutionException import kotlin.math.abs class ImageFragment : Fragment() { @@ -33,6 +42,32 @@ class ImageFragment : Fragment() { view.webcontent.settings.setBuiltInZoomControls(true) view.webcontent.settings.setDisplayZoomControls(false) + view.webcontent.webViewClient = object : WebViewClient() { + override fun shouldInterceptRequest(view: WebView?, url: String): WebResourceResponse? { + val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL) + if (url.toLowerCase().contains(".jpg") || url.toLowerCase().contains(".jpeg")) { + try { + val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() + return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.JPEG)) + }catch ( e : ExecutionException) {} + } + else if (url.toLowerCase().contains(".png")) { + try { + val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() + return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.PNG)) + }catch ( e : ExecutionException) {} + } + else if (url.toLowerCase().contains(".webp")) { + try { + val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get() + return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.WEBP)) + }catch ( e : ExecutionException) {} + } + + return super.shouldInterceptRequest(view, url) + } + } + val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() { override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean { val SWIPE_MIN_DISTANCE = 120 diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/glide/GlideUtils.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/glide/GlideUtils.kt index ea29a70..9183126 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/glide/GlideUtils.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/glide/GlideUtils.kt @@ -14,6 +14,9 @@ import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.LazyHeaders import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.BitmapImageViewTarget +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.InputStream fun Context.bitmapCenterCrop(config: Config, url: String, iv: ImageView) = Glide.with(this) @@ -56,4 +59,11 @@ fun RequestManager.loadMaybeBasicAuth(config: Config, url: String): RequestBuild } val glideUrl = GlideUrl(url, builder.build()) return this.load(glideUrl) +} + +fun getBitmapInputStream(bitmap:Bitmap,compressFormat: Bitmap.CompressFormat): InputStream { + val byteArrayOutputStream = ByteArrayOutputStream() + bitmap.compress(compressFormat, 80, byteArrayOutputStream) + val bitmapData: ByteArray = byteArrayOutputStream.toByteArray() + return ByteArrayInputStream(bitmapData) } \ No newline at end of file