Skip to content

Commit afe548b

Browse files
authored
[resources] Add functions to retrieve bytes from drawable or font resources. (JetBrains#4651)
Implemented two new experimental functions: ```kotlin /** * Retrieves the byte array of the drawable resource. * * @param environment The resource environment, which can be obtained from [rememberResourceEnvironment] or [getSystemResourceEnvironment]. * @param resource The drawable resource. * @return The byte array representing the drawable resource. */ @ExperimentalResourceApi suspend fun getDrawableResourceBytes( environment: ResourceEnvironment, resource: DrawableResource ): ByteArray {...} /** * Retrieves the byte array of the font resource. * * @param environment The resource environment, which can be obtained from [rememberResourceEnvironment] or [getSystemResourceEnvironment]. * @param resource The font resource. * @return The byte array representing the font resource. */ @ExperimentalResourceApi suspend fun getFontResourceBytes( environment: ResourceEnvironment, resource: FontResource ): ByteArray {...} ``` fixes JetBrains#4360
1 parent d14b8f0 commit afe548b

File tree

15 files changed

+261
-56
lines changed

15 files changed

+261
-56
lines changed

components/README.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,6 @@ in Android Studio or in AppCode with [installed CocoaPods](https://kotlinlang.or
1313
### Run JS in browser with WebAssembly Skia via Gradle:
1414
`./gradlew :resources:demo:shared:jsBrowserDevelopmentRun`
1515

16-
### Run MacOS via Gradle:
17-
- on Intel CPU: `./gradlew :resources:demo:shared:runDebugExecutableMacosX64`
18-
- on Apple Silicon: `./gradlew :resources:demo:shared:runDebugExecutableMacosArm64`
19-
2016
# Tests
2117
Run script:
2218
```bash

components/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ android.useAndroidX=true
88

99
#Versions
1010
kotlin.version=1.9.23
11-
compose.version=1.6.10-beta01
11+
compose.version=1.6.10-dev1596
1212
agp.version=8.2.2
1313

1414
#Compose

components/resources/demo/shared/build.gradle.kts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,8 @@ kotlin {
3939
binaries.executable()
4040
}
4141

42-
listOf(
43-
macosX64(),
44-
macosArm64()
45-
).forEach { macosTarget ->
46-
macosTarget.binaries {
47-
executable {
48-
entryPoint = "main"
49-
}
50-
}
51-
}
52-
5342
applyDefaultHierarchyTemplate()
5443
sourceSets {
55-
all {
56-
languageSettings {
57-
optIn("org.jetbrains.compose.resources.ExperimentalResourceApi")
58-
}
59-
}
6044
val desktopMain by getting
6145
val wasmJsMain by getting
6246

components/resources/demo/shared/src/commonMain/kotlin/org/jetbrains/compose/resources/demo/shared/FileRes.kt

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ import androidx.compose.runtime.*
99
import androidx.compose.ui.Modifier
1010
import androidx.compose.ui.unit.dp
1111
import components.resources.demo.shared.generated.resources.Res
12+
import components.resources.demo.shared.generated.resources.droid_icon
13+
import org.jetbrains.compose.resources.ExperimentalResourceApi
14+
import org.jetbrains.compose.resources.getDrawableResourceBytes
15+
import org.jetbrains.compose.resources.rememberResourceEnvironment
1216

17+
@OptIn(ExperimentalResourceApi::class)
1318
@Composable
1419
fun FileRes(paddingValues: PaddingValues) {
1520
Column(
16-
modifier = Modifier.padding(paddingValues)
21+
modifier = Modifier.padding(paddingValues).verticalScroll(rememberScrollState())
1722
) {
1823
Text(
1924
modifier = Modifier.padding(16.dp),
@@ -48,6 +53,34 @@ fun FileRes(paddingValues: PaddingValues) {
4853
Text(bytes.decodeToString())
4954
""".trimIndent()
5055
)
56+
HorizontalDivider(modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp))
57+
OutlinedCard(
58+
modifier = Modifier.padding(horizontal = 16.dp),
59+
shape = RoundedCornerShape(4.dp),
60+
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer)
61+
) {
62+
val composeEnv = rememberResourceEnvironment()
63+
var bytes by remember { mutableStateOf(ByteArray(0)) }
64+
LaunchedEffect(Unit) {
65+
bytes = getDrawableResourceBytes(composeEnv, Res.drawable.droid_icon)
66+
}
67+
Text(
68+
modifier = Modifier.padding(8.dp),
69+
text = "droid_icon byte size = " + bytes.size,
70+
color = MaterialTheme.colorScheme.onPrimaryContainer
71+
)
72+
}
73+
Text(
74+
modifier = Modifier.padding(16.dp),
75+
text = """
76+
val composeEnv = rememberResourceEnvironment()
77+
var bytes by remember { mutableStateOf(ByteArray(0)) }
78+
LaunchedEffect(Unit) {
79+
bytes = getDrawableResourceBytes(composeEnv, Res.drawable.droid_icon)
80+
}
81+
Text("droid_icon byte size = " + bytes.size)
82+
""".trimIndent()
83+
)
5184
Text(
5285
modifier = Modifier.padding(16.dp),
5386
text = "File: 'files/platform-text.txt'",
@@ -80,5 +113,23 @@ fun FileRes(paddingValues: PaddingValues) {
80113
Text(bytes.decodeToString())
81114
""".trimIndent()
82115
)
116+
HorizontalDivider(modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp))
117+
OutlinedCard(
118+
modifier = Modifier.padding(horizontal = 16.dp),
119+
shape = RoundedCornerShape(4.dp),
120+
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.primaryContainer)
121+
) {
122+
Text(
123+
modifier = Modifier.padding(8.dp),
124+
text = "File URI: " + Res.getUri("files/platform-text.txt"),
125+
color = MaterialTheme.colorScheme.onPrimaryContainer
126+
)
127+
}
128+
Text(
129+
modifier = Modifier.padding(16.dp),
130+
text = """
131+
Text("File URI: " + Res.getUri("files/platform-text.txt"))
132+
""".trimIndent()
133+
)
83134
}
84135
}

components/resources/demo/shared/src/macosMain/composeResources/files/platform-text.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

components/resources/demo/shared/src/macosMain/kotlin/main.macos.kt

Lines changed: 0 additions & 17 deletions
This file was deleted.

components/resources/library/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ kotlin {
5353
optIn("kotlinx.cinterop.ExperimentalForeignApi")
5454
optIn("kotlin.experimental.ExperimentalNativeApi")
5555
optIn("org.jetbrains.compose.resources.InternalResourceApi")
56+
optIn("org.jetbrains.compose.resources.ExperimentalResourceApi")
5657
}
5758
}
5859

components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/FontResources.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.jetbrains.compose.resources
22

33
import androidx.compose.runtime.Composable
44
import androidx.compose.runtime.Immutable
5+
import androidx.compose.runtime.getValue
56
import androidx.compose.ui.text.font.*
67

78
/**
@@ -32,4 +33,20 @@ expect fun Font(
3233
resource: FontResource,
3334
weight: FontWeight = FontWeight.Normal,
3435
style: FontStyle = FontStyle.Normal
35-
): Font
36+
): Font
37+
38+
/**
39+
* Retrieves the byte array of the font resource.
40+
*
41+
* @param environment The resource environment, which can be obtained from [rememberResourceEnvironment] or [getSystemResourceEnvironment].
42+
* @param resource The font resource.
43+
* @return The byte array representing the font resource.
44+
*/
45+
@ExperimentalResourceApi
46+
suspend fun getFontResourceBytes(
47+
environment: ResourceEnvironment,
48+
resource: FontResource
49+
): ByteArray {
50+
val resourceItem = resource.getResourceItemByEnvironment(environment)
51+
return DefaultResourceReader.read(resourceItem.path)
52+
}

components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ImageResources.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ internal expect fun SvgElement.toSvgPainter(density: Density): Painter
9595

9696
private val emptySvgPainter: Painter by lazy { BitmapPainter(emptyImageBitmap) }
9797

98-
@OptIn(ExperimentalResourceApi::class)
9998
@Composable
10099
private fun svgPainter(resource: DrawableResource): Painter {
101100
val resourceReader = LocalResourceReader.current
@@ -110,6 +109,22 @@ private fun svgPainter(resource: DrawableResource): Painter {
110109
return svgPainter
111110
}
112111

112+
/**
113+
* Retrieves the byte array of the drawable resource.
114+
*
115+
* @param environment The resource environment, which can be obtained from [rememberResourceEnvironment] or [getSystemResourceEnvironment].
116+
* @param resource The drawable resource.
117+
* @return The byte array representing the drawable resource.
118+
*/
119+
@ExperimentalResourceApi
120+
suspend fun getDrawableResourceBytes(
121+
environment: ResourceEnvironment,
122+
resource: DrawableResource
123+
): ByteArray {
124+
val resourceItem = resource.getResourceItemByEnvironment(environment)
125+
return DefaultResourceReader.read(resourceItem.path)
126+
}
127+
113128
internal expect fun ByteArray.toImageBitmap(): ImageBitmap
114129
internal expect fun ByteArray.toXmlElement(): Element
115130
internal expect fun ByteArray.toSvgElement(): SvgElement

components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/PluralStringResources.kt

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,24 @@ fun pluralStringResource(resource: PluralStringResource, quantity: Int): String
4343
* @throws IllegalArgumentException If the provided ID or the pluralization is not found in the resource file.
4444
*/
4545
suspend fun getPluralString(resource: PluralStringResource, quantity: Int): String =
46-
loadPluralString(resource, quantity, DefaultResourceReader, getResourceEnvironment())
46+
loadPluralString(resource, quantity, DefaultResourceReader, getSystemResourceEnvironment())
47+
48+
/**
49+
* Loads a string using the specified string resource.
50+
*
51+
* @param environment The resource environment.
52+
* @param resource The string resource to be used.
53+
* @param quantity The quantity of the pluralization to use.
54+
* @return The loaded string resource.
55+
*
56+
* @throws IllegalArgumentException If the provided ID or the pluralization is not found in the resource file.
57+
*/
58+
@ExperimentalResourceApi
59+
suspend fun getPluralString(
60+
environment: ResourceEnvironment,
61+
resource: PluralStringResource,
62+
quantity: Int
63+
): String = loadPluralString(resource, quantity, DefaultResourceReader, environment)
4764

4865
private suspend fun loadPluralString(
4966
resource: PluralStringResource,
@@ -99,9 +116,33 @@ suspend fun getPluralString(resource: PluralStringResource, quantity: Int, varar
99116
resource, quantity,
100117
formatArgs.map { it.toString() },
101118
DefaultResourceReader,
102-
getResourceEnvironment(),
119+
getSystemResourceEnvironment(),
103120
)
104121

122+
/**
123+
* Loads a string using the specified string resource.
124+
*
125+
* @param environment The resource environment.
126+
* @param resource The string resource to be used.
127+
* @param quantity The quantity of the pluralization to use.
128+
* @param formatArgs The arguments to be inserted into the formatted string.
129+
* @return The loaded string resource.
130+
*
131+
* @throws IllegalArgumentException If the provided ID or the pluralization is not found in the resource file.
132+
*/
133+
@ExperimentalResourceApi
134+
suspend fun getPluralString(
135+
environment: ResourceEnvironment,
136+
resource: PluralStringResource,
137+
quantity: Int,
138+
vararg formatArgs: Any
139+
): String = loadPluralString(
140+
resource, quantity,
141+
formatArgs.map { it.toString() },
142+
DefaultResourceReader,
143+
environment
144+
)
145+
105146
private suspend fun loadPluralString(
106147
resource: PluralStringResource,
107148
quantity: Int,

components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.kt

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,35 @@ import androidx.compose.runtime.*
55
import androidx.compose.ui.platform.LocalDensity
66
import androidx.compose.ui.text.intl.Locale
77

8-
internal data class ResourceEnvironment(
9-
val language: LanguageQualifier,
10-
val region: RegionQualifier,
11-
val theme: ThemeQualifier,
12-
val density: DensityQualifier
13-
)
8+
@ExperimentalResourceApi
9+
class ResourceEnvironment internal constructor(
10+
internal val language: LanguageQualifier,
11+
internal val region: RegionQualifier,
12+
internal val theme: ThemeQualifier,
13+
internal val density: DensityQualifier
14+
) {
15+
override fun equals(other: Any?): Boolean {
16+
if (this === other) return true
17+
if (other == null || this::class != other::class) return false
18+
19+
other as ResourceEnvironment
20+
21+
if (language != other.language) return false
22+
if (region != other.region) return false
23+
if (theme != other.theme) return false
24+
if (density != other.density) return false
25+
26+
return true
27+
}
28+
29+
override fun hashCode(): Int {
30+
var result = language.hashCode()
31+
result = 31 * result + region.hashCode()
32+
result = 31 * result + theme.hashCode()
33+
result = 31 * result + density.hashCode()
34+
return result
35+
}
36+
}
1437

1538
internal interface ComposeEnvironment {
1639
@Composable
@@ -39,14 +62,32 @@ internal val DefaultComposeEnvironment = object : ComposeEnvironment {
3962
//ComposeEnvironment provider will be overridden for tests
4063
internal val LocalComposeEnvironment = staticCompositionLocalOf { DefaultComposeEnvironment }
4164

65+
/**
66+
* Returns an instance of [ResourceEnvironment].
67+
*
68+
* The [ResourceEnvironment] class represents the environment for resources.
69+
*
70+
* @return An instance of [ResourceEnvironment] representing the current environment.
71+
*/
72+
@ExperimentalResourceApi
73+
@Composable
74+
fun rememberResourceEnvironment(): ResourceEnvironment {
75+
val composeEnvironment = LocalComposeEnvironment.current
76+
return composeEnvironment.rememberEnvironment()
77+
}
78+
4279
internal expect fun getSystemEnvironment(): ResourceEnvironment
4380

4481
//the function reference will be overridden for tests
82+
//@TestOnly
83+
internal var getResourceEnvironment = ::getSystemEnvironment
84+
4585
/**
46-
* Provides the resource environment for non-composable access to string resources.
86+
* Provides the resource environment for non-composable access to resources.
4787
* It is an expensive operation! Don't use it in composable functions with no cache!
4888
*/
49-
internal var getResourceEnvironment = ::getSystemEnvironment
89+
@ExperimentalResourceApi
90+
fun getSystemResourceEnvironment(): ResourceEnvironment = getResourceEnvironment()
5091

5192
@OptIn(InternalResourceApi::class)
5293
internal fun Resource.getResourceItemByEnvironment(environment: ResourceEnvironment): ResourceItem {

components/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/StringArrayResources.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,22 @@ fun stringArrayResource(resource: StringArrayResource): List<String> {
4646
* @throws IllegalStateException if the string array with the given ID is not found.
4747
*/
4848
suspend fun getStringArray(resource: StringArrayResource): List<String> =
49-
loadStringArray(resource, DefaultResourceReader, getResourceEnvironment())
49+
loadStringArray(resource, DefaultResourceReader, getSystemResourceEnvironment())
50+
51+
/**
52+
* Loads a list of strings using the specified string array resource.
53+
*
54+
* @param environment The resource environment.
55+
* @param resource The string array resource to be used.
56+
* @return A list of strings representing the items in the string array.
57+
*
58+
* @throws IllegalStateException if the string array with the given ID is not found.
59+
*/
60+
@ExperimentalResourceApi
61+
suspend fun getStringArray(
62+
environment: ResourceEnvironment,
63+
resource: StringArrayResource
64+
): List<String> = loadStringArray(resource, DefaultResourceReader, environment)
5065

5166
private suspend fun loadStringArray(
5267
resource: StringArrayResource,

0 commit comments

Comments
 (0)