Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
[![CI](https://github.com/ioki-mobility/TextRef/actions/workflows/test-lib.yml/badge.svg)](https://github.com/ioki-mobility/TextRef/actions/workflows/test-lib.yml)
[![Maven Central](https://img.shields.io/maven-central/v/com.ioki.textref/textref?labelColor=%2324292E&color=%233246c8)](https://central.sonatype.com/namespace/com.ioki.textref) <!-- Disabled because of: https://github.com/badges/shields/pull/10997
[![Snapshot](https://img.shields.io/nexus/s/com.ioki.textref/textref?labelColor=%2324292E&color=%234f78ff&server=https://s01.oss.sonatype.org)](https://s01.oss.sonatype.org/content/repositories/snapshots/com/ioki/textref/) -->
[![javadoc](https://javadoc.io/badge2/com.ioki.textref/textref/javadoc.svg?labelColor=%2324292E&color=%236eaaff)](https://javadoc.io/doc/com.ioki.textref)
[![javadoc](https://javadoc.io/badge2/com.ioki.textref/textref/javadoc.svg?labelColor=%2324292E&color=%236eaaff)](https://javadoc.io/doc/com.ioki.textref)
[![MIT](https://img.shields.io/badge/license-MIT-blue.svg?labelColor=%2324292E&color=%23d11064)](https://github.com/ioki-mobility/TextRef/blob/master/LICENSE.md)

## What?

TextRef is an abstraction over Android text. It wraps a `String` or a string/plurals resource ID.
With the help of an Android `Context` a final `String` can be resolved. Format args are supported too!
With the help of Android `Context` or `Resources` a final `String` can be resolved. Format args are supported too!

## How?

Expand All @@ -24,6 +24,7 @@ TextRef.string("The arguments are %d and %s", 5, "foo")
**Resolve**
```kotlin
val text: String = textRef.resolve(context)
val textFromResources: String = textRef.resolve(resources)
```

## Why?
Expand Down
6 changes: 3 additions & 3 deletions compose/src/main/kotlin/com/ioki/textref/compose/TextRef.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.ioki.textref.compose

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalResources
import com.ioki.textref.TextRef

@Composable
fun textRef(textRef: TextRef): String = textRef.resolve(LocalContext.current)
fun textRef(textRef: TextRef): String = textRef.resolve(LocalResources.current)

@Composable
fun textRefOrNull(textRef: TextRef?): String? = textRef?.resolve(LocalContext.current)
fun textRefOrNull(textRef: TextRef?): String? = textRef?.resolve(LocalResources.current)
27 changes: 19 additions & 8 deletions core/src/main/java/com/ioki/textref/TextRef.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ioki.textref

import android.content.Context
import android.content.res.Resources
import android.os.Parcel
import android.os.ParcelFormatException
import android.os.Parcelable
Expand All @@ -26,30 +27,40 @@ class TextRef private constructor(
* @param context The context used to resolve the string if created from a [StringRes] ID
* @return A String, formatted with any args passed on creation
*/
fun resolve(context: Context): String {
val args = processArgs(context)
fun resolve(context: Context): String = resolve(context.resources)

/**
* Resolves the contents of the TextRef to a [String].
*
* Any format args passed on creation will be used to format the string.
*
* @param resources The resources used to resolve string and plurals resource IDs
* @return A String, formatted with any args passed on creation
*/
fun resolve(resources: Resources): String {
val args = processArgs(resources)
return when {
value is String && args.isEmpty() -> value
value is String -> value.format(*args)
value is Int && args.isEmpty() -> context.getString(value)
value is Int -> context.getString(value, *args)
value is Int && args.isEmpty() -> resources.getString(value)
value is Int -> resources.getString(value, *args)
value is Pair<*, *> && args.isEmpty() -> {
val id = value.first as Int
val quantity = value.second as Int
context.resources.getQuantityString(id, quantity)
resources.getQuantityString(id, quantity)
}
value is Pair<*, *> -> {
val id = value.first as Int
val quantity = value.second as Int
context.resources.getQuantityString(id, quantity, *args)
resources.getQuantityString(id, quantity, *args)
}
else -> error("Unsupported type: ${value.javaClass.name}")
}
}

private fun processArgs(context: Context): Array<Any> =
private fun processArgs(resources: Resources): Array<Any> =
args.map {
if (it is TextRef) it.resolve(context)
if (it is TextRef) it.resolve(resources)
else it
}.toTypedArray()

Expand Down
31 changes: 27 additions & 4 deletions core/src/test/java/com/ioki/textref/TextRefTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class TextRefTest {
private val formattedIdWithIntArg = "biz $intArg"
private val formattedIdWithStringArg = "biz bar"
private val formattedIdWithTwoArgs = "biz $intArg bar"
private val formattedIdWithTextRefArg = "biz $formattedIdWithoutArg"

private val formattedPluralWithoutArg = "boz"
private val formattedPluralWithIntArg = "boz $intArg"
Expand All @@ -52,10 +53,11 @@ class TextRefTest {
@Before
fun setUp() {
`when`(mockContext.resources).thenReturn(mockResources)
`when`(mockContext.getString(idWithoutArg)).thenReturn(formattedIdWithoutArg)
`when`(mockContext.getString(idWithIntArg, intArg)).thenReturn(formattedIdWithIntArg)
`when`(mockContext.getString(idWithStringArg, stringArg)).thenReturn(formattedIdWithStringArg)
`when`(mockContext.getString(idWithTwoArgs, intArg, stringArg)).thenReturn(formattedIdWithTwoArgs)
`when`(mockResources.getString(idWithoutArg)).thenReturn(formattedIdWithoutArg)
`when`(mockResources.getString(idWithIntArg, intArg)).thenReturn(formattedIdWithIntArg)
`when`(mockResources.getString(idWithStringArg, stringArg)).thenReturn(formattedIdWithStringArg)
`when`(mockResources.getString(idWithStringArg, formattedIdWithoutArg)).thenReturn(formattedIdWithTextRefArg)
`when`(mockResources.getString(idWithTwoArgs, intArg, stringArg)).thenReturn(formattedIdWithTwoArgs)
`when`(mockResources.getQuantityString(idWithoutArg, quantity)).thenReturn(formattedPluralWithoutArg)
`when`(mockResources.getQuantityString(idWithIntArg, quantity, intArg)).thenReturn(formattedPluralWithIntArg)
`when`(mockResources.getQuantityString(idWithStringArg, quantity, stringArg)).thenReturn(
Expand Down Expand Up @@ -87,6 +89,13 @@ class TextRefTest {
assertThat(result).isEqualTo(formattedIdWithoutArg)
}

@Test
fun resolve_createdWithStringResAndResources_resultIsCorrect() {
val result = TextRef.stringRes(idWithoutArg).resolve(mockResources)

assertThat(result).isEqualTo(formattedIdWithoutArg)
}

@Test
fun createdWithNullStringRes_resultIsEmptyTextRef() {
val result = TextRef.stringRes(null)
Expand All @@ -101,6 +110,13 @@ class TextRefTest {
assertThat(result).isEqualTo(formattedPluralWithoutArg)
}

@Test
fun resolve_createdWithPluralsResAndResources_resultIsCorrect() {
val result = TextRef.pluralsRes(idWithoutArg, quantity).resolve(mockResources)

assertThat(result).isEqualTo(formattedPluralWithoutArg)
}

@Test
fun createdWithNullPluralsRes_resultIsEmptyTextRef() {
val result = TextRef.pluralsRes(null, quantity)
Expand Down Expand Up @@ -157,6 +173,13 @@ class TextRefTest {
assertThat(result).isEqualTo(formattedIdWithStringArg)
}

@Test
fun resolve_createdWithStringResAndTextRefArgAndResources_resultIsCorrect() {
val result = TextRef.stringRes(idWithStringArg, TextRef.stringRes(idWithoutArg)).resolve(mockResources)

assertThat(result).isEqualTo(formattedIdWithTextRefArg)
}

@Test
fun resolve_createdWithStringResAndTwoArgs_resultIsCorrect() {
val result = TextRef.stringRes(idWithTwoArgs, intArg, stringArg).resolve(mockContext)
Expand Down
Loading