Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get environment and select resource by qualifiers #4018

Merged
merged 12 commits into from
Dec 20, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fun FileRes(paddingValues: PaddingValues) {
mutableStateOf(ByteArray(0))
}
LaunchedEffect(Unit) {
bytes = readBytes("composeRes/images/droid_icon.xml")
bytes = readResourceBytes("composeRes/images/droid_icon.xml")
}
Text(bytes.decodeToString())
""".trimIndent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import components.resources.demo.generated.resources.Res
import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.getStringArray
import org.jetbrains.compose.resources.stringResource
import org.jetbrains.compose.resources.stringArrayResource
import org.jetbrains.compose.resources.readResourceBytes

@Composable
Expand Down Expand Up @@ -54,7 +54,7 @@ fun StringRes(paddingValues: PaddingValues) {
}
OutlinedTextField(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
value = getString(Res.strings.app_name),
value = stringResource(Res.strings.app_name),
onValueChange = {},
label = { Text("Text(getString(Res.strings.app_name)") },
enabled = false,
Expand All @@ -66,7 +66,7 @@ fun StringRes(paddingValues: PaddingValues) {
)
OutlinedTextField(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
value = getString(Res.strings.hello),
value = stringResource(Res.strings.hello),
onValueChange = {},
label = { Text("Text(getString(Res.strings.hello)") },
enabled = false,
Expand All @@ -78,7 +78,7 @@ fun StringRes(paddingValues: PaddingValues) {
)
OutlinedTextField(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
value = getString(Res.strings.multi_line),
value = stringResource(Res.strings.multi_line),
onValueChange = {},
label = { Text("Text(getString(Res.strings.multi_line)") },
enabled = false,
Expand All @@ -90,7 +90,7 @@ fun StringRes(paddingValues: PaddingValues) {
)
OutlinedTextField(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
value = getString(Res.strings.str_template, "User_name", 100),
value = stringResource(Res.strings.str_template, "User_name", 100),
onValueChange = {},
label = { Text("Text(getString(Res.strings.str_template, \"User_name\", 100)") },
enabled = false,
Expand All @@ -102,7 +102,7 @@ fun StringRes(paddingValues: PaddingValues) {
)
OutlinedTextField(
modifier = Modifier.padding(16.dp).fillMaxWidth(),
value = getStringArray(Res.strings.str_arr).toString(),
value = stringArrayResource(Res.strings.str_arr).toString(),
onValueChange = {},
label = { Text("Text(getStringArray(Res.strings.str_arr).toString())") },
enabled = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ class ComposeResourceTest {
setContent {
CompositionLocalProvider(LocalResourceReader provides testResourceReader) {
val res by stringIdFlow.collectAsState()
Text(getString(res))
Text(getStringArray(TestStringResource("str_arr")).joinToString())
Text(stringResource(res))
Text(stringArrayResource(TestStringResource("str_arr")).joinToString())
}
}
awaitIdle()
Expand All @@ -94,12 +94,12 @@ class ComposeResourceTest {
fun testReadStringResource() = runComposeUiTest {
runBlockingTest {
setContent {
assertEquals("Compose Resources App", getString(TestStringResource("app_name")))
assertEquals("Compose Resources App", stringResource(TestStringResource("app_name")))
assertEquals(
"Hello, test-name! You have 42 new messages.",
getString(TestStringResource("str_template"), "test-name", 42)
stringResource(TestStringResource("str_template"), "test-name", 42)
)
assertEquals(listOf("item 1", "item 2", "item 3"), getStringArray(TestStringResource("str_arr")))
assertEquals(listOf("item 1", "item 2", "item 3"), stringArrayResource(TestStringResource("str_arr")))
}
awaitIdle()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package org.jetbrains.compose.resources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.font.*

@ExperimentalResourceApi
@Composable
actual fun Font(resource: FontResource, weight: FontWeight, style: FontStyle): Font {
val path = resource.getPathByEnvironment()
val environment = rememberEnvironment()
val path = remember(environment) { resource.getPathByEnvironment(environment) }
return Font(path, LocalContext.current.assets, weight, style)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.jetbrains.compose.resources

import android.content.res.Configuration
import android.content.res.Resources
import java.util.*

internal actual fun getResourceEnvironment(): ResourceEnvironment {
val locale = Locale.getDefault()
val configuration = Resources.getSystem().configuration
val isDarkTheme = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
val dpi = configuration.densityDpi
return ResourceEnvironment(
language = LanguageQualifier(locale.language),
region = RegionQualifier(locale.country),
theme = ThemeQualifier.selectByValue(isDarkTheme),
density = DensityQualifier.selectByValue(dpi)
)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.jetbrains.compose.resources

import androidx.compose.runtime.*
import kotlinx.coroutines.runBlocking

@Composable
internal actual fun <T> rememberResourceState(
key: Any,
getDefault: () -> T,
block: suspend (ResourceEnvironment) -> T
): State<T> {
val environment = rememberEnvironment()
return remember(key, environment) {
mutableStateOf(
runBlocking { block(environment) }
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package org.jetbrains.compose.resources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.font.*

/**
* Represents a font resource.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package org.jetbrains.compose.resources

import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
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.platform.LocalDensity
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.jetbrains.compose.resources.vector.toImageVector
Expand Down Expand Up @@ -50,7 +44,8 @@ fun ImageResource(path: String): ImageResource = ImageResource(
@ExperimentalResourceApi
@Composable
fun painterResource(resource: ImageResource): Painter {
val filePath = remember(resource) { resource.getPathByEnvironment() }
val environment = rememberEnvironment()
val filePath = remember(resource, environment) { resource.getPathByEnvironment(environment) }
val isXml = filePath.endsWith(".xml", true)
if (isXml) {
return rememberVectorPainter(vectorResource(resource))
Expand All @@ -71,8 +66,8 @@ private val emptyImageBitmap: ImageBitmap by lazy { ImageBitmap(1, 1) }
@Composable
fun imageResource(resource: ImageResource): ImageBitmap {
val resourceReader = LocalResourceReader.current
val imageBitmap by rememberState(resource, { emptyImageBitmap }) {
val path = resource.getPathByEnvironment()
val imageBitmap by rememberResourceState(resource, { emptyImageBitmap }) { env ->
val path = resource.getPathByEnvironment(env)
val cached = loadImage(path, resourceReader) {
ImageCache.Bitmap(it.toImageBitmap())
} as ImageCache.Bitmap
Expand All @@ -96,8 +91,8 @@ private val emptyImageVector: ImageVector by lazy {
fun vectorResource(resource: ImageResource): ImageVector {
val resourceReader = LocalResourceReader.current
val density = LocalDensity.current
val imageVector by rememberState(resource, { emptyImageVector }) {
val path = resource.getPathByEnvironment()
val imageVector by rememberResourceState(resource, { emptyImageVector }) { env ->
val path = resource.getPathByEnvironment(env)
val cached = loadImage(path, resourceReader) {
ImageCache.Vector(it.toXmlElement().toImageVector(density))
} as ImageCache.Vector
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.jetbrains.compose.resources

interface Qualifier

data class LanguageQualifier(
val language: String
) : Qualifier {
companion object {
val regex = Regex("[a-z][a-z]")
MatkovIvan marked this conversation as resolved.
Show resolved Hide resolved
}
}

data class RegionQualifier(
val region: String
) : Qualifier {
companion object {
val regex = Regex("r[A-Z][A-Z]")
}
}

enum class ThemeQualifier(val code: String) : Qualifier {
LIGHT("light"),
DARK("dark");

companion object {
fun selectByValue(isDark: Boolean) =
if (isDark) DARK else LIGHT
}
}

//https://developer.android.com/guide/topics/resources/providing-resources
enum class DensityQualifier(val code: String, val dpi: Int) : Qualifier {
LDPI("ldpi", 120),
MDPI("mdpi", 160),
HDPI("hdpi", 240),
XHDPI("xhdpi", 320),
XXHDPI("xxhdpi", 480),
XXXHDPI("xxxhdpi", 640);

companion object {
fun selectByValue(dpi: Int) = when {
dpi <= LDPI.dpi -> LDPI
dpi <= MDPI.dpi -> MDPI
dpi <= HDPI.dpi -> HDPI
dpi <= XHDPI.dpi -> XHDPI
dpi <= XXHDPI.dpi -> XXHDPI
else -> XXXHDPI
}
fun selectByDensity(density: Float) = when {
density <= 0.75 -> LDPI
density <= 1.0 -> MDPI
density <= 1.33 -> HDPI
density <= 2.0 -> XHDPI
density <= 3.0 -> XXHDPI
else -> XXXHDPI
}
}
}

//TODO: move it to the gradle plugin
internal fun List<String>.parseQualifiers(): List<Qualifier> {
var language: LanguageQualifier? = null
var region: RegionQualifier? = null
var theme: ThemeQualifier? = null
var density: DensityQualifier? = null

this.forEach { q ->
if (density == null) {
DensityQualifier.entries.firstOrNull { it.code == q }?.let {
density = it
return@forEach
}
}
if (theme == null) {
ThemeQualifier.entries.firstOrNull { it.code == q }?.let {
theme = it
return@forEach
}
}
if (language == null && q.matches(LanguageQualifier.regex)) {
language = LanguageQualifier(q)
return@forEach
}
if (region == null && q.matches(RegionQualifier.regex)) {
region = RegionQualifier(q.takeLast(2))
return@forEach
}
}

return buildList {
language?.let { add(it) }
region?.let { add(it) }
theme?.let { add(it) }
density?.let { add(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,3 @@ data class ResourceItem(
internal val qualifiers: Set<String>,
internal val path: String
)

internal fun Resource.getPathByEnvironment(): String {
//TODO
return items.first().path
}
Loading