mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-21 16:54:33 +01:00
Cache ImageVectors to Improve App Performance
This commit is contained in:
parent
e4c22c5d0c
commit
dbaaa0816f
@ -40,7 +40,6 @@
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
|
@ -5,9 +5,13 @@ plugins {
|
||||
kotlin {
|
||||
sourceSets {
|
||||
all {
|
||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||
languageSettings.useExperimentalAnnotation("androidx.compose.animation")
|
||||
languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
|
||||
languageSettings.apply {
|
||||
useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||
useExperimentalAnnotation("kotlin.Experimental")
|
||||
useExperimentalAnnotation("kotlin.time.ExperimentalTime")
|
||||
useExperimentalAnnotation("androidx.compose.animation")
|
||||
useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,9 @@ actual fun ImageLoad(
|
||||
modifier: Modifier
|
||||
// placeholder: ImageVector
|
||||
) {
|
||||
var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
|
||||
var pic by remember(link) {
|
||||
mutableStateOf<ImageBitmap?>(null)
|
||||
}
|
||||
|
||||
LaunchedEffect(link) {
|
||||
withContext(dispatcherIO) {
|
||||
|
@ -21,15 +21,23 @@ package com.shabinder.common.uikit
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import com.shabinder.common.database.R
|
||||
import com.shabinder.common.translations.Strings
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Composable
|
||||
internal actual fun <T> imageVectorResource(id: T): ImageVector =
|
||||
ImageVector.Companion.vectorResource(id as Int)
|
||||
|
||||
@Composable
|
||||
actual fun DownloadImageTick() {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_tick),
|
||||
getCachedPainter(R.drawable.ic_tick),
|
||||
Strings.downloadDone()
|
||||
)
|
||||
}
|
||||
@ -37,7 +45,7 @@ actual fun DownloadImageTick() {
|
||||
@Composable
|
||||
actual fun DownloadImageError(modifier: Modifier) {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_error),
|
||||
getCachedPainter(R.drawable.ic_error),
|
||||
Strings.downloadError(),
|
||||
modifier = modifier
|
||||
)
|
||||
@ -46,44 +54,44 @@ actual fun DownloadImageError(modifier: Modifier) {
|
||||
@Composable
|
||||
actual fun DownloadImageArrow(modifier: Modifier) {
|
||||
Image(
|
||||
painterResource(R.drawable.ic_arrow),
|
||||
getCachedPainter(R.drawable.ic_arrow),
|
||||
Strings.downloadStart(),
|
||||
modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun DownloadAllImage() = painterResource(R.drawable.ic_download_arrow)
|
||||
actual fun DownloadAllImage() = getCachedPainter(R.drawable.ic_download_arrow)
|
||||
|
||||
@Composable
|
||||
actual fun ShareImage() = painterResource(R.drawable.ic_share_open)
|
||||
actual fun ShareImage() = getCachedPainter(R.drawable.ic_share_open)
|
||||
|
||||
@Composable
|
||||
actual fun PlaceHolderImage() = painterResource(R.drawable.ic_song_placeholder)
|
||||
actual fun PlaceHolderImage() = getCachedPainter(R.drawable.ic_song_placeholder)
|
||||
|
||||
@Composable
|
||||
actual fun SpotiFlyerLogo() = painterResource(R.drawable.ic_spotiflyer_logo)
|
||||
actual fun SpotiFlyerLogo() = getCachedPainter(R.drawable.ic_spotiflyer_logo)
|
||||
|
||||
@Composable
|
||||
actual fun HeartIcon() = painterResource(R.drawable.ic_heart)
|
||||
|
||||
@Composable
|
||||
actual fun SpotifyLogo() = painterResource(R.drawable.ic_spotify_logo)
|
||||
actual fun SpotifyLogo() = getCachedPainter(R.drawable.ic_spotify_logo)
|
||||
|
||||
@Composable
|
||||
actual fun SaavnLogo() = painterResource(R.drawable.ic_jio_saavn_logo)
|
||||
actual fun SaavnLogo() = getCachedPainter(R.drawable.ic_jio_saavn_logo)
|
||||
|
||||
@Composable
|
||||
actual fun GaanaLogo() = painterResource(R.drawable.ic_gaana)
|
||||
actual fun GaanaLogo() = getCachedPainter(R.drawable.ic_gaana)
|
||||
|
||||
@Composable
|
||||
actual fun YoutubeLogo() = painterResource(R.drawable.ic_youtube)
|
||||
actual fun YoutubeLogo() = getCachedPainter(R.drawable.ic_youtube)
|
||||
|
||||
@Composable
|
||||
actual fun YoutubeMusicLogo() = painterResource(R.drawable.ic_youtube_music_logo)
|
||||
actual fun YoutubeMusicLogo() = getCachedPainter(R.drawable.ic_youtube_music_logo)
|
||||
|
||||
@Composable
|
||||
actual fun GithubLogo() = painterResource(R.drawable.ic_github)
|
||||
actual fun GithubLogo() = getCachedPainter(R.drawable.ic_github)
|
||||
|
||||
@Composable
|
||||
actual fun PaypalLogo() = painterResource(R.drawable.ic_paypal_logo)
|
||||
@ -100,4 +108,4 @@ actual fun Toast(
|
||||
duration: ToastDuration
|
||||
) {
|
||||
// We Have Android's Implementation of Toast so its just Empty
|
||||
}
|
||||
}
|
@ -15,11 +15,27 @@
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName")
|
||||
|
||||
package com.shabinder.common.uikit
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import com.shabinder.common.caching.Cache
|
||||
|
||||
private val ImageCache = Cache.Builder.newBuilder()
|
||||
.maximumCacheSize(15).build<Any, ImageVector>()
|
||||
|
||||
@Composable
|
||||
internal expect fun <T> imageVectorResource(id: T): ImageVector
|
||||
|
||||
@Composable
|
||||
fun <K : Any> getCachedPainter(key: K): Painter {
|
||||
return rememberVectorPainter(
|
||||
ImageCache.get(key) ?: imageVectorResource(key).also { ImageCache.put(key, it) })
|
||||
}
|
||||
|
||||
@Composable
|
||||
expect fun DownloadImageTick()
|
||||
|
@ -15,19 +15,26 @@
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName")
|
||||
|
||||
package com.shabinder.common.uikit
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||
import androidx.compose.ui.res.loadXmlImageVector
|
||||
import androidx.compose.ui.res.vectorXmlResource
|
||||
|
||||
@Composable
|
||||
internal actual fun <T> imageVectorResource(id: T): ImageVector =
|
||||
vectorXmlResource(id as String)
|
||||
|
||||
@Composable
|
||||
actual fun DownloadImageTick() {
|
||||
Image(
|
||||
vectorXmlResource("drawable/ic_tick.xml"),
|
||||
getCachedPainter("drawable/ic_tick.xml"),
|
||||
"Downloaded"
|
||||
)
|
||||
}
|
||||
@ -35,7 +42,7 @@ actual fun DownloadImageTick() {
|
||||
@Composable
|
||||
actual fun DownloadImageError(modifier: Modifier) {
|
||||
Image(
|
||||
vectorXmlResource("drawable/ic_error.xml"),
|
||||
getCachedPainter("drawable/ic_error.xml"),
|
||||
"Can't Download",
|
||||
modifier = modifier
|
||||
)
|
||||
@ -44,51 +51,61 @@ actual fun DownloadImageError(modifier: Modifier) {
|
||||
@Composable
|
||||
actual fun DownloadImageArrow(modifier: Modifier) {
|
||||
Image(
|
||||
vectorXmlResource("drawable/ic_arrow.xml"),
|
||||
getCachedPainter("drawable/ic_arrow.xml"),
|
||||
"Download",
|
||||
modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
actual fun DownloadAllImage() = rememberVectorPainter(vectorXmlResource("drawable/ic_download_arrow.xml")) as Painter
|
||||
actual fun DownloadAllImage() = getCachedPainter("drawable/ic_download_arrow.xml")
|
||||
|
||||
|
||||
@Composable
|
||||
actual fun ShareImage() = rememberVectorPainter(vectorXmlResource("drawable/ic_share_open.xml")) as Painter
|
||||
actual fun ShareImage() = getCachedPainter("drawable/ic_share_open.xml")
|
||||
|
||||
@Composable
|
||||
actual fun PlaceHolderImage() = rememberVectorPainter(vectorXmlResource("drawable/music.xml"))
|
||||
as Painter
|
||||
@Composable
|
||||
actual fun SpotiFlyerLogo() =
|
||||
rememberVectorPainter(vectorXmlResource("drawable/ic_spotiflyer_logo.xml")) as Painter
|
||||
actual fun PlaceHolderImage() = getCachedPainter("drawable/music.xml")
|
||||
|
||||
@Composable
|
||||
actual fun HeartIcon() = rememberVectorPainter(vectorXmlResource("drawable/ic_heart.xml")) as Painter
|
||||
actual fun SpotiFlyerLogo() = getCachedPainter("drawable/ic_spotiflyer_logo.xml")
|
||||
|
||||
@Composable
|
||||
actual fun SpotifyLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_spotify_logo.xml")) as Painter
|
||||
actual fun HeartIcon() =
|
||||
getCachedPainter("drawable/ic_heart.xml")
|
||||
|
||||
@Composable
|
||||
actual fun SaavnLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_jio_saavn_logo.xml")) as Painter
|
||||
actual fun SpotifyLogo() =
|
||||
getCachedPainter("drawable/ic_spotify_logo.xml")
|
||||
|
||||
@Composable
|
||||
actual fun YoutubeLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_youtube.xml")) as Painter
|
||||
actual fun SaavnLogo() =
|
||||
getCachedPainter("drawable/ic_jio_saavn_logo.xml")
|
||||
|
||||
@Composable
|
||||
actual fun GaanaLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_gaana.xml")) as Painter
|
||||
actual fun YoutubeLogo() =
|
||||
getCachedPainter("drawable/ic_youtube.xml")
|
||||
|
||||
@Composable
|
||||
actual fun YoutubeMusicLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_youtube_music_logo.xml")) as Painter
|
||||
actual fun GaanaLogo() =
|
||||
getCachedPainter("drawable/ic_gaana.xml")
|
||||
|
||||
@Composable
|
||||
actual fun GithubLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_github.xml")) as Painter
|
||||
actual fun YoutubeMusicLogo() =
|
||||
getCachedPainter("drawable/ic_youtube_music_logo.xml")
|
||||
|
||||
@Composable
|
||||
actual fun PaypalLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_paypal_logo.xml")) as Painter
|
||||
actual fun GithubLogo() =
|
||||
getCachedPainter("drawable/ic_github.xml")
|
||||
|
||||
@Composable
|
||||
actual fun OpenCollectiveLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_opencollective_icon.xml")) as Painter
|
||||
actual fun PaypalLogo() =
|
||||
getCachedPainter("drawable/ic_paypal_logo.xml")
|
||||
|
||||
@Composable
|
||||
actual fun RazorPay() = rememberVectorPainter(vectorXmlResource("drawable/ic_indian_rupee.xml")) as Painter
|
||||
actual fun OpenCollectiveLogo() =
|
||||
getCachedPainter("drawable/ic_opencollective_icon.xml")
|
||||
|
||||
@Composable
|
||||
actual fun RazorPay() =
|
||||
getCachedPainter("drawable/ic_indian_rupee.xml")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.shabinder.common.models
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
actual interface PlatformActions {
|
||||
|
||||
@ -26,3 +27,5 @@ internal actual val StubPlatformActions = object : PlatformActions {
|
||||
|
||||
override fun sendTracksToService(array: List<TrackDetails>) {}
|
||||
}
|
||||
|
||||
actual fun <T> runBlocking(block: suspend CoroutineScope.() -> T): T = kotlinx.coroutines.runBlocking { block() }
|
@ -1,6 +1,7 @@
|
||||
package com.shabinder.common.caching
|
||||
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.TimeSource
|
||||
|
||||
/**
|
||||
@ -23,6 +24,8 @@ public interface Cache<in Key : Any, Value : Any> {
|
||||
*/
|
||||
public suspend fun get(key: Key, loader: suspend () -> Value): Value
|
||||
|
||||
public fun getBlocking(key: Key, loader: suspend () -> Value): Value
|
||||
|
||||
/**
|
||||
* Associates [value] with [key] in this cache. If the cache previously contained a
|
||||
* value associated with [key], the old value is replaced by [value].
|
||||
|
@ -4,6 +4,7 @@ import co.touchlab.stately.collections.IsoMutableMap
|
||||
import co.touchlab.stately.collections.IsoMutableSet
|
||||
import co.touchlab.stately.concurrency.AtomicReference
|
||||
import co.touchlab.stately.concurrency.value
|
||||
import com.shabinder.common.models.runBlocking
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.TimeMark
|
||||
import kotlin.time.TimeSource
|
||||
@ -110,6 +111,12 @@ internal class RealCache<Key : Any, Value : Any>(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun getBlocking(key: Key, loader: suspend () -> Value): Value =
|
||||
runBlocking {
|
||||
get(key, loader)
|
||||
}
|
||||
|
||||
override fun put(key: Key, value: Value) {
|
||||
expireEntries()
|
||||
|
||||
@ -185,7 +192,7 @@ internal class RealCache<Key : Any, Value : Any>(
|
||||
*/
|
||||
private fun CacheEntry<Key, Value>.isExpired(): Boolean {
|
||||
return expiresAfterAccess && (accessTimeMark.get() + expireAfterAccessDuration).hasPassedNow() ||
|
||||
expiresAfterWrite && (writeTimeMark.get() + expireAfterWriteDuration).hasPassedNow()
|
||||
expiresAfterWrite && (writeTimeMark.get() + expireAfterWriteDuration).hasPassedNow()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,9 @@
|
||||
package com.shabinder.common.models
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
expect interface PlatformActions
|
||||
|
||||
internal expect val StubPlatformActions: PlatformActions
|
||||
|
||||
expect fun <T> runBlocking(block: suspend CoroutineScope.() -> T): T
|
@ -7,7 +7,6 @@ import kotlin.contracts.contract
|
||||
|
||||
fun <T : Any?> T?.requireNotNull(): T = requireNotNull(this)
|
||||
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
inline fun buildString(track: TrackDetails, builderAction: StringBuilder.() -> Unit): String {
|
||||
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
||||
|
@ -1,5 +1,9 @@
|
||||
package com.shabinder.common.models
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
||||
actual interface PlatformActions
|
||||
|
||||
internal actual val StubPlatformActions = object : PlatformActions {}
|
||||
|
||||
actual fun <T> runBlocking(block: suspend CoroutineScope.() -> T): T = kotlinx.coroutines.runBlocking { block() }
|
@ -1,5 +1,10 @@
|
||||
package com.shabinder.common.models
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.promise
|
||||
|
||||
|
||||
actual interface PlatformActions
|
||||
internal actual val StubPlatformActions = object : PlatformActions {}
|
||||
internal actual val StubPlatformActions = object : PlatformActions {}
|
||||
actual fun <T> runBlocking(block: suspend CoroutineScope.() -> T): dynamic = GlobalScope.promise(block = block)
|
Loading…
Reference in New Issue
Block a user