tKwO14&qr!fNm&Gl@M
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
Km#vmI3;jP`-AaT2
literal 0
HcmV?d00001
diff --git a/components/resources/demo/shared/src/commonMain/resources/img.webp b/components/resources/demo/shared/src/commonMain/resources/img.webp
new file mode 100644
index 0000000000000000000000000000000000000000..0da983e2ce5335eb13a7b793a1403588617dde3c
GIT binary patch
literal 10474
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
literal 0
HcmV?d00001
diff --git a/components/resources/demo/shared/src/desktopMain/kotlin/org/jetbrains/compose/resources/demo/shared/main.desktop.kt b/components/resources/demo/shared/src/desktopMain/kotlin/org/jetbrains/compose/resources/demo/shared/main.desktop.kt
new file mode 100644
index 0000000000..d1997f205b
--- /dev/null
+++ b/components/resources/demo/shared/src/desktopMain/kotlin/org/jetbrains/compose/resources/demo/shared/main.desktop.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources.demo.shared
+
+import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.runtime.Composable
+
+@Composable
+fun MainView() {
+ UseResources()
+}
+
+@Preview
+@Composable
+fun Preview() {
+ MainView()
+}
diff --git a/components/resources/demo/shared/src/iosMain/kotlin/main.ios.kt b/components/resources/demo/shared/src/iosMain/kotlin/main.ios.kt
new file mode 100644
index 0000000000..8614d4176a
--- /dev/null
+++ b/components/resources/demo/shared/src/iosMain/kotlin/main.ios.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.height
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Application
+import org.jetbrains.compose.resources.demo.shared.UseResources
+import platform.UIKit.UIViewController
+
+fun MainViewController(): UIViewController =
+ Application("Resources demo") {
+ Column {
+ Box(
+ modifier = Modifier
+ .height(100.dp)
+ )
+ UseResources()
+ }
+ }
diff --git a/components/resources/demo/shared/src/jsMain/kotlin/main.js.kt b/components/resources/demo/shared/src/jsMain/kotlin/main.js.kt
new file mode 100644
index 0000000000..2eb351f69a
--- /dev/null
+++ b/components/resources/demo/shared/src/jsMain/kotlin/main.js.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Window
+import org.jetbrains.compose.resources.demo.shared.UseResources
+import org.jetbrains.skiko.wasm.onWasmReady
+
+fun main() {
+ onWasmReady {
+ Window("Resources demo") {
+ MainView()
+ }
+ }
+}
+
+@Composable
+fun MainView() {
+ Column(modifier = Modifier.fillMaxSize()) {
+ Spacer(modifier = Modifier.height(24.dp))
+ UseResources()
+ }
+}
diff --git a/components/resources/demo/shared/src/jsMain/resources/index.html b/components/resources/demo/shared/src/jsMain/resources/index.html
new file mode 100644
index 0000000000..971817e6a8
--- /dev/null
+++ b/components/resources/demo/shared/src/jsMain/resources/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+ compose multiplatform web demo
+
+
+
+
+ compose multiplatform web demo
+
+
+
+
+
+
diff --git a/components/resources/demo/shared/src/jsMain/resources/styles.css b/components/resources/demo/shared/src/jsMain/resources/styles.css
new file mode 100644
index 0000000000..e5b3293a7a
--- /dev/null
+++ b/components/resources/demo/shared/src/jsMain/resources/styles.css
@@ -0,0 +1,8 @@
+#root {
+ width: 100%;
+ height: 100vh;
+}
+
+#root > .compose-web-column > div {
+ position: relative;
+}
\ No newline at end of file
diff --git a/components/resources/demo/shared/src/macosMain/kotlin/main.macos.kt b/components/resources/demo/shared/src/macosMain/kotlin/main.macos.kt
new file mode 100644
index 0000000000..963d3badf7
--- /dev/null
+++ b/components/resources/demo/shared/src/macosMain/kotlin/main.macos.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+import androidx.compose.ui.window.Window
+import org.jetbrains.compose.resources.demo.shared.UseResources
+import platform.AppKit.NSApp
+import platform.AppKit.NSApplication
+
+fun main() {
+ NSApplication.sharedApplication()
+ Window("Resources demo") {
+ UseResources()
+ }
+ NSApp?.run()
+}
diff --git a/components/resources/library/build.gradle.kts b/components/resources/library/build.gradle.kts
index 0f4368531b..796ef6019e 100644
--- a/components/resources/library/build.gradle.kts
+++ b/components/resources/library/build.gradle.kts
@@ -1,24 +1,114 @@
-import org.jetbrains.compose.compose
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
id("maven-publish")
+ id("com.android.library")
}
+val composeVersion = extra["compose.version"] as String
+
kotlin {
jvm("desktop")
+ android {
+ publishLibraryVariants("release")
+ }
+ ios()
+ iosSimulatorArm64()
+ js(IR) {
+ browser()
+ }
+ macosX64()
+ macosArm64()
sourceSets {
- named("commonMain") {
+ val commonMain by getting {
+ dependencies {
+ implementation("org.jetbrains.compose.runtime:runtime:$composeVersion")
+ implementation("org.jetbrains.compose.foundation:foundation:$composeVersion")
+ }
+ }
+ val commonTest by getting {
dependencies {
- api(compose.runtime)
- api(compose.foundation)
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4")
+ implementation(kotlin("test"))
+ }
+ }
+ val skikoMain by creating {
+ dependsOn(commonMain)
+ }
+ val desktopMain by getting {
+ dependsOn(skikoMain)
+ }
+ val desktopTest by getting {
+ dependencies {
+ implementation(compose.desktop.currentOs)
+ implementation("org.jetbrains.compose.ui:ui-test-junit4:$composeVersion")
+ implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.6.4")
+ }
+ }
+ val androidMain by getting {}
+ val androidTest by getting {
+ dependencies {
+
}
}
- named("desktopMain") {}
+ val iosMain by getting {
+ dependsOn(skikoMain)
+ }
+ val iosTest by getting
+ val iosSimulatorArm64Main by getting
+ iosSimulatorArm64Main.dependsOn(iosMain)
+ val iosSimulatorArm64Test by getting
+ iosSimulatorArm64Test.dependsOn(iosTest)
+ val jsMain by getting {
+ dependsOn(skikoMain)
+ }
+ val macosMain by creating {
+ dependsOn(skikoMain)
+ }
+ val macosX64Main by getting {
+ dependsOn(macosMain)
+ }
+ val macosArm64Main by getting {
+ dependsOn(macosMain)
+ }
+ }
+}
+
+android {
+ compileSdk = 33
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+ defaultConfig {
+ minSdk = 24
+ targetSdk = 33
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
+ testOptions {
+ managedDevices {
+ devices {
+ maybeCreate("pixel5").apply {
+ device = "Pixel 5"
+ apiLevel = 31
+ systemImageSource = "aosp"
+ }
+ }
+ }
+ }
+}
+
+dependencies {
+ //Android integration tests
+ testImplementation("androidx.test:core:1.5.0")
+ androidTestImplementation("androidx.compose.ui:ui-test-manifest:1.3.1")
+ androidTestImplementation("androidx.compose.ui:ui-test:1.3.1")
+ androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.3.1")
+ androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4")
}
// TODO it seems that argument isn't applied to the common sourceSet. Figure out why
@@ -30,4 +120,4 @@ configureMavenPublication(
groupId = "org.jetbrains.compose.components",
artifactId = "components-resources",
name = "Resources for Compose JB"
-)
\ No newline at end of file
+)
diff --git a/components/resources/library/src/androidAndroidTest/kotlin/org/jetbrains/compose/resources/ComposeResourceTest.kt b/components/resources/library/src/androidAndroidTest/kotlin/org/jetbrains/compose/resources/ComposeResourceTest.kt
new file mode 100644
index 0000000000..2803875019
--- /dev/null
+++ b/components/resources/library/src/androidAndroidTest/kotlin/org/jetbrains/compose/resources/ComposeResourceTest.kt
@@ -0,0 +1,61 @@
+package org.jetbrains.compose.resources
+
+import androidx.compose.foundation.Image
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.test.junit4.createComposeRule
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalResourceApi::class, ExperimentalCoroutinesApi::class)
+class ComposeResourceTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun testMissingResource() = runTest (UnconfinedTestDispatcher()) {
+ var recompositionCount = 0
+ rule.setContent {
+ CountRecompositions(resource("missing.png").rememberImageBitmap().orEmpty()) {
+ recompositionCount++
+ }
+ }
+ rule.awaitIdle()
+ assertEquals(2, recompositionCount)
+ }
+
+ @Test
+ fun testCountRecompositions() = runTest (UnconfinedTestDispatcher()) {
+ val mutableStateFlow = MutableStateFlow(true)
+ var recompositionCount = 0
+ rule.setContent {
+ val state: Boolean by mutableStateFlow.collectAsState(true)
+ val resource = resource(if (state) "1.png" else "2.png")
+ CountRecompositions(resource.rememberImageBitmap().orEmpty()) {
+ recompositionCount++
+ }
+ }
+ rule.awaitIdle()
+ mutableStateFlow.value = false
+ rule.awaitIdle()
+ assertEquals(4, recompositionCount)
+ }
+
+}
+
+@Composable
+private fun CountRecompositions(imageBitmap: ImageBitmap?, onRecomposition: () -> Unit) {
+ onRecomposition()
+ if (imageBitmap != null) {
+ Image(bitmap = imageBitmap, contentDescription = null)
+ }
+}
diff --git a/components/resources/library/src/androidAndroidTest/resources/1.png b/components/resources/library/src/androidAndroidTest/resources/1.png
new file mode 100644
index 0000000000000000000000000000000000000000..c11cb2ec658905996d5a1ecb86e8d4c6caf106b0
GIT binary patch
literal 946
zcmV;j15NyiP)^G+oiJ=!Nz8&w9k}QkJa>-xI6jWIedCSZHLW4Loc(E*m
zJS!k$+4{cW5f_hdmhCXZ(zT4Q{xNYoHZFx0OLl~4{UIO;0e=v!BbKPl$nf*Ol9aE8
zDHu^^Nw&B*y!-)43JeS3o-LN*0MR-oX~&4x0ZZW0G3@;FaAT9;n5D!8UBptC3rfu5@q#Etq|B$Ut^Nkn<+$PLOVF$acHl1%cq-GaU3bAv!Lq5?R
zE_NZJv`cE*+W+6jW`{fElijg{jjz1}ZBpWCpE=I4yFnJ{2D@|ZQ;J6__O;8d3O0wx
zf*oR0(Js#RNyW7?>?1Zg2FQX9$YJxSJbO(Vv`?HT*jynobcM}{_E|Lr1w^TaS&4Tf
zhTbV*Rzs8uByLZ;=eM~)V(J15?K{FAi3{gEd>pz+Om%VQJdnfmufQVAnn;W_F^kf_
zB70DV3@|%GV(bjFKzZ(g#62rR)-k(9V(b>Py7JsJiR&pt7BPE5V(baCqVimi#Eq39
zUCf3^j14h!mFLDJPL#GWn;2(MzZg-B
z@J@~gc2oEP9E2Q&U4~qTJ&1S`^C;?B+{cKoF`uJ7-{VmjP*PM@SXx|O
zVM1j_X-aKQaZ+_wd0KtmfPx7PBPwQe{tqdoXGqDEmNB*2ndbCf9dZBw00000E@A-m
U1WWIxpa1{>07*qoM6N<$f)}-`i~s-t
literal 0
HcmV?d00001
diff --git a/components/resources/library/src/androidAndroidTest/resources/2.png b/components/resources/library/src/androidAndroidTest/resources/2.png
new file mode 100644
index 0000000000000000000000000000000000000000..5fa326654ef90ee5b1db23fdf4b1f21dcd6fc9f5
GIT binary patch
literal 785
zcmV+s1Md8ZP)zs)waNAO|nnWVjJc)+h^E)8qz>IiW1F$jelb|l-ofR=5J=#>sk)ukR9w9L+
z-cc8lkSC?;JfY0tnTRfzbcuLInZpxxQmDnNdFV2y!%uXWo2L@5v`Co;-i#j~Q{jJ9
zh>e}_#sewRGJbwSjo+w|7`vcFO4JR5e@CBd=(96SggX9_H!OXRl)08NkA~$ik9P@5
zz&9irpW`H(HY+K80E}8?4)EP4@7qr&Y7Xx}(-)8=u-*HAk#FYfV=1sj5|T#yX`X
zhfg_C&%FcgQ{cV`-nYSj?c8k*fItib&`VG;|HdX@B5*)|kwEsIiu-8mAmk|QGPLD7
zJmEU*LBx}oM^Vq>K1O_v`5fKwJ>KUMkPwj(k`j{>loXW}mKK*+m{6Hfno^rnoK&4v
zp8jZkeje-d^QZc}0R
+
\ No newline at end of file
diff --git a/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/ComposableResource.android.kt b/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/ComposableResource.android.kt
new file mode 100644
index 0000000000..01c312d1db
--- /dev/null
+++ b/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/ComposableResource.android.kt
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.asImageBitmap
+
+@ExperimentalResourceApi
+internal actual fun ByteArray.toImageBitmap(): ImageBitmap = toAndroidBitmap().asImageBitmap()
+
+private fun ByteArray.toAndroidBitmap(): Bitmap {
+ return BitmapFactory.decodeByteArray(this, 0, size);
+}
diff --git a/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/Resource.android.kt b/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/Resource.android.kt
new file mode 100644
index 0000000000..18190a95e4
--- /dev/null
+++ b/components/resources/library/src/androidMain/kotlin/org/jetbrains/compose/resources/Resource.android.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+import java.io.IOException
+
+@ExperimentalResourceApi
+actual fun resource(path: String): Resource = AndroidResourceImpl(path)
+
+@ExperimentalResourceApi
+private class AndroidResourceImpl(path: String) : AbstractResourceImpl(path) {
+ override suspend fun readBytes(): ByteArray {
+ val resource = (::AndroidResourceImpl.javaClass.classLoader).getResourceAsStream(path)
+ if (resource != null) {
+ return resource.readBytes()
+ } else {
+ throw MissingResourceException(path)
+ }
+ }
+}
+
+internal actual class MissingResourceException actual constructor(path: String) :
+ IOException("Missing resource with path: $path")
diff --git a/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ComposeResource.common.kt b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ComposeResource.common.kt
new file mode 100644
index 0000000000..f39c1fcde1
--- /dev/null
+++ b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ComposeResource.common.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+import androidx.compose.runtime.*
+import androidx.compose.ui.graphics.ImageBitmap
+
+private val emptyImageBitmap: ImageBitmap by lazy { ImageBitmap(1, 1) }
+
+/**
+ * Get and remember resource. While loading and if resource not exists result will be null.
+ */
+@ExperimentalResourceApi
+@Composable
+fun Resource.rememberImageBitmap(): LoadState {
+ val state: MutableState> = remember(this) { mutableStateOf(LoadState.Loading()) }
+ LaunchedEffect(this) {
+ state.value = try {
+ LoadState.Success(readBytes().toImageBitmap())
+ } catch (e: Exception) {
+ LoadState.Error(e)
+ }
+ }
+ return state.value
+}
+
+/**
+ * return current ImageBitmap or return empty while loading
+ */
+@ExperimentalResourceApi
+fun LoadState.orEmpty(): ImageBitmap = when (this) {
+ is LoadState.Loading -> emptyImageBitmap
+ is LoadState.Success -> this.value
+ is LoadState.Error -> emptyImageBitmap
+}
+
+internal expect fun ByteArray.toImageBitmap(): ImageBitmap
diff --git a/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ExperimentalResourceApi.kt b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ExperimentalResourceApi.kt
new file mode 100644
index 0000000000..eb1e8a60be
--- /dev/null
+++ b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ExperimentalResourceApi.kt
@@ -0,0 +1,9 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+@RequiresOptIn("This API is experimental and is likely to change in the future.")
+annotation class ExperimentalResourceApi
diff --git a/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/Resource.common.kt b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/Resource.common.kt
new file mode 100644
index 0000000000..59f4463e1d
--- /dev/null
+++ b/components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/Resource.common.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+/**
+ * Should implement equals() and hashCode()
+ */
+@ExperimentalResourceApi
+interface Resource {
+ suspend fun readBytes(): ByteArray //todo in future use streaming
+}
+
+/**
+ * Get a resource from /resources (for example, from commonMain/resources).
+ */
+@ExperimentalResourceApi
+expect fun resource(path: String): Resource
+
+internal expect class MissingResourceException(path: String)
+
+@OptIn(ExperimentalResourceApi::class)
+internal abstract class AbstractResourceImpl(val path: String) : Resource {
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ return if (other is AbstractResourceImpl) {
+ path == other.path
+ } else {
+ false
+ }
+ }
+
+ override fun hashCode(): Int {
+ return path.hashCode()
+ }
+}
diff --git a/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt b/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt
new file mode 100644
index 0000000000..6d47e32c03
--- /dev/null
+++ b/components/resources/library/src/commonTest/kotlin/org/jetbrains/compose/resources/ResourceTest.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+
+@OptIn(ExperimentalResourceApi::class)
+class ResourceTest {
+ @Test
+ fun testResourceEquals() {
+ assertEquals(resource("a"), resource("a"))
+ }
+
+ @Test
+ fun testResourceNotEquals() {
+ assertNotEquals(resource("a"), resource("b"))
+ }
+}
diff --git a/components/resources/library/src/desktopMain/kotlin/org/jetbrains/compose/resources/Resource.desktop.kt b/components/resources/library/src/desktopMain/kotlin/org/jetbrains/compose/resources/Resource.desktop.kt
new file mode 100644
index 0000000000..b6379f63e3
--- /dev/null
+++ b/components/resources/library/src/desktopMain/kotlin/org/jetbrains/compose/resources/Resource.desktop.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
+ */
+
+package org.jetbrains.compose.resources
+
+import java.io.IOException
+
+@ExperimentalResourceApi
+actual fun resource(path: String): Resource = DesktopResourceImpl(path)
+
+@ExperimentalResourceApi
+private class DesktopResourceImpl(path: String) : AbstractResourceImpl(path) {
+ override suspend fun readBytes(): ByteArray {
+ val resource = (::DesktopResourceImpl.javaClass.classLoader).getResourceAsStream(path)
+ if (resource != null) {
+ return resource.readBytes()
+ } else {
+ throw MissingResourceException(path)
+ }
+ }
+}
+
+internal actual class MissingResourceException actual constructor(path: String) :
+ IOException("Missing resource with path: $path")
diff --git a/components/resources/library/src/desktopTest/kotlin/org/jetbrains/compose/resources/ComposeResourceTest.kt b/components/resources/library/src/desktopTest/kotlin/org/jetbrains/compose/resources/ComposeResourceTest.kt
new file mode 100644
index 0000000000..2803875019
--- /dev/null
+++ b/components/resources/library/src/desktopTest/kotlin/org/jetbrains/compose/resources/ComposeResourceTest.kt
@@ -0,0 +1,61 @@
+package org.jetbrains.compose.resources
+
+import androidx.compose.foundation.Image
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.test.junit4.createComposeRule
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Rule
+import org.junit.Test
+
+@OptIn(ExperimentalResourceApi::class, ExperimentalCoroutinesApi::class)
+class ComposeResourceTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ @Test
+ fun testMissingResource() = runTest (UnconfinedTestDispatcher()) {
+ var recompositionCount = 0
+ rule.setContent {
+ CountRecompositions(resource("missing.png").rememberImageBitmap().orEmpty()) {
+ recompositionCount++
+ }
+ }
+ rule.awaitIdle()
+ assertEquals(2, recompositionCount)
+ }
+
+ @Test
+ fun testCountRecompositions() = runTest (UnconfinedTestDispatcher()) {
+ val mutableStateFlow = MutableStateFlow(true)
+ var recompositionCount = 0
+ rule.setContent {
+ val state: Boolean by mutableStateFlow.collectAsState(true)
+ val resource = resource(if (state) "1.png" else "2.png")
+ CountRecompositions(resource.rememberImageBitmap().orEmpty()) {
+ recompositionCount++
+ }
+ }
+ rule.awaitIdle()
+ mutableStateFlow.value = false
+ rule.awaitIdle()
+ assertEquals(4, recompositionCount)
+ }
+
+}
+
+@Composable
+private fun CountRecompositions(imageBitmap: ImageBitmap?, onRecomposition: () -> Unit) {
+ onRecomposition()
+ if (imageBitmap != null) {
+ Image(bitmap = imageBitmap, contentDescription = null)
+ }
+}
diff --git a/components/resources/library/src/desktopTest/resources/1.png b/components/resources/library/src/desktopTest/resources/1.png
new file mode 100644
index 0000000000000000000000000000000000000000..c11cb2ec658905996d5a1ecb86e8d4c6caf106b0
GIT binary patch
literal 946
zcmV;j15NyiP)^G+oiJ=!Nz8