From ec620228b6130969822013e541ae834d25d8b015 Mon Sep 17 00:00:00 2001 From: "a.emogurov" Date: Tue, 6 Aug 2024 11:08:42 +0400 Subject: [PATCH 1/3] AND-145: move textvalue into gears --- settings.gradle.kts | 2 + textvalue/CHANGELOG.md | 10 +++ textvalue/README.md | 77 +++++++++++++++++ textvalue/build.gradle.kts | 3 + textvalue/gradle.properties | 1 + textvalue/textvalue-common/build.gradle.kts | 16 ++++ .../src/main/kotlin/TextValue.kt | 84 +++++++++++++++++++ textvalue/textvalue-compose/build.gradle.kts | 18 ++++ .../src/main/kotlin/StringResources.kt | 31 +++++++ 9 files changed, 242 insertions(+) create mode 100644 textvalue/CHANGELOG.md create mode 100644 textvalue/README.md create mode 100644 textvalue/build.gradle.kts create mode 100644 textvalue/gradle.properties create mode 100644 textvalue/textvalue-common/build.gradle.kts create mode 100644 textvalue/textvalue-common/src/main/kotlin/TextValue.kt create mode 100644 textvalue/textvalue-compose/build.gradle.kts create mode 100644 textvalue/textvalue-compose/src/main/kotlin/StringResources.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index e539fbb..fd3d797 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -61,4 +61,6 @@ include( ":viewmodelevents:viewmodelevents-flow", ":viewmodelevents:viewmodelevents-livedata", ":resultflow", + ":textvalue:textvalue-common", + ":textvalue:textvalue-compose" ) diff --git a/textvalue/CHANGELOG.md b/textvalue/CHANGELOG.md new file mode 100644 index 0000000..3bb1203 --- /dev/null +++ b/textvalue/CHANGELOG.md @@ -0,0 +1,10 @@ +## [Unreleased] + +*No changes* + +## [1.0.0] + +- Public release textvalue library and textvalue-compose extensions library + +[unreleased]: https://github.com/RedMadRobot/TextValue/compare/1.0.0...main +[1.0.0]: https://github.com/RedMadRobot/TextValue/compare/d5d1d9...1.0.0 diff --git a/textvalue/README.md b/textvalue/README.md new file mode 100644 index 0000000..caca5dd --- /dev/null +++ b/textvalue/README.md @@ -0,0 +1,77 @@ +# TextValue +[![Version](https://img.shields.io/maven-central/v/com.redmadrobot.textvalue/textvalue?style=flat-square)][mavenCentral] +[![License](https://img.shields.io/github/license/RedMadRobot/textvalue?style=flat-square)][license] + +TextValue is an abstraction allowing to work with a `String` and a string resource ID the same way. + +--- + + + +- [Installation](#installation) +- [Usage](#usage) +- [Contributing](#contributing) + + + +## Installation + +Add the dependency: +```groovy +repositories { + mavenCentral() + google() +} + +dependencies { + // Views version + implementation("com.redmadrobot.textvalue:textvalue-common:") + + // Compose extensions for textvalue + implementation("com.redmadrobot.textvalue:textvalue-compose:") +} +``` + +## Usage + +**TextValue** is a wrapper to make it possible to work with plain `String` and `StringRes` in the same way. +It may be useful for cases when you want to fallback to `StringRes` if desired string value is `null`. + +You can wrap `String` and `StringRes` with `TextValue` using `TextValue(String)`, `TextValue(Int)` or `TextValue(String?, Int))`, and use method `TextValue.get(Resource)` to retrieve `String`: + +```kotlin +// in some place where we can't access Context +val errorMessage = TextValue(exception.message, defaultResourceId = R.string.unknown_error) +showMessage(errorMessage) + +// in Activity, Fragment or View +fun showMessage(text: TextValue) { + val messageText = text.get(resources) + //... +} +``` + +`TextValue` also could be used with Jetpack Compose: + +```kotlin +// in Composable functions +@Composable +fun Screen(title: TextValue) { + // Remember to add com.redmadrobot.textvalue:textvalue-compose dependency + Text(text = stringResource(title)) +} +``` + +There are extensions to work with `TextValue` like with `StringRes`: + +- `Context.getString(text: TextValue): String` +- `View.getString(text: TextValue): String` +- `Resources.getString(text: TextValue): String` + +## Contributing + +Merge requests are welcome. +For major changes, please open an issue first to discuss what you would like to change. + +[mavenCentral]: https://search.maven.org/artifact/com.redmadrobot.textvalue/textvalue +[license]: LICENSE diff --git a/textvalue/build.gradle.kts b/textvalue/build.gradle.kts new file mode 100644 index 0000000..9790631 --- /dev/null +++ b/textvalue/build.gradle.kts @@ -0,0 +1,3 @@ +// For some reason gradle.properties in this project doesn't affect its subprojects +val textValueGroup = group +subprojects { group = textValueGroup } diff --git a/textvalue/gradle.properties b/textvalue/gradle.properties new file mode 100644 index 0000000..53ace56 --- /dev/null +++ b/textvalue/gradle.properties @@ -0,0 +1 @@ +group=com.redmadrobot.textvalue diff --git a/textvalue/textvalue-common/build.gradle.kts b/textvalue/textvalue-common/build.gradle.kts new file mode 100644 index 0000000..0559d5c --- /dev/null +++ b/textvalue/textvalue-common/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + convention.library.android + id("kotlin-parcelize") +} + +description = "TextValue is an abstraction over Android text" + +android { + namespace = "$group.common" +} + +dependencies { + api(kotlin("stdlib")) + api(androidx.annotation) + compileOnly(androidx.compose.runtime) +} diff --git a/textvalue/textvalue-common/src/main/kotlin/TextValue.kt b/textvalue/textvalue-common/src/main/kotlin/TextValue.kt new file mode 100644 index 0000000..2ee2bb7 --- /dev/null +++ b/textvalue/textvalue-common/src/main/kotlin/TextValue.kt @@ -0,0 +1,84 @@ +package com.redmadrobot.textvalue + +import android.content.Context +import android.content.res.Resources +import android.os.Parcelable +import android.view.View +import androidx.annotation.StringRes +import androidx.compose.runtime.Immutable +import kotlinx.parcelize.Parcelize + +/** + * Wrapper to make it possible to work with plain [String] and [StringRes] in the same way. + * + * ``` + * // in some place where we can't access Context + * val errorMessage = TextValue(exception.message, defaultResourceId= R.string.unknown_error) + * showMessage(errorMessage) + * + * // in Activity, Fragment or View + * val messageText = getString(message) + * ``` + */ +@Immutable +public sealed interface TextValue : Parcelable { + + /** Retrieves [String] using the given [resources]. */ + public fun get(resources: Resources): String + + override fun equals(other: Any?): Boolean + override fun hashCode(): Int + + /** Plain string. */ + @Parcelize + public data class Plain(public val string: String) : TextValue { + override fun get(resources: Resources): String = string + } + + /** String resource, requires [Resources] to get [String]. */ + @Parcelize + public data class Resource(@StringRes public val resourceId: Int) : TextValue { + override fun get(resources: Resources): String = resources.getString(resourceId) + } + + public companion object { + + /** Empty [TextValue]. */ + public val EMPTY: TextValue = TextValue("") + } +} + +/** Creates [TextValue] from the given [resourceId]. */ +public fun TextValue(@StringRes resourceId: Int): TextValue = TextValue.Resource(resourceId) + +/** Creates [TextValue] from the given [string]. */ +public fun TextValue(string: String): TextValue = TextValue.Plain(string) + +/** Creates [TextValue] from the given [string], or from the [defaultResourceId] if string is `null`. */ +public fun TextValue(string: String?, @StringRes defaultResourceId: Int): TextValue { + return if (string != null) TextValue.Plain(string) else TextValue.Resource(defaultResourceId) +} + +/** + * Unwraps and returns a string for the given [text]. + * @see TextValue + */ +public fun Context.getString(text: TextValue): String = resources.getString(text) + +/** + * Unwraps and returns a string for the given [text]. + * @see TextValue + */ +public fun View.getString(text: TextValue): String = resources.getString(text) + +/** + * Unwraps and returns a string for the given [text]. + * @see TextValue + */ +public fun Resources.getString(text: TextValue): String = text.get(this) + +/** + * Returns TextValue itself if it is not `null`, or the [TextValue.EMPTY] otherwise. + * @see TextValue + */ +public fun TextValue?.orEmpty(): TextValue = this ?: TextValue.EMPTY diff --git a/textvalue/textvalue-compose/build.gradle.kts b/textvalue/textvalue-compose/build.gradle.kts new file mode 100644 index 0000000..599c59a --- /dev/null +++ b/textvalue/textvalue-compose/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + convention.library.android +} + +description = "Compose extensions for TextValue" + +dependencies { + api(project(":textvalue:textvalue-common")) + api(androidx.compose.ui) +} + +android { + namespace = "$group.compose" + + buildFeatures { + compose = true + } +} diff --git a/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt b/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt new file mode 100644 index 0000000..3426299 --- /dev/null +++ b/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt @@ -0,0 +1,31 @@ +package com.redmadrobot.textvalue.compose + +import android.content.res.Resources +import androidx.compose.runtime.Composable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext +import com.redmadrobot.textvalue.TextValue +import com.redmadrobot.textvalue.getString + +/** + * Unwraps and returns a string for the given [text]. + * @see TextValue + */ +@Composable +@ReadOnlyComposable +public fun stringResource(text: TextValue): String { + val resources = resources() + return resources.getString(text) +} + +/** + * A composable function that returns the [Resources]. It will be recomposed when [Configuration] + * gets updated. + */ +@Composable +@ReadOnlyComposable +private fun resources(): Resources { + LocalConfiguration.current + return LocalContext.current.resources +} From b35fb1b4541d70dddc6034d7da8f1edee19f2066 Mon Sep 17 00:00:00 2001 From: "a.emogurov" Date: Tue, 6 Aug 2024 11:32:55 +0400 Subject: [PATCH 2/3] AND-145: migrate to kotlin compiler plugin & minor improves --- README.md | 8 ++++++++ textvalue/textvalue-compose/build.gradle.kts | 1 + .../textvalue-compose/src/main/kotlin/StringResources.kt | 4 +--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 25cf4dc..a86504e 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,11 @@ Gears could be used together or alone. A couple of extensions to convert long operations into `Flow>`. +### :speech_balloon: **[TextValue](textvalue/)** + +- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=textvalue-common)][textvalue-common] - An implementation of the TextValue - an abstraction over Android text +- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=textvalue-compose)][textvalue-compose] - A set of handy tools for dealing with TextValue inside `@Composable` functions + ## Why Gears? The goal of this mono-repository is to simplify the creation and publication of libraries. @@ -75,5 +80,8 @@ For major changes, open a [discussion][discussions] first to discuss what you wo [viewmodelevents-flow]: viewmodelevents/viewmodelevents-flow/ [viewmodelevents-livedata]: viewmodelevents/viewmodelevents-livedata/ +[textvalue-common]: textvalue/textvalue-common/ +[textvalue-compose]: textvalue/textvalue-compose/ + [ci]: https://github.com/RedMadRobot/gears-android/actions?query=branch%3Amain++ [discussions]: https://github.com/RedMadRobot/gears-android/discussions diff --git a/textvalue/textvalue-compose/build.gradle.kts b/textvalue/textvalue-compose/build.gradle.kts index 599c59a..ff8efb9 100644 --- a/textvalue/textvalue-compose/build.gradle.kts +++ b/textvalue/textvalue-compose/build.gradle.kts @@ -1,5 +1,6 @@ plugins { convention.library.android + alias(stack.plugins.kotlin.compose) } description = "Compose extensions for TextValue" diff --git a/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt b/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt index 3426299..eadf3d6 100644 --- a/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt +++ b/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt @@ -1,12 +1,10 @@ -package com.redmadrobot.textvalue.compose +package com.redmadrobot.textvalue import android.content.res.Resources import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalContext -import com.redmadrobot.textvalue.TextValue -import com.redmadrobot.textvalue.getString /** * Unwraps and returns a string for the given [text]. From bca33a219400aa593ca4ae07fee954df4b4faddb Mon Sep 17 00:00:00 2001 From: "a.emogurov" Date: Mon, 19 Aug 2024 09:58:20 +0400 Subject: [PATCH 3/3] AND-145: review fixes --- README.md | 18 ++++-------------- settings.gradle.kts | 2 +- textvalue/README.md | 11 ++++++----- textvalue/textvalue-compose/build.gradle.kts | 2 +- .../src/main/kotlin/StringResources.kt | 3 +-- .../build.gradle.kts | 2 +- .../src/main/kotlin/TextValue.kt | 0 7 files changed, 14 insertions(+), 24 deletions(-) rename textvalue/{textvalue-common => textvalue}/build.gradle.kts (89%) rename textvalue/{textvalue-common => textvalue}/src/main/kotlin/TextValue.kt (100%) diff --git a/README.md b/README.md index a86504e..f6f623e 100644 --- a/README.md +++ b/README.md @@ -33,20 +33,17 @@ Gears could be used together or alone. - [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.extensions/resources-ktx?style=flat-square&label=resources-ktx)][resources-ktx] — A set of extensions for accessing resources - [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.extensions/viewbinding-ktx?style=flat-square&label=viewbinding-ktx)][viewbinding-ktx] — A set of extensions for dealing with ViewBinding -### :mag_right: **[ViewModelEvents](viewmodelevents/)** +### :mag_right: **[ViewModelEvents](viewmodelevents/)** [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=viewmodelevents) -- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=viewmodelevents-compose)][viewmodelevents-compose] — A set of extensions for dealing with ViewModelEvents inside `@Composable` functions -- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=viewmodelevents-flow)][viewmodelevents-flow] — An implementation of ViewModelEvents via `Flow` -- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=viewmodelevents-livedata)][viewmodelevents-livedata] — An implementation of ViewModelEvents via `LiveData` +`ViewModelEvents` addresses the challenge of buffering and consuming one-time events: ### :hourglass_flowing_sand: **[Result Flow](resultflow/)** ![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/resultflow?style=flat-square) A couple of extensions to convert long operations into `Flow>`. -### :speech_balloon: **[TextValue](textvalue/)** +### :speech_balloon: **[TextValue](textvalue/)** ![Version](https://img.shields.io/maven-central/v/com.redmadrobot.textvalue/textvalue?style=flat-square) -- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=textvalue-common)][textvalue-common] - An implementation of the TextValue - an abstraction over Android text -- [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.gears/kotlin?style=flat-square&label=textvalue-compose)][textvalue-compose] - A set of handy tools for dealing with TextValue inside `@Composable` functions +An abstraction over Android text ## Why Gears? @@ -76,12 +73,5 @@ For major changes, open a [discussion][discussions] first to discuss what you wo [gears-compose]: gears/gears-compose [gears-kotlin]: gears/gears-kotlin -[viewmodelevents-compose]: viewmodelevents/viewmodelevents-compose/ -[viewmodelevents-flow]: viewmodelevents/viewmodelevents-flow/ -[viewmodelevents-livedata]: viewmodelevents/viewmodelevents-livedata/ - -[textvalue-common]: textvalue/textvalue-common/ -[textvalue-compose]: textvalue/textvalue-compose/ - [ci]: https://github.com/RedMadRobot/gears-android/actions?query=branch%3Amain++ [discussions]: https://github.com/RedMadRobot/gears-android/discussions diff --git a/settings.gradle.kts b/settings.gradle.kts index fd3d797..44382f7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -61,6 +61,6 @@ include( ":viewmodelevents:viewmodelevents-flow", ":viewmodelevents:viewmodelevents-livedata", ":resultflow", - ":textvalue:textvalue-common", + ":textvalue:textvalue", ":textvalue:textvalue-compose" ) diff --git a/textvalue/README.md b/textvalue/README.md index caca5dd..bc88165 100644 --- a/textvalue/README.md +++ b/textvalue/README.md @@ -1,6 +1,7 @@ -# TextValue +# TextValue + [![Version](https://img.shields.io/maven-central/v/com.redmadrobot.textvalue/textvalue?style=flat-square)][mavenCentral] -[![License](https://img.shields.io/github/license/RedMadRobot/textvalue?style=flat-square)][license] +[![License](https://img.shields.io/github/license/RedMadRobot/gears-android?style=flat-square)][license] TextValue is an abstraction allowing to work with a `String` and a string resource ID the same way. @@ -25,7 +26,7 @@ repositories { dependencies { // Views version - implementation("com.redmadrobot.textvalue:textvalue-common:") + implementation("com.redmadrobot.textvalue:textvalue:") // Compose extensions for textvalue implementation("com.redmadrobot.textvalue:textvalue-compose:") @@ -73,5 +74,5 @@ There are extensions to work with `TextValue` like with `StringRes`: Merge requests are welcome. For major changes, please open an issue first to discuss what you would like to change. -[mavenCentral]: https://search.maven.org/artifact/com.redmadrobot.textvalue/textvalue -[license]: LICENSE +[mavenCentral]: https://central.sonatype.com/artifact/com.redmadrobot.textvalue/textvalue +[license]: ../LICENSE diff --git a/textvalue/textvalue-compose/build.gradle.kts b/textvalue/textvalue-compose/build.gradle.kts index ff8efb9..a34b83a 100644 --- a/textvalue/textvalue-compose/build.gradle.kts +++ b/textvalue/textvalue-compose/build.gradle.kts @@ -6,7 +6,7 @@ plugins { description = "Compose extensions for TextValue" dependencies { - api(project(":textvalue:textvalue-common")) + api(project(":textvalue:textvalue")) api(androidx.compose.ui) } diff --git a/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt b/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt index eadf3d6..166a321 100644 --- a/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt +++ b/textvalue/textvalue-compose/src/main/kotlin/StringResources.kt @@ -13,8 +13,7 @@ import androidx.compose.ui.platform.LocalContext @Composable @ReadOnlyComposable public fun stringResource(text: TextValue): String { - val resources = resources() - return resources.getString(text) + return resources().getString(text) } /** diff --git a/textvalue/textvalue-common/build.gradle.kts b/textvalue/textvalue/build.gradle.kts similarity index 89% rename from textvalue/textvalue-common/build.gradle.kts rename to textvalue/textvalue/build.gradle.kts index 0559d5c..fef1abd 100644 --- a/textvalue/textvalue-common/build.gradle.kts +++ b/textvalue/textvalue/build.gradle.kts @@ -6,7 +6,7 @@ plugins { description = "TextValue is an abstraction over Android text" android { - namespace = "$group.common" + namespace = "$group" } dependencies { diff --git a/textvalue/textvalue-common/src/main/kotlin/TextValue.kt b/textvalue/textvalue/src/main/kotlin/TextValue.kt similarity index 100% rename from textvalue/textvalue-common/src/main/kotlin/TextValue.kt rename to textvalue/textvalue/src/main/kotlin/TextValue.kt