-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Get environment and select resource by qualifiers
- Loading branch information
Showing
20 changed files
with
422 additions
and
86 deletions.
There are no files selected for viewing
8 changes: 4 additions & 4 deletions
8
...s/library/src/androidMain/kotlin/org/jetbrains/compose/resources/FontResources.android.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
18 changes: 18 additions & 0 deletions
18
...ary/src/androidMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.android.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
) | ||
} |
14 changes: 0 additions & 14 deletions
14
...library/src/blockingMain/kotlin/org/jetbrains/compose/resources/PlatformState.blocking.kt
This file was deleted.
Oops, something went wrong.
18 changes: 18 additions & 0 deletions
18
...library/src/blockingMain/kotlin/org/jetbrains/compose/resources/ResourceState.blocking.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) } | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
96 changes: 96 additions & 0 deletions
96
...ents/resources/library/src/commonMain/kotlin/org/jetbrains/compose/resources/Qualifier.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]") | ||
} | ||
} | ||
|
||
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) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
...rces/library/src/commonMain/kotlin/org/jetbrains/compose/resources/ResourceEnvironment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.jetbrains.compose.resources | ||
|
||
import androidx.compose.runtime.* | ||
import androidx.compose.ui.LocalSystemTheme | ||
import androidx.compose.ui.SystemTheme | ||
import androidx.compose.ui.platform.LocalDensity | ||
import androidx.compose.ui.text.intl.Locale | ||
|
||
internal data class ResourceEnvironment( | ||
val language: LanguageQualifier, | ||
val region: RegionQualifier, | ||
val theme: ThemeQualifier, | ||
val density: DensityQualifier | ||
) | ||
|
||
@OptIn(InternalComposeApi::class) | ||
@Composable | ||
internal fun rememberEnvironment(): ResourceEnvironment { | ||
val composeLocale = Locale.current | ||
val composeTheme = LocalSystemTheme.current | ||
val composeDensity = LocalDensity.current | ||
|
||
//cache ResourceEnvironment unless compose environment is changed | ||
//TODO provide top level function with a single cache in a root of compose tree | ||
return remember(composeLocale, composeTheme, composeDensity) { | ||
ResourceEnvironment( | ||
LanguageQualifier(composeLocale.language), | ||
RegionQualifier(composeLocale.region), | ||
ThemeQualifier.selectByValue(composeTheme == SystemTheme.Dark), | ||
DensityQualifier.selectByDensity(composeDensity.density) | ||
) | ||
} | ||
} | ||
|
||
//expensive operation - do not use during recomposition | ||
//it is required for a non-composable access to string resources | ||
internal expect fun getResourceEnvironment(): ResourceEnvironment | ||
|
||
internal fun Resource.getPathByEnvironment(environment: ResourceEnvironment): String { | ||
items.toList() | ||
.filterBy(environment.language) | ||
.also { if (it.size == 1) return it.first().path } | ||
.filterBy(environment.region) | ||
.also { if (it.size == 1) return it.first().path } | ||
.filterBy(environment.theme) | ||
.also { if (it.size == 1) return it.first().path } | ||
.filterBy(environment.density) | ||
.also { if (it.size == 1) return it.first().path } | ||
.let { return it.first().path } | ||
} | ||
|
||
private fun List<ResourceItem>.filterBy(qualifier: Qualifier): List<ResourceItem> { | ||
val items = map { it to it.qualifiers.toList().parseQualifiers() } | ||
val withQualifier = items.filter { (_, qualifiers) -> | ||
qualifiers.any { it == qualifier } | ||
}.map { (item, _) -> item } | ||
|
||
if (withQualifier.isNotEmpty()) return withQualifier | ||
|
||
val withoutQualifier = items.filter { (_, qualifiers) -> | ||
qualifiers.none { it::class == qualifier::class } | ||
}.map { (item, _) -> item } | ||
|
||
if (withoutQualifier.isNotEmpty()) return withoutQualifier | ||
|
||
return this | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.