mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-22 09:04:32 +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.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".App"
|
android:name=".App"
|
||||||
|
@ -5,9 +5,13 @@ plugins {
|
|||||||
kotlin {
|
kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
all {
|
all {
|
||||||
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
|
languageSettings.apply {
|
||||||
languageSettings.useExperimentalAnnotation("androidx.compose.animation")
|
useExperimentalAnnotation("kotlin.RequiresOptIn")
|
||||||
languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
|
useExperimentalAnnotation("kotlin.Experimental")
|
||||||
|
useExperimentalAnnotation("kotlin.time.ExperimentalTime")
|
||||||
|
useExperimentalAnnotation("androidx.compose.animation")
|
||||||
|
useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,7 +23,9 @@ actual fun ImageLoad(
|
|||||||
modifier: Modifier
|
modifier: Modifier
|
||||||
// placeholder: ImageVector
|
// placeholder: ImageVector
|
||||||
) {
|
) {
|
||||||
var pic by remember(link) { mutableStateOf<ImageBitmap?>(null) }
|
var pic by remember(link) {
|
||||||
|
mutableStateOf<ImageBitmap?>(null)
|
||||||
|
}
|
||||||
|
|
||||||
LaunchedEffect(link) {
|
LaunchedEffect(link) {
|
||||||
withContext(dispatcherIO) {
|
withContext(dispatcherIO) {
|
||||||
|
@ -21,15 +21,23 @@ package com.shabinder.common.uikit
|
|||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
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.painterResource
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
import com.shabinder.common.database.R
|
import com.shabinder.common.database.R
|
||||||
import com.shabinder.common.translations.Strings
|
import com.shabinder.common.translations.Strings
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal actual fun <T> imageVectorResource(id: T): ImageVector =
|
||||||
|
ImageVector.Companion.vectorResource(id as Int)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadImageTick() {
|
actual fun DownloadImageTick() {
|
||||||
Image(
|
Image(
|
||||||
painterResource(R.drawable.ic_tick),
|
getCachedPainter(R.drawable.ic_tick),
|
||||||
Strings.downloadDone()
|
Strings.downloadDone()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -37,7 +45,7 @@ actual fun DownloadImageTick() {
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadImageError(modifier: Modifier) {
|
actual fun DownloadImageError(modifier: Modifier) {
|
||||||
Image(
|
Image(
|
||||||
painterResource(R.drawable.ic_error),
|
getCachedPainter(R.drawable.ic_error),
|
||||||
Strings.downloadError(),
|
Strings.downloadError(),
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
@ -46,44 +54,44 @@ actual fun DownloadImageError(modifier: Modifier) {
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadImageArrow(modifier: Modifier) {
|
actual fun DownloadImageArrow(modifier: Modifier) {
|
||||||
Image(
|
Image(
|
||||||
painterResource(R.drawable.ic_arrow),
|
getCachedPainter(R.drawable.ic_arrow),
|
||||||
Strings.downloadStart(),
|
Strings.downloadStart(),
|
||||||
modifier
|
modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadAllImage() = painterResource(R.drawable.ic_download_arrow)
|
actual fun DownloadAllImage() = getCachedPainter(R.drawable.ic_download_arrow)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun ShareImage() = painterResource(R.drawable.ic_share_open)
|
actual fun ShareImage() = getCachedPainter(R.drawable.ic_share_open)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun PlaceHolderImage() = painterResource(R.drawable.ic_song_placeholder)
|
actual fun PlaceHolderImage() = getCachedPainter(R.drawable.ic_song_placeholder)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SpotiFlyerLogo() = painterResource(R.drawable.ic_spotiflyer_logo)
|
actual fun SpotiFlyerLogo() = getCachedPainter(R.drawable.ic_spotiflyer_logo)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun HeartIcon() = painterResource(R.drawable.ic_heart)
|
actual fun HeartIcon() = painterResource(R.drawable.ic_heart)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SpotifyLogo() = painterResource(R.drawable.ic_spotify_logo)
|
actual fun SpotifyLogo() = getCachedPainter(R.drawable.ic_spotify_logo)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SaavnLogo() = painterResource(R.drawable.ic_jio_saavn_logo)
|
actual fun SaavnLogo() = getCachedPainter(R.drawable.ic_jio_saavn_logo)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun GaanaLogo() = painterResource(R.drawable.ic_gaana)
|
actual fun GaanaLogo() = getCachedPainter(R.drawable.ic_gaana)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun YoutubeLogo() = painterResource(R.drawable.ic_youtube)
|
actual fun YoutubeLogo() = getCachedPainter(R.drawable.ic_youtube)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun YoutubeMusicLogo() = painterResource(R.drawable.ic_youtube_music_logo)
|
actual fun YoutubeMusicLogo() = getCachedPainter(R.drawable.ic_youtube_music_logo)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun GithubLogo() = painterResource(R.drawable.ic_github)
|
actual fun GithubLogo() = getCachedPainter(R.drawable.ic_github)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun PaypalLogo() = painterResource(R.drawable.ic_paypal_logo)
|
actual fun PaypalLogo() = painterResource(R.drawable.ic_paypal_logo)
|
||||||
|
@ -15,11 +15,27 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@file:Suppress("FunctionName")
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
package com.shabinder.common.uikit
|
package com.shabinder.common.uikit
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
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
|
@Composable
|
||||||
expect fun DownloadImageTick()
|
expect fun DownloadImageTick()
|
||||||
|
@ -15,19 +15,26 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@file:Suppress("FunctionName")
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
package com.shabinder.common.uikit
|
package com.shabinder.common.uikit
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
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.graphics.vector.rememberVectorPainter
|
||||||
|
import androidx.compose.ui.res.loadXmlImageVector
|
||||||
import androidx.compose.ui.res.vectorXmlResource
|
import androidx.compose.ui.res.vectorXmlResource
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal actual fun <T> imageVectorResource(id: T): ImageVector =
|
||||||
|
vectorXmlResource(id as String)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadImageTick() {
|
actual fun DownloadImageTick() {
|
||||||
Image(
|
Image(
|
||||||
vectorXmlResource("drawable/ic_tick.xml"),
|
getCachedPainter("drawable/ic_tick.xml"),
|
||||||
"Downloaded"
|
"Downloaded"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -35,7 +42,7 @@ actual fun DownloadImageTick() {
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadImageError(modifier: Modifier) {
|
actual fun DownloadImageError(modifier: Modifier) {
|
||||||
Image(
|
Image(
|
||||||
vectorXmlResource("drawable/ic_error.xml"),
|
getCachedPainter("drawable/ic_error.xml"),
|
||||||
"Can't Download",
|
"Can't Download",
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
@ -44,51 +51,61 @@ actual fun DownloadImageError(modifier: Modifier) {
|
|||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadImageArrow(modifier: Modifier) {
|
actual fun DownloadImageArrow(modifier: Modifier) {
|
||||||
Image(
|
Image(
|
||||||
vectorXmlResource("drawable/ic_arrow.xml"),
|
getCachedPainter("drawable/ic_arrow.xml"),
|
||||||
"Download",
|
"Download",
|
||||||
modifier
|
modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun DownloadAllImage() = rememberVectorPainter(vectorXmlResource("drawable/ic_download_arrow.xml")) as Painter
|
actual fun DownloadAllImage() = getCachedPainter("drawable/ic_download_arrow.xml")
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun ShareImage() = rememberVectorPainter(vectorXmlResource("drawable/ic_share_open.xml")) as Painter
|
actual fun ShareImage() = getCachedPainter("drawable/ic_share_open.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun PlaceHolderImage() = rememberVectorPainter(vectorXmlResource("drawable/music.xml"))
|
actual fun PlaceHolderImage() = getCachedPainter("drawable/music.xml")
|
||||||
as Painter
|
|
||||||
@Composable
|
|
||||||
actual fun SpotiFlyerLogo() =
|
|
||||||
rememberVectorPainter(vectorXmlResource("drawable/ic_spotiflyer_logo.xml")) as Painter
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun HeartIcon() = rememberVectorPainter(vectorXmlResource("drawable/ic_heart.xml")) as Painter
|
actual fun SpotiFlyerLogo() = getCachedPainter("drawable/ic_spotiflyer_logo.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SpotifyLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_spotify_logo.xml")) as Painter
|
actual fun HeartIcon() =
|
||||||
|
getCachedPainter("drawable/ic_heart.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun SaavnLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_jio_saavn_logo.xml")) as Painter
|
actual fun SpotifyLogo() =
|
||||||
|
getCachedPainter("drawable/ic_spotify_logo.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun YoutubeLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_youtube.xml")) as Painter
|
actual fun SaavnLogo() =
|
||||||
|
getCachedPainter("drawable/ic_jio_saavn_logo.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun GaanaLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_gaana.xml")) as Painter
|
actual fun YoutubeLogo() =
|
||||||
|
getCachedPainter("drawable/ic_youtube.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun YoutubeMusicLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_youtube_music_logo.xml")) as Painter
|
actual fun GaanaLogo() =
|
||||||
|
getCachedPainter("drawable/ic_gaana.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun GithubLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_github.xml")) as Painter
|
actual fun YoutubeMusicLogo() =
|
||||||
|
getCachedPainter("drawable/ic_youtube_music_logo.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun PaypalLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_paypal_logo.xml")) as Painter
|
actual fun GithubLogo() =
|
||||||
|
getCachedPainter("drawable/ic_github.xml")
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun OpenCollectiveLogo() = rememberVectorPainter(vectorXmlResource("drawable/ic_opencollective_icon.xml")) as Painter
|
actual fun PaypalLogo() =
|
||||||
|
getCachedPainter("drawable/ic_paypal_logo.xml")
|
||||||
|
|
||||||
@Composable
|
@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
|
package com.shabinder.common.models
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
actual interface PlatformActions {
|
actual interface PlatformActions {
|
||||||
|
|
||||||
@ -26,3 +27,5 @@ internal actual val StubPlatformActions = object : PlatformActions {
|
|||||||
|
|
||||||
override fun sendTracksToService(array: List<TrackDetails>) {}
|
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
|
package com.shabinder.common.caching
|
||||||
|
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.ExperimentalTime
|
||||||
import kotlin.time.TimeSource
|
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 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
|
* Associates [value] with [key] in this cache. If the cache previously contained a
|
||||||
* value associated with [key], the old value is replaced by [value].
|
* 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.collections.IsoMutableSet
|
||||||
import co.touchlab.stately.concurrency.AtomicReference
|
import co.touchlab.stately.concurrency.AtomicReference
|
||||||
import co.touchlab.stately.concurrency.value
|
import co.touchlab.stately.concurrency.value
|
||||||
|
import com.shabinder.common.models.runBlocking
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.TimeMark
|
import kotlin.time.TimeMark
|
||||||
import kotlin.time.TimeSource
|
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) {
|
override fun put(key: Key, value: Value) {
|
||||||
expireEntries()
|
expireEntries()
|
||||||
|
|
||||||
@ -185,7 +192,7 @@ internal class RealCache<Key : Any, Value : Any>(
|
|||||||
*/
|
*/
|
||||||
private fun CacheEntry<Key, Value>.isExpired(): Boolean {
|
private fun CacheEntry<Key, Value>.isExpired(): Boolean {
|
||||||
return expiresAfterAccess && (accessTimeMark.get() + expireAfterAccessDuration).hasPassedNow() ||
|
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
|
package com.shabinder.common.models
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
expect interface PlatformActions
|
expect interface PlatformActions
|
||||||
|
|
||||||
internal expect val StubPlatformActions: 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)
|
fun <T : Any?> T?.requireNotNull(): T = requireNotNull(this)
|
||||||
|
|
||||||
|
|
||||||
@OptIn(ExperimentalContracts::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
inline fun buildString(track: TrackDetails, builderAction: StringBuilder.() -> Unit): String {
|
inline fun buildString(track: TrackDetails, builderAction: StringBuilder.() -> Unit): String {
|
||||||
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package com.shabinder.common.models
|
package com.shabinder.common.models
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
actual interface PlatformActions
|
actual interface PlatformActions
|
||||||
|
|
||||||
internal actual val StubPlatformActions = object : 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
|
package com.shabinder.common.models
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.promise
|
||||||
|
|
||||||
|
|
||||||
actual interface PlatformActions
|
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