Merge pull request #353 from gotify/concurrent-image-access
fix: image loading when using markdown img and bigImageUrl
This commit is contained in:
@@ -16,13 +16,62 @@ import java.io.IOException
|
||||
import okhttp3.OkHttpClient
|
||||
import org.tinylog.kotlin.Logger
|
||||
|
||||
internal class CoilHandler(private val context: Context, private val settings: Settings) {
|
||||
private val imageLoader = makeImageLoader()
|
||||
object CoilInstance {
|
||||
private var holder: Pair<SSLSettings, ImageLoader>? = null
|
||||
|
||||
private fun makeImageLoader(): ImageLoader {
|
||||
@Throws(IOException::class)
|
||||
fun getImageFromUrl(context: Context, url: String?): Bitmap {
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.build()
|
||||
return (get(context).executeBlocking(request).drawable as BitmapDrawable).bitmap
|
||||
}
|
||||
|
||||
fun getIcon(context: Context, app: Application?): Bitmap {
|
||||
if (app == null) {
|
||||
return BitmapFactory.decodeResource(context.resources, R.drawable.gotify)
|
||||
}
|
||||
val baseUrl = Settings(context).url
|
||||
try {
|
||||
return getImageFromUrl(
|
||||
context,
|
||||
Utils.resolveAbsoluteUrl("$baseUrl/", app.image)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
Logger.error(e, "Could not load image for notification")
|
||||
}
|
||||
return BitmapFactory.decodeResource(context.resources, R.drawable.gotify)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
fun evict(context: Context) {
|
||||
try {
|
||||
get(context).apply {
|
||||
diskCache?.clear()
|
||||
memoryCache?.clear()
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Logger.error(e, "Problem evicting Coil cache")
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun get(context: Context): ImageLoader {
|
||||
val newSettings = Settings(context).sslSettings()
|
||||
val copy = holder
|
||||
if (copy != null && copy.first == newSettings) {
|
||||
return copy.second
|
||||
}
|
||||
return makeImageLoader(context, newSettings).also { holder = it }.second
|
||||
}
|
||||
|
||||
private fun makeImageLoader(
|
||||
context: Context,
|
||||
sslSettings: SSLSettings
|
||||
): Pair<SSLSettings, ImageLoader> {
|
||||
val builder = OkHttpClient.Builder()
|
||||
CertUtils.applySslSettings(builder, settings.sslSettings())
|
||||
return ImageLoader.Builder(context)
|
||||
CertUtils.applySslSettings(builder, sslSettings)
|
||||
val loader = ImageLoader.Builder(context)
|
||||
.okHttpClient(builder.build())
|
||||
.diskCache {
|
||||
DiskCache.Builder()
|
||||
@@ -33,39 +82,6 @@ internal class CoilHandler(private val context: Context, private val settings: S
|
||||
add(SvgDecoder.Factory())
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun getImageFromUrl(url: String?): Bitmap {
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(url)
|
||||
.build()
|
||||
return (imageLoader.executeBlocking(request).drawable as BitmapDrawable).bitmap
|
||||
}
|
||||
|
||||
fun getIcon(app: Application?): Bitmap {
|
||||
if (app == null) {
|
||||
return BitmapFactory.decodeResource(context.resources, R.drawable.gotify)
|
||||
}
|
||||
try {
|
||||
return getImageFromUrl(
|
||||
Utils.resolveAbsoluteUrl("${settings.url}/", app.image)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
Logger.error(e, "Could not load image for notification")
|
||||
}
|
||||
return BitmapFactory.decodeResource(context.resources, R.drawable.gotify)
|
||||
}
|
||||
|
||||
fun get() = imageLoader
|
||||
|
||||
@OptIn(ExperimentalCoilApi::class)
|
||||
fun evict() {
|
||||
try {
|
||||
imageLoader.diskCache?.clear()
|
||||
imageLoader.memoryCache?.clear()
|
||||
} catch (e: IOException) {
|
||||
Logger.error(e, "Problem evicting Coil cache")
|
||||
}
|
||||
return sslSettings to loader
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.github.gotify
|
||||
|
||||
internal class SSLSettings(
|
||||
internal data class SSLSettings(
|
||||
val validateSSL: Boolean,
|
||||
val caCertPath: String?,
|
||||
val clientCertPath: String?,
|
||||
|
||||
@@ -31,6 +31,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.request.ImageRequest
|
||||
import com.github.gotify.BuildConfig
|
||||
import com.github.gotify.CoilInstance
|
||||
import com.github.gotify.MissedMessageUtil
|
||||
import com.github.gotify.R
|
||||
import com.github.gotify.Utils
|
||||
@@ -102,7 +103,7 @@ internal class MessagesActivity :
|
||||
listMessageAdapter = ListMessageAdapter(
|
||||
this,
|
||||
viewModel.settings,
|
||||
viewModel.coilHandler.get()
|
||||
CoilInstance.get(this)
|
||||
) { message ->
|
||||
scheduleDeletion(message)
|
||||
}
|
||||
@@ -169,13 +170,13 @@ internal class MessagesActivity :
|
||||
}
|
||||
|
||||
private fun refreshAll() {
|
||||
viewModel.coilHandler.evict()
|
||||
CoilInstance.evict(this)
|
||||
startActivity(Intent(this, InitializationActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun onRefresh() {
|
||||
viewModel.coilHandler.evict()
|
||||
CoilInstance.evict(this)
|
||||
viewModel.messages.clear()
|
||||
launchCoroutine {
|
||||
loadMore(viewModel.appId).forEachIndexed { index, message ->
|
||||
@@ -211,9 +212,7 @@ internal class MessagesActivity :
|
||||
.size(100, 100)
|
||||
.target(t)
|
||||
.build()
|
||||
viewModel.coilHandler
|
||||
.get()
|
||||
.enqueue(request)
|
||||
CoilInstance.get(this).enqueue(request)
|
||||
}
|
||||
selectAppInMenu(selectedItem)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.github.gotify.messages
|
||||
import android.app.Activity
|
||||
import androidx.lifecycle.ViewModel
|
||||
import coil.target.Target
|
||||
import com.github.gotify.CoilHandler
|
||||
import com.github.gotify.Settings
|
||||
import com.github.gotify.api.ClientFactory
|
||||
import com.github.gotify.client.api.MessageApi
|
||||
@@ -13,7 +12,6 @@ import com.github.gotify.messages.provider.MessageState
|
||||
|
||||
internal class MessagesModel(parentView: Activity) : ViewModel() {
|
||||
val settings = Settings(parentView)
|
||||
val coilHandler = CoilHandler(parentView, settings)
|
||||
val client = ClientFactory.clientToken(settings)
|
||||
val appsHolder = ApplicationHolder(parentView, client)
|
||||
val messages = MessageFacade(client.createService(MessageApi::class.java), appsHolder)
|
||||
|
||||
@@ -17,7 +17,7 @@ import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.github.gotify.BuildConfig
|
||||
import com.github.gotify.CoilHandler
|
||||
import com.github.gotify.CoilInstance
|
||||
import com.github.gotify.MarkwonFactory
|
||||
import com.github.gotify.MissedMessageUtil
|
||||
import com.github.gotify.NotificationSupport
|
||||
@@ -62,7 +62,6 @@ internal class WebSocketService : Service() {
|
||||
private val lastReceivedMessage = AtomicLong(NOT_LOADED)
|
||||
private lateinit var missingMessageUtil: MissedMessageUtil
|
||||
|
||||
private lateinit var coilHandler: CoilHandler
|
||||
private lateinit var markwon: Markwon
|
||||
|
||||
override fun onCreate() {
|
||||
@@ -71,8 +70,7 @@ internal class WebSocketService : Service() {
|
||||
val client = ClientFactory.clientToken(settings)
|
||||
missingMessageUtil = MissedMessageUtil(client.createService(MessageApi::class.java))
|
||||
Logger.info("Create ${javaClass.simpleName}")
|
||||
coilHandler = CoilHandler(this, settings)
|
||||
markwon = MarkwonFactory.createForNotification(this, coilHandler.get())
|
||||
markwon = MarkwonFactory.createForNotification(this, CoilInstance.get(this))
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
@@ -377,7 +375,7 @@ internal class WebSocketService : Service() {
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setSmallIcon(R.drawable.ic_gotify)
|
||||
.setLargeIcon(coilHandler.getIcon(appIdToApp[appId]))
|
||||
.setLargeIcon(CoilInstance.getIcon(this, appIdToApp[appId]))
|
||||
.setTicker("${getString(R.string.app_name)} - $title")
|
||||
.setGroup(NotificationSupport.Group.MESSAGES)
|
||||
.setContentTitle(title)
|
||||
@@ -406,7 +404,7 @@ internal class WebSocketService : Service() {
|
||||
try {
|
||||
b.setStyle(
|
||||
NotificationCompat.BigPictureStyle()
|
||||
.bigPicture(coilHandler.getImageFromUrl(notificationImageUrl))
|
||||
.bigPicture(CoilInstance.getImageFromUrl(this, notificationImageUrl))
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Logger.error(e, "Error loading bigImageUrl")
|
||||
|
||||
Reference in New Issue
Block a user