Limited images concurrent loading to 3
This commit is contained in:
parent
bf6600878b
commit
7a3d68e3a6
15
src/main/kotlin/app/extensions/SemaphoreExtensions.kt
Normal file
15
src/main/kotlin/app/extensions/SemaphoreExtensions.kt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package app.extensions
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
|
||||||
|
suspend inline fun Semaphore.acquireAndUse(
|
||||||
|
block: () -> Composable
|
||||||
|
) {
|
||||||
|
this.acquire()
|
||||||
|
try {
|
||||||
|
block()
|
||||||
|
} finally {
|
||||||
|
this.release()
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package app.images
|
package app.images
|
||||||
|
|
||||||
interface ImagesCache {
|
interface ImagesCache {
|
||||||
fun getCachedObject(urlSource: String): ByteArray?
|
fun getCachedImage(urlSource: String): ByteArray?
|
||||||
fun cacheImage(urlSource: String, image: ByteArray)
|
fun cacheImage(urlSource: String, image: ByteArray)
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ package app.images
|
|||||||
object InMemoryImagesCache : ImagesCache {
|
object InMemoryImagesCache : ImagesCache {
|
||||||
private val cachedImages = hashMapOf<String, ByteArray>()
|
private val cachedImages = hashMapOf<String, ByteArray>()
|
||||||
|
|
||||||
override fun getCachedObject(urlSource: String): ByteArray? {
|
override fun getCachedImage(urlSource: String): ByteArray? {
|
||||||
return cachedImages[urlSource]
|
return cachedImages[urlSource]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
75
src/main/kotlin/app/images/NetworkImageLoader.kt
Normal file
75
src/main/kotlin/app/images/NetworkImageLoader.kt
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package app.images
|
||||||
|
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||||
|
import androidx.compose.ui.res.useResource
|
||||||
|
import app.extensions.acquireAndUse
|
||||||
|
import app.extensions.toByteArray
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.jetbrains.skia.Image
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
private const val MAX_LOADING_IMAGES = 3
|
||||||
|
|
||||||
|
object NetworkImageLoader {
|
||||||
|
private val loadingImagesSemaphore = Semaphore(MAX_LOADING_IMAGES)
|
||||||
|
private val cache: ImagesCache = InMemoryImagesCache
|
||||||
|
|
||||||
|
suspend fun loadImageNetwork(url: String): ImageBitmap? = withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
val cachedImage = cache.getCachedImage(url)
|
||||||
|
|
||||||
|
if(cachedImage != null)
|
||||||
|
return@withContext cachedImage.toComposeImage()
|
||||||
|
|
||||||
|
loadingImagesSemaphore.acquireAndUse {
|
||||||
|
val imageByteArray = loadImage(url)
|
||||||
|
cache.cacheImage(url, imageByteArray)
|
||||||
|
return@withContext imageByteArray.toComposeImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a previous return hasn't been called, something has gone wrong, return null
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun loadImage(link: String): ByteArray = withContext(Dispatchers.IO) {
|
||||||
|
val url = URL(link)
|
||||||
|
val connection = url.openConnection() as HttpURLConnection
|
||||||
|
connection.connect()
|
||||||
|
|
||||||
|
connection.inputStream.toByteArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberNetworkImage(url: String): ImageBitmap {
|
||||||
|
val networkImageLoader = NetworkImageLoader
|
||||||
|
var image by remember(url) {
|
||||||
|
mutableStateOf(
|
||||||
|
useResource("image.jpg") {
|
||||||
|
Image.makeFromEncoded(it.toByteArray()).toComposeImageBitmap()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(url) {
|
||||||
|
val networkImage = networkImageLoader.loadImageNetwork(url)
|
||||||
|
if(networkImage != null)
|
||||||
|
image = networkImage
|
||||||
|
}
|
||||||
|
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ByteArray.toComposeImage() = Image.makeFromEncoded(this).toComposeImageBitmap()
|
||||||
|
|
@ -5,38 +5,30 @@ import androidx.compose.foundation.layout.*
|
|||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.Divider
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
|
||||||
import androidx.compose.ui.res.useResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import app.extensions.*
|
import app.extensions.*
|
||||||
import kotlinx.coroutines.*
|
import app.git.GitManager
|
||||||
import org.eclipse.jgit.diff.DiffEntry
|
import app.images.rememberNetworkImage
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
|
||||||
import app.theme.headerBackground
|
import app.theme.headerBackground
|
||||||
|
import app.theme.headerText
|
||||||
import app.theme.primaryTextColor
|
import app.theme.primaryTextColor
|
||||||
import app.theme.secondaryTextColor
|
import app.theme.secondaryTextColor
|
||||||
import java.net.HttpURLConnection
|
|
||||||
import java.net.URL
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
|
||||||
import app.ui.components.ScrollableLazyColumn
|
import app.ui.components.ScrollableLazyColumn
|
||||||
import app.git.GitManager
|
|
||||||
import app.images.ImagesCache
|
|
||||||
import app.images.InMemoryImagesCache
|
|
||||||
import app.theme.headerText
|
|
||||||
import app.ui.components.TooltipText
|
import app.ui.components.TooltipText
|
||||||
import org.eclipse.jgit.lib.PersonIdent
|
import org.eclipse.jgit.diff.DiffEntry
|
||||||
import org.jetbrains.skia.Image.Companion.makeFromEncoded
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommitChanges(
|
fun CommitChanges(
|
||||||
@ -166,45 +158,6 @@ fun Author(commit: RevCommit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loadImage(link: String): ByteArray = withContext(Dispatchers.IO) {
|
|
||||||
val url = URL(link)
|
|
||||||
val connection = url.openConnection() as HttpURLConnection
|
|
||||||
connection.connect()
|
|
||||||
|
|
||||||
connection.inputStream.toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun rememberNetworkImage(url: String, cache: ImagesCache = InMemoryImagesCache): ImageBitmap {
|
|
||||||
val cachedImage = cache.getCachedObject(url)
|
|
||||||
|
|
||||||
var image by remember(url) {
|
|
||||||
if(cachedImage != null)
|
|
||||||
mutableStateOf(makeFromEncoded(cachedImage).toComposeImageBitmap())
|
|
||||||
else
|
|
||||||
mutableStateOf(
|
|
||||||
useResource("image.jpg") {
|
|
||||||
makeFromEncoded(it.toByteArray()).toComposeImageBitmap()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cachedImage == null) {
|
|
||||||
LaunchedEffect(url) {
|
|
||||||
try {
|
|
||||||
loadImage(url).let {
|
|
||||||
image = makeFromEncoded(it).toComposeImageBitmap()
|
|
||||||
cache.cacheImage(url, it)
|
|
||||||
}
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
println("Avatar loading failed: ${ex.message}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return image
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CommitLogChanges(diffEntries: List<DiffEntry>, onDiffSelected: (DiffEntry) -> Unit) {
|
fun CommitLogChanges(diffEntries: List<DiffEntry>, onDiffSelected: (DiffEntry) -> Unit) {
|
||||||
val selectedIndex = remember(diffEntries) { mutableStateOf(-1) }
|
val selectedIndex = remember(diffEntries) { mutableStateOf(-1) }
|
||||||
|
@ -36,6 +36,7 @@ import app.extensions.*
|
|||||||
import app.git.GitManager
|
import app.git.GitManager
|
||||||
import app.git.LogStatus
|
import app.git.LogStatus
|
||||||
import app.git.graph.GraphNode
|
import app.git.graph.GraphNode
|
||||||
|
import app.images.rememberNetworkImage
|
||||||
import app.theme.headerBackground
|
import app.theme.headerBackground
|
||||||
import app.theme.headerText
|
import app.theme.headerText
|
||||||
import app.theme.primaryTextColor
|
import app.theme.primaryTextColor
|
||||||
@ -46,7 +47,6 @@ import app.ui.dialogs.MergeDialog
|
|||||||
import app.ui.dialogs.NewBranchDialog
|
import app.ui.dialogs.NewBranchDialog
|
||||||
import app.ui.dialogs.NewTagDialog
|
import app.ui.dialogs.NewTagDialog
|
||||||
import app.ui.dialogs.ResetBranchDialog
|
import app.ui.dialogs.ResetBranchDialog
|
||||||
import app.ui.rememberNetworkImage
|
|
||||||
import org.eclipse.jgit.lib.Ref
|
import org.eclipse.jgit.lib.Ref
|
||||||
import org.eclipse.jgit.revwalk.RevCommit
|
import org.eclipse.jgit.revwalk.RevCommit
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user