Updated the regex to correctly match multi-digit placeholders in string
templates. Added a suite of tests to ensure `replaceWithArgs` handles
various edge cases like missing arguments, mismatched placeholders, and
invalid formats reliably.
Fixes https://youtrack.jetbrains.com/issue/CMP-7236
## Testing
- Unit tests
## Release Notes
### Fixes - Resources
- Fix string resource's regex for placeholders to correctly match
multi-digit placeholders.
First commit fixes compose resources for native macOS app (see currently
broken chat app using `runDebugExecutableMacosArm64`).
Second commit adds support for embedding resources into native macOS
framework. Similar to how it works on iOS. This allows using the macOS
compose code in an Xcode project. Just like iOS, using kotlin code as
framwork. Then call the main function from the Xcode project to run the
compose app.
## Testing
First commit: run chat app using `runDebugExecutableMacosArm64`
Second commit: Tested by adding macOS support to the iOS Xcode project
in chat app (not in this PR). Can add the sample app if needed.
## Release Notes
### Features - Resources
- Add new API to preload and cache font and image resources on web
targets: `preloadFont`, `preloadImageBitmap`, `preloadImageVector`
____
Add a new experimental web-specific API to preload fonts and images:
```kotlin
@Composable
fun preloadFont(
resource: FontResource,
weight: FontWeight = FontWeight.Normal,
style: FontStyle = FontStyle.Normal
): State<Font?>
@Composable
fun preloadImageBitmap(
resource: DrawableResource,
): State<ImageBitmap?>
@Composable
fun preloadImageVector(
resource: DrawableResource,
): State<ImageVector?>
```
Using this methods in advance, it's possible to avoid FOUT (flash of
unstyled text), or flickering of images/icons.
Usage example:
```kotlin
val font1 by preloadFont(Res.font.Workbench_Regular)
val font2 by preloadFont(Res.font.font_awesome, FontWeight.Normal, FontStyle.Normal)
UseResources() // Main App that uses the above fonts
if (font1 != null && font2 != null) {
println("Fonts are ready")
} else {
Box(modifier = Modifier.fillMaxSize().background(Color.White.copy(alpha = 0.8f)).clickable { }) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
println("Fonts are not ready yet")
}
```
Should fix
```
Dependency 'androidx.compose.foundation:foundation-android:1.8.0-alpha02' requires libraries and applications that depend on it to compile against version 35 or later of the Android APIs.
```
Fixes https://youtrack.jetbrains.com/issue/CMP-6688
## Testing
Added a unit test.
<!-- Optional -->
This should be tested by QA
## Release Notes
### Fixes - Resources
- Read `android:autoMirrored="true"` property and pass it to ImageVector
builder
1) The PR adds a support test resources in Compose multiplatform
projects.
2) The PR adds a support multi-module resources in JVM-only projects.
Fixes https://youtrack.jetbrains.com/issue/CMP-1470
Fixes https://youtrack.jetbrains.com/issue/CMP-5963
## Release Notes
### Features - Resources
- Added support of test resources in Compose Multiplatform projects
- Added support of multi-module resources in JVM-only projects
Use deprecated `seekToFileOffset` on iOS 12 to fix a crash on old Apple
devices
Fixes https://youtrack.jetbrains.com/issue/CMP-5967
## Release Notes
### Fixes - Resources
- _(prerelease fix)_ Fix a resource reading on iOS 12
The PR adds a method to convert a bitmap bytearray to the ImageBitma, a
vector XML content bytearray to the ImageVector in the common code. And
the same for an SVG files on non-android targets.
<!-- Optional -->
Fixes https://youtrack.jetbrains.com/issue/CMP-3869
Fixes https://youtrack.jetbrains.com/issue/CMP-4925
## Release Notes
### Features - Resources
- Added utility functions to decode `Bitmap ByteArray as ImageVector`
and `XML ByteArray as ImageVector` in the common code and `SVG ByteArray
as Painter` in the non-android code
Add a font cache on non-android targets.
Android targets already have own font caching.
Fixes https://youtrack.jetbrains.com/issue/CMP-1477
## Release Notes
### Features - Resources
- To avoid constant reading raw font bytes on each Font usage on
non-android targets, there was added the font cache. Android has own
font cache inside the platform implementation.
In some cases the skip and read methods may handle less bytes then
expected. The PR fixes it by proper API on the JVM and manual check on
the Android.
Fixes https://github.com/JetBrains/compose-multiplatform/issues/4938
## Testing
I manually checked it on the project from the issue.
## Release Notes
### Fixes - Resources
- Read exactly requested count of bytes from InputStream on jvm
platforms.
The change speeds resources web rendering up by the reading a cached
value instantly by request (it was being dispatched to the end of the UI
queue in `LaunchedEffect`)
## Release Notes
### Features - Resources
- Speed resources web rendering up by the reading a cached value
instantly
Fixes#4863
Before this update, when a new `resource` value was passed to
`org.jetbrains.compose.resources.Font` composable, it kept the original
value.
Test sample code. `Res.font` here is autogenerated from
`commonMain/composeResources/font/` folder content.
```kt
var flag by remember {
mutableStateOf(false)
}
Column {
Text(
"hey",
fontFamily = FontFamily(Font(if (flag) Res.font.HelveticaNeueMedium else Res.font.COMICSANS, FontWeight.Normal))
)
Switch(checked = flag, onCheckedChange = { flag = it })
}
```
## Release Notes
### Fixes - Resources
- Fix a cached font if the resource acessor was changed
Before the fix we could cancel a coroutine and the cancelled deferred
was saved in cache.
## Release Notes
### Fixes - Resources
- _(prerelease fix)_ Fix a cached empty resource on a Compose for Web if
the resource loading was canceled during progress
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 https://github.com/JetBrains/compose-multiplatform/issues/4360
We need to filter by language and region together because there is
slightly different logic:
1) if there is the exact match language+region then use it
2) if there is the language WITHOUT region match then use it
3) in other cases use items WITHOUT language and region qualifiers at
all
Given resources:
values
values-en-rUS
values-de
Filter results:
"en" -> values
"en-US" -> values-en-rUS
"en-GB" -> values
"de-IT" -> values-de
fixes https://github.com/JetBrains/compose-multiplatform/issues/4571
Adds a public `Res.getUri(path: String): String` function.
It lets external libraries a way to read resource files by a platform
dependent Uri.
E.g.: video players, image loaders or embedded web browsers.
```kotlin
val uri = Res.getUri("files/my_video.mp4")
```
fixes https://github.com/JetBrains/compose-multiplatform/issues/4360
Users noticed if an app has big a `string.xml` file it affects the app
startup time:
https://github.com/JetBrains/compose-multiplatform/issues/4537
The problem is slow XML parsing.
Possible ways for optimization:
1) inject text resources direct to the source code
2) convert XMLs to an optimized format to read it faster
We selected the second way because texts injected to source code have
several problems:
- strict limitations on text size
- increase compilation and analysation time
- affects a class loader and GC
> Note: android resources do the same and converts xml values to own
`resources.arsc` file
Things was done in the PR:
1) added support any XML files in the `values` directory
2) **[BREAKING CHANGE]** added `Res.array` accessor for string-array
resources
3) in a final app there won't be original `values*/*.xml` files. There
will be converted `values*/*.cvr` files.
4) generated code points on string resources as file -> offset+size
5) string resource cache is by item now (it was by the full xml file
before)
6) implemented random access to read CVR files
7) tasks for syncing ios resources to a final app were seriously
refactored to support generated resources (CVR files)
8) restriction for 3-party resources plugin were deleted
9) Gradle property `compose.resources.always.generate.accessors` was
deleted. It was for internal needs only.
Fixes https://github.com/JetBrains/compose-multiplatform/issues/4537
Ports a part of Unicode's ICU in pure Kotlin and implements
Android-style plural string resource support. Fixes
JetBrains/compose-multiplatform#425.
# Changes
- Added `org.jetbrains.compose.resources.intl.{PluralCategory,
PluralRule, PluralRuleList}`, which parses and evaluates scripts in
Unicode's Locale Data Markup Langauge.
- Copied `plurals.xml` from Unicode's
[CLDR](https://github.com/unicode-org/cldr/blob/release-44-1/common/supplemental/plurals.xml).
- Added `GeneratePluralRuleListsTask`, which parses `plurals.xml` and
generates required Kotlin source codes.
- Added `PluralStringResource`, `pluralStringResource`, or
`getPluralString`, corresponding to `StringResource`, `stringResource`,
or `getString`.
- Modified `ResourcesSpec.kt` so the generated `Res` class exposes
`Res.plurals`.
# Potential Further Improvements
- [ ] Allow configuring the default language in the `compose.resources
{}` block (#4482) to determine the default pluralization rule (or just
presume English as default)
- [ ] Move the parser logic to the Gradle plugin and generate
pluralization rules in `Res` only for languages used in
`composeResources`
---------
Co-authored-by: Konstantin Tskhovrebov <konstantin.tskhovrebov@jetbrains.com>
There is a bug on iOS:
```
NSLocale.currentLocale() -> 'en-US'
NSLocale.preferredLanguages().first().let { NSLocale(it as String) } -> 'ru'
```
An equal result was expected!
the first method was used in a non-compose code and another one in the
compose code.
The PR fixes behavior in a non-compose environment.
The issue was because we cache the value in the current composition, and
the next composition returns the cached value.
There weren't an issue if we just call one `stringResource` after
another because those are different compositions.
Fixes https://github.com/JetBrains/compose-multiplatform/issues/4325
The issue was because we cache the value in the current composition, and the next composition returns the cached value.
There weren't an issue if we just call one `stringResource` after another because those are different compositions.
Fixes https://github.com/JetBrains/compose-multiplatform/issues/4325