diff --git a/client/src/main/kotlin/io/spine/chords/client/EntityChooser.kt b/client/src/main/kotlin/io/spine/chords/client/EntityChooser.kt index ea0c4871..bbdacd39 100644 --- a/client/src/main/kotlin/io/spine/chords/client/EntityChooser.kt +++ b/client/src/main/kotlin/io/spine/chords/client/EntityChooser.kt @@ -70,7 +70,7 @@ public abstract class EntityChooser< > : DropdownSelector() { /** - * An enumeration of class's type parameters. + * An enumeration of the class's type parameters. */ @Suppress("unused" /* All type parameters are listed for completeness despite only a part of them might be used via this enum. */) @@ -92,10 +92,8 @@ public abstract class EntityChooser< private val entityStatesByIds: HashMap = hashMapOf() /** - * A function which has to be implemented to provide a value of - * type `Class[E]` for the component which is being implemented. - * - * E.g., if [E] is a `User` class, it would just specify `User::class.java`. + * Identifies a type specified for the [E] type parameter by the + * implementation of the actual component's instance. */ @OptIn(ExperimentalStdlibApi::class) private val entityStateClass: Class get() { @@ -108,11 +106,13 @@ public abstract class EntityChooser< "The V type parameter (entity value type) cannot be a star <*> projection. " } - // We only have the entity state type as an abstract `Type` value at - // runtime, so we have no other choice than to explicitly cast it to - // Class here (it's safe as long as `TypeParameters` enum is kept - // up to date). - @Suppress("UNCHECKED_CAST") + @Suppress( + // We only have the entity state type as an abstract `Type` value at + // runtime, so we have no other choice than to explicitly cast it to + // Class here (it's safe as long as `TypeParameters` enum is kept + // up to date). + "UNCHECKED_CAST" + ) return entityStateType.javaType as Class } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 63cfab45..47a649c4 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -25,6 +25,7 @@ */ import io.spine.internal.dependency.Kotest +import io.spine.internal.dependency.Kotlin import io.spine.internal.dependency.Material3 import io.spine.internal.dependency.Voyager @@ -34,7 +35,7 @@ plugins { dependencies { api(Voyager.navigator) - implementation(project(":runtime")) + implementation(Kotlin.reflect) implementation(compose.desktop.currentOs) implementation(Material3.Desktop.lib) testImplementation(Kotest.runnerJUnit5) diff --git a/core/src/main/kotlin/io/spine/chords/core/Component.kt b/core/src/main/kotlin/io/spine/chords/core/Component.kt index 6d005460..45302e91 100644 --- a/core/src/main/kotlin/io/spine/chords/core/Component.kt +++ b/core/src/main/kotlin/io/spine/chords/core/Component.kt @@ -34,6 +34,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import io.spine.chords.core.appshell.Props +import kotlin.reflect.javaType +import kotlin.reflect.full.allSupertypes import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.isActive import kotlinx.coroutines.launch @@ -180,14 +182,12 @@ import kotlinx.coroutines.launch * perspective this would just be a `someProp` property that can be configured * with any `String` value. * - * Here's an example of creating an input component that allows entering + * Here's an example of creating an input component that displays * a string value: * * ```kotlin * public class HelloComponent : Component() { - * public companion object : ComponentSetup({ - * HelloComponent() - * }) + * public companion object : ComponentSetup() * * public var name: String by mutableStateOf("") * @@ -234,9 +234,8 @@ import kotlinx.coroutines.launch * * ```kotlin * public class StyledHelloComponent : Component() { - * public companion object : ComponentSetup({ - * StyledHelloComponent() // <-- Note child class name. ^^^ - * }) + * public companion object : ComponentSetup() + * // Note child class name here ^^^ * * // Add some more component customization properties... * public var style: TextStyle by mutableStateOf(MaterialTheme.typography.bodyMedium) @@ -345,7 +344,7 @@ import kotlinx.coroutines.launch * Here's an example: * ``` * public class HelloComponent : Component() { - * public companion object : ComponentSetup({ HelloComponent() }) + * public companion object : ComponentSetup() * * public lateinit var name: String * @@ -838,7 +837,7 @@ public abstract class Component : DefaultPropsOwnerBase() { * @see ComponentSetup */ public abstract class AbstractComponentSetup( - protected val createInstance: (() -> Component)? = null + protected var createInstance: (() -> Component)? = null ) { /** @@ -946,14 +945,75 @@ public abstract class AbstractComponentSetup( * should be instantiated and rendered via this companion object). * * @constructor Creates a companion object for a component of type [C]. - * @param createInstance A lambda that should create a component's instance of - * type [C] with the given properties configuration callback. + * @param createInstance An optional lambda that should create a component's + * instance of type [C]. In most cases (when a component has the recommended + * no-args constructor), there's no need to specify this parameter. * @see AbstractComponentSetup */ -public open class ComponentSetup( - createInstance: () -> C +public abstract class ComponentSetup< + C : Component // Keep the list of type parameters in sync with the `TypeParameters` enum! + >( + createInstance: (() -> C)? = null ) : AbstractComponentSetup(createInstance) { + /** + * An enumeration of the class's type parameters. + */ + private enum class TypeParameters(val index: Int) { + + /** + * The component type parameter (the class's `C` parameter). + */ + COMPONENT_TYPE(0), + } + + init { + if (this.createInstance == null) { + this.createInstance = { + createInstanceByTypeParameter() + } + } + } + + /** + * Creates an instance of a component by its type parameter [C], which is + * detected automatically from the class instance's implementation. + */ + private fun createInstanceByTypeParameter(): C { + val cls = componentClass + val defaultConstructor = cls.declaredConstructors.find { it.parameters.isEmpty() } + checkNotNull(defaultConstructor) { + "A component must have a no-args constructor: $cls" + } + @Suppress("UNCHECKED_CAST") + return defaultConstructor.newInstance() as C + } + + /** + * Identifies a type specified for the [C] type parameter by the companion + * object that implements this class. + */ + @OptIn(ExperimentalStdlibApi::class) + private val componentClass: Class get() { + val parameterizedEntityChooserType = this::class.allSupertypes.first { + it.classifier == ComponentSetup::class + } + val entityStateType = + parameterizedEntityChooserType.arguments[TypeParameters.COMPONENT_TYPE.index].type + checkNotNull(entityStateType) { + "The C type parameter (component type) cannot be a star <*> projection." + } + + @Suppress( + // We only have the component type as an abstract `Type` value at + // runtime, so we have no other choice than to explicitly cast it to + // Class here (it's safe as long as `TypeParameters` enum is kept + // up to date). + "UNCHECKED_CAST" + ) + return entityStateType.javaType as Class + } + /** * Declares an instance of component of type [C] with the respective * property value specifications. @@ -965,7 +1025,7 @@ public open class ComponentSetup( * Once an instance is created, it is saved using [remember] and is reused * for subsequent recompositions. * - * @param props A lambda that is invoked in context of the component's + * @param props A lambda that is invoked in the context of the component's * instance, which should configure its properties in a way that is needed * for this component's instance. It is invoked before each recomposition * of the component. diff --git a/core/src/main/kotlin/io/spine/chords/core/DropdownSelector.kt b/core/src/main/kotlin/io/spine/chords/core/DropdownSelector.kt index 9eade09b..d2e6a1b2 100644 --- a/core/src/main/kotlin/io/spine/chords/core/DropdownSelector.kt +++ b/core/src/main/kotlin/io/spine/chords/core/DropdownSelector.kt @@ -40,6 +40,8 @@ import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.Text import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldColors +import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect import androidx.compose.runtime.Stable @@ -125,6 +127,12 @@ public abstract class DropdownSelector : InputComponent() { */ public var modifier: Modifier by mutableStateOf(Modifier) + /** + * A [TextFieldColors] instance, which defines the color scheme for + * the selector's field. + */ + public lateinit var fieldColors: TextFieldColors + /** * Indicates whether the drop-down menu is expanded or not. */ @@ -193,6 +201,9 @@ public abstract class DropdownSelector : InputComponent() { @Composable override fun content() { + if (!::fieldColors.isInitialized) { + fieldColors = TextFieldDefaults.colors() + } val fieldText = getFieldText(searchString) SideEffect { @@ -236,6 +247,7 @@ public abstract class DropdownSelector : InputComponent() { } }, textStyle = fieldTextStyle, + colors = fieldColors, modifier = modifier .focusRequester(this@DropdownSelector.focusRequester) .moveFocusOnTab() diff --git a/core/src/main/kotlin/io/spine/chords/core/InputComponent.kt b/core/src/main/kotlin/io/spine/chords/core/InputComponent.kt index 58abbc22..d0181aca 100644 --- a/core/src/main/kotlin/io/spine/chords/core/InputComponent.kt +++ b/core/src/main/kotlin/io/spine/chords/core/InputComponent.kt @@ -236,7 +236,7 @@ public abstract class InputComponent : FocusableComponent() { * implementation to ensure that the value specified in this property is * displayed as needed. */ - public open var externalValidationMessage: State? = null + public var externalValidationMessage: State? = null /** * A callback, which is invoked every time when a component transitions @@ -244,7 +244,7 @@ public abstract class InputComponent : FocusableComponent() { * an argument of `true`, when the new state is dirty, and `false` when it * becomes empty. */ - public open var onDirtyStateChange: ((Boolean) -> Unit)? = null + public var onDirtyStateChange: ((Boolean) -> Unit)? = null /** * A context that contains any data that affects input components that diff --git a/core/src/main/kotlin/io/spine/chords/core/InputField.kt b/core/src/main/kotlin/io/spine/chords/core/InputField.kt index 21e4e5ae..685a44b0 100644 --- a/core/src/main/kotlin/io/spine/chords/core/InputField.kt +++ b/core/src/main/kotlin/io/spine/chords/core/InputField.kt @@ -32,6 +32,8 @@ import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.Text import androidx.compose.material3.TextField +import androidx.compose.material3.TextFieldColors +import androidx.compose.material3.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.Stable @@ -50,6 +52,7 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TransformedText import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation.Companion.None +import io.spine.chords.core.InputReviser.Companion.maxLength import io.spine.chords.core.keyboard.KeyRange.Companion.Digit import io.spine.chords.core.keyboard.KeyRange.Companion.Whitespace import io.spine.chords.core.keyboard.matches @@ -306,6 +309,12 @@ public open class InputField : InputComponent() { */ public var textStyle: TextStyle? by mutableStateOf(null) + /** + * A [TextFieldColors] instance, which defines the color scheme for + * this field. + */ + public lateinit var colors: TextFieldColors + /** * An [InputReviser] that can be specified to modify the user's input before * it is applied to the input field. @@ -367,13 +376,13 @@ public open class InputField : InputComponent() { protected open var multiline: Boolean by mutableStateOf(false) /** - * Minimum number of visible lines + * Minimum number of visible lines of text * (applicable only if [multiline] == `true`). */ protected open var minLines: Int by mutableStateOf(1) /** - * Maximum number of visible lines + * Maximum number of visible lines of text * (applicable only if [multiline] == `true`). */ protected open var maxLines: Int by mutableStateOf(MAX_VALUE) @@ -443,6 +452,9 @@ public open class InputField : InputComponent() { @Composable override fun content(): Unit = recompositionWorkaround { + if (!::colors.isInitialized) { + colors = TextFieldDefaults.colors() + } val textStyle = textStyle ?: LocalTextStyle.current val rawTextContent = getRawTextContent() @@ -477,6 +489,7 @@ public open class InputField : InputComponent() { maxLines = if (multiline) maxLines else 1, enabled = enabled, textStyle = textStyle, + colors = colors, modifier = modifier(modifier) .focusRequester(focusRequester) .preventWidthAutogrowing() diff --git a/core/src/main/kotlin/io/spine/chords/core/appshell/MainScreen.kt b/core/src/main/kotlin/io/spine/chords/core/appshell/MainScreen.kt index 8f6ac1e8..db506a04 100644 --- a/core/src/main/kotlin/io/spine/chords/core/appshell/MainScreen.kt +++ b/core/src/main/kotlin/io/spine/chords/core/appshell/MainScreen.kt @@ -30,7 +30,6 @@ import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.navigator.Navigator -import io.spine.chords.runtime.safeCast /** * The main screen of the application. @@ -88,5 +87,5 @@ public class MainScreen( * Returns the currently selected view. */ internal val currentView: AppView - get() = viewNavigator.lastItem.safeCast() + get() = viewNavigator.lastItem as AppView } diff --git a/core/src/main/kotlin/io/spine/chords/core/layout/Wizard.kt b/core/src/main/kotlin/io/spine/chords/core/layout/Wizard.kt index 7e23f661..eeb249ac 100644 --- a/core/src/main/kotlin/io/spine/chords/core/layout/Wizard.kt +++ b/core/src/main/kotlin/io/spine/chords/core/layout/Wizard.kt @@ -207,7 +207,7 @@ public abstract class Wizard : Component() { onFinishClick = { handleFinishClick(currentPage) }, - onCancelClick = { onCloseRequest?.invoke() }, + onCancelClick = { close() }, isOnFirstPage = isOnFirstPage(), isOnLastPage = isOnLastPage(), submitting diff --git a/core/src/main/kotlin/io/spine/chords/core/primitive/StringField.kt b/core/src/main/kotlin/io/spine/chords/core/primitive/StringField.kt index d95d0941..893e5575 100644 --- a/core/src/main/kotlin/io/spine/chords/core/primitive/StringField.kt +++ b/core/src/main/kotlin/io/spine/chords/core/primitive/StringField.kt @@ -36,7 +36,7 @@ import io.spine.chords.core.InputReviser * An [InputField] implementation that allows entering `String` values. */ public class StringField : InputField() { - public companion object : ComponentSetup({ StringField() }) + public companion object : ComponentSetup() public override var inputReviser: InputReviser? get() = super.inputReviser diff --git a/dependencies.md b/dependencies.md index a1a24a9c..64836e57 100644 --- a/dependencies.md +++ b/dependencies.md @@ -1,6 +1,6 @@ -# Dependencies of `io.spine.chords:spine-chords-client:2.0.0-SNAPSHOT.80` +# Dependencies of `io.spine.chords:spine-chords-client:2.0.0-SNAPSHOT.81` ## Runtime 1. **Group** : cafe.adriel.voyager. **Name** : voyager-core. **Version** : 1.0.1.**No license information found** @@ -121,7 +121,7 @@ * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-macos-x64. **Version** : 1.5.12.**No license information found** +1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-windows-x64. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation-desktop. **Version** : 1.5.12. * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) @@ -244,7 +244,7 @@ * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-macos-x64. **Version** : 0.7.85.4. +1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-windows-x64. **Version** : 0.7.85.4. * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -774,7 +774,7 @@ * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-macos-x64. **Version** : 1.5.12.**No license information found** +1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-windows-x64. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation-desktop. **Version** : 1.5.12. * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) @@ -1020,7 +1020,7 @@ * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-macos-x64. **Version** : 0.7.85.4. +1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-windows-x64. **Version** : 0.7.85.4. * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -1094,12 +1094,12 @@ The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Apr 18 13:36:25 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Mon May 19 05:01:25 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.chords:spine-chords-codegen-tests:2.0.0-SNAPSHOT.80` +# Dependencies of `io.spine.chords:spine-chords-codegen-tests:2.0.0-SNAPSHOT.81` ## Runtime 1. **Group** : com.google.android. **Name** : annotations. **Version** : 4.1.1.4. @@ -1953,12 +1953,12 @@ This report was generated on **Fri Apr 18 13:36:25 EEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Mon May 19 05:01:27 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.chords:spine-chords-core:2.0.0-SNAPSHOT.80` +# Dependencies of `io.spine.chords:spine-chords-core:2.0.0-SNAPSHOT.81` ## Runtime 1. **Group** : cafe.adriel.voyager. **Name** : voyager-core. **Version** : 1.0.1. @@ -1989,14 +1989,6 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic * **Project URL:** [https://errorprone.info/error_prone_annotations](https://errorprone.info/error_prone_annotations) * **License:** [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : com.google.flogger. **Name** : flogger. **Version** : 0.7.4. - * **Project URL:** [https://github.com/google/flogger](https://github.com/google/flogger) - * **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - -1. **Group** : com.google.flogger. **Name** : flogger-system-backend. **Version** : 0.7.4. - * **Project URL:** [https://github.com/google/flogger](https://github.com/google/flogger) - * **License:** [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) - 1. **Group** : com.google.guava. **Name** : failureaccess. **Version** : 1.0.1. * **Project URL:** [https://github.com/google/guava/](https://github.com/google/guava/) * **License:** [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2021,11 +2013,6 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic 1. **Group** : com.google.protobuf. **Name** : protobuf-kotlin. **Version** : 3.22.3. * **License:** [BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause) -1. **Group** : org.checkerframework. **Name** : checker-compat-qual. **Version** : 2.5.3. - * **Project URL:** [https://checkerframework.org](https://checkerframework.org) - * **License:** [GNU General Public License, version 2 (GPL2), with the classpath exception](http://www.gnu.org/software/classpath/license.html) - * **License:** [The MIT License](http://opensource.org/licenses/MIT) - 1. **Group** : org.checkerframework. **Name** : checker-qual. **Version** : 3.40.0. * **Project URL:** [https://checkerframework.org/](https://checkerframework.org/) * **License:** [The MIT License](http://opensource.org/licenses/MIT) @@ -2049,7 +2036,7 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-macos-x64. **Version** : 1.5.12.**No license information found** +1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-windows-x64. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation-desktop. **Version** : 1.5.12. * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) @@ -2124,6 +2111,10 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 1.9.23. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 1.9.23. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2167,7 +2158,7 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-macos-x64. **Version** : 0.7.85.4. +1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-windows-x64. **Version** : 0.7.85.4. * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2672,7 +2663,7 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-macos-x64. **Version** : 1.5.12.**No license information found** +1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-windows-x64. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation-desktop. **Version** : 1.5.12. * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) @@ -2917,7 +2908,7 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-macos-x64. **Version** : 0.7.85.4. +1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-windows-x64. **Version** : 0.7.85.4. * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -2991,12 +2982,12 @@ This report was generated on **Fri Apr 18 13:36:27 EEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Mon May 19 05:01:30 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.chords:spine-chords-proto:2.0.0-SNAPSHOT.80` +# Dependencies of `io.spine.chords:spine-chords-proto:2.0.0-SNAPSHOT.81` ## Runtime 1. **Group** : cafe.adriel.voyager. **Name** : voyager-core. **Version** : 1.0.1.**No license information found** @@ -3085,7 +3076,7 @@ This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-Lic * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-macos-x64. **Version** : 1.5.12.**No license information found** +1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-windows-x64. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation-desktop. **Version** : 1.5.12. * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) @@ -3160,6 +3151,10 @@ This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-Lic * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) +1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-reflect. **Version** : 1.9.23. + * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) + * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) + 1. **Group** : org.jetbrains.kotlin. **Name** : kotlin-stdlib. **Version** : 1.9.23. * **Project URL:** [https://kotlinlang.org/](https://kotlinlang.org/) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3200,7 +3195,7 @@ This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-Lic * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-macos-x64. **Version** : 0.7.85.4. +1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-windows-x64. **Version** : 0.7.85.4. * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -3699,7 +3694,7 @@ This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-Lic * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) * **License:** [The Apache Software License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-macos-x64. **Version** : 1.5.12.**No license information found** +1. **Group** : org.jetbrains.compose.desktop. **Name** : desktop-jvm-windows-x64. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation. **Version** : 1.5.12.**No license information found** 1. **Group** : org.jetbrains.compose.foundation. **Name** : foundation-desktop. **Version** : 1.5.12. * **Project URL:** [https://github.com/JetBrains/compose-jb](https://github.com/JetBrains/compose-jb) @@ -3941,7 +3936,7 @@ This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-Lic * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) -1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-macos-x64. **Version** : 0.7.85.4. +1. **Group** : org.jetbrains.skiko. **Name** : skiko-awt-runtime-windows-x64. **Version** : 0.7.85.4. * **Project URL:** [https://www.github.com/JetBrains/skiko](https://www.github.com/JetBrains/skiko) * **License:** [The Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt) @@ -4015,12 +4010,12 @@ This report was generated on **Fri Apr 18 13:36:28 EEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Apr 18 13:36:29 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Mon May 19 05:01:33 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.chords:spine-chords-proto-values:2.0.0-SNAPSHOT.80` +# Dependencies of `io.spine.chords:spine-chords-proto-values:2.0.0-SNAPSHOT.81` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -4814,12 +4809,12 @@ This report was generated on **Fri Apr 18 13:36:29 EEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Apr 18 13:36:30 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). +This report was generated on **Mon May 19 05:01:35 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). -# Dependencies of `io.spine.chords:spine-chords-runtime:2.0.0-SNAPSHOT.80` +# Dependencies of `io.spine.chords:spine-chords-runtime:2.0.0-SNAPSHOT.81` ## Runtime 1. **Group** : com.google.code.findbugs. **Name** : jsr305. **Version** : 3.0.2. @@ -5583,4 +5578,4 @@ This report was generated on **Fri Apr 18 13:36:30 EEST 2025** using [Gradle-Lic The dependencies distributed under several licenses, are used according their commercial-use-friendly license. -This report was generated on **Fri Apr 18 13:36:31 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file +This report was generated on **Mon May 19 05:01:37 EEST 2025** using [Gradle-License-Report plugin](https://github.com/jk1/Gradle-License-Report) by Evgeny Naumenko, licensed under [Apache 2.0 License](https://github.com/jk1/Gradle-License-Report/blob/master/LICENSE). \ No newline at end of file diff --git a/pom.xml b/pom.xml index cb09ad34..7522c9e2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ all modules and does not describe the project structure per-subproject. --> io.spine.chords Chords -2.0.0-SNAPSHOT.80 +2.0.0-SNAPSHOT.81 2015 @@ -79,7 +79,7 @@ all modules and does not describe the project structure per-subproject. org.jetbrains.compose.desktop - desktop-jvm-macos-x64 + desktop-jvm-windows-x64 1.5.12 compile diff --git a/proto-values/src/main/kotlin/io/spine/chords/proto/value/money/MoneyExts.kt b/proto-values/src/main/kotlin/io/spine/chords/proto/value/money/MoneyExts.kt index ebcf96d0..98d789dc 100644 --- a/proto-values/src/main/kotlin/io/spine/chords/proto/value/money/MoneyExts.kt +++ b/proto-values/src/main/kotlin/io/spine/chords/proto/value/money/MoneyExts.kt @@ -40,6 +40,12 @@ import java.util.* import kotlin.math.abs import kotlin.reflect.KClass + +/** + * Gets a decimal separator character. + */ +public val decimalSeparator: Char get() = DecimalFormatSymbols.getInstance().decimalSeparator + /** * Represents the number of digits denoting nano (10^-9) units of the amount. */ @@ -127,16 +133,27 @@ public fun identifyCurrency(str: String): Currency? { } /** - * Gets a decimal separator character. + * Formats the [Money] value to a human-readable string that includes both the + * amount and ISO 4217 currency code. + * + * @receiver money instance that should be formatted. + * @see formatAmount */ -public val decimalSeparator: Char get() = DecimalFormatSymbols.getInstance().decimalSeparator +public fun Money.format(): String { + val amountText = formatAmount() + return "${currency.name} $amountText" +} /** - * Formats the [Money] value as a respective human-readable string - * without currency symbol. + * Formats the [Money] value as a respective human-readable string without + * mentioning a currency symbol or currency code. + * + * Use [format] if you need to format [Money] value as a string, which includes + * both an amount and a currency code. * * @receiver money instance that should be formatted. * @return a human-readable string representation of this [Money] value. + * @see format */ public fun Money.formatAmount(): String { val currencyOptions = currency.options diff --git a/proto/src/main/kotlin/io/spine/chords/proto/money/BankAccountField.kt b/proto/src/main/kotlin/io/spine/chords/proto/money/BankAccountField.kt index 4cd99634..35604c89 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/money/BankAccountField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/money/BankAccountField.kt @@ -35,7 +35,7 @@ import io.spine.chords.proto.value.money.BankAccount * A field that allows entering a bank account number. */ public class BankAccountField : InputField() { - public companion object : ComponentSetup({ BankAccountField() }) + public companion object : ComponentSetup() init { label = "Bank account" diff --git a/proto/src/main/kotlin/io/spine/chords/proto/money/MoneyField.kt b/proto/src/main/kotlin/io/spine/chords/proto/money/MoneyField.kt index b1f5e096..d2420269 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/money/MoneyField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/money/MoneyField.kt @@ -85,7 +85,7 @@ private val defaultCurrency = USD * A field that allows entering [Money] values. */ public class MoneyField : InputField() { - public companion object : ComponentSetup({ MoneyField() }) + public companion object : ComponentSetup() /** * A list of item values to choose from. diff --git a/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentCardNumberField.kt b/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentCardNumberField.kt index c3d2d968..cc2a450d 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentCardNumberField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentCardNumberField.kt @@ -65,9 +65,7 @@ private val PaymentCardNumberKt.maxValueLength get() = 19 * A field that allows entering a payment card number. */ public class PaymentCardNumberField : InputField() { - public companion object : ComponentSetup({ - PaymentCardNumberField() - }) + public companion object : ComponentSetup() init { label = "Card no" diff --git a/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentMethodEditor.kt b/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentMethodEditor.kt index afabd005..6a634508 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentMethodEditor.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/money/PaymentMethodEditor.kt @@ -52,7 +52,7 @@ import io.spine.chords.proto.value.money.PaymentMethodDef.paymentCard public class PaymentMethodEditor : CustomMessageForm( { PaymentMethod.newBuilder() } ) { - public companion object : ComponentSetup({ PaymentMethodEditor() }) + public companion object : ComponentSetup() /** * Identifies the component's appearance parameters. diff --git a/proto/src/main/kotlin/io/spine/chords/proto/net/EmailField.kt b/proto/src/main/kotlin/io/spine/chords/proto/net/EmailField.kt index d5a60de7..2d453d75 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/net/EmailField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/net/EmailField.kt @@ -40,7 +40,7 @@ private const val EmailRegex = """^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}${'$'}""" * An input field that allows editing a [EmailAddress] field. */ public class EmailField : InputField() { - public companion object : ComponentSetup({ EmailField() }) + public companion object : ComponentSetup() init { label = "Email" diff --git a/proto/src/main/kotlin/io/spine/chords/proto/net/InternetDomainField.kt b/proto/src/main/kotlin/io/spine/chords/proto/net/InternetDomainField.kt index a83f9eaf..74581304 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/net/InternetDomainField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/net/InternetDomainField.kt @@ -39,9 +39,7 @@ import io.spine.net.InternetDomains * A field that allows entering an [InternetDomain] value. */ public class InternetDomainField : InputField() { - public companion object : ComponentSetup( - { InternetDomainField() } - ) + public companion object : ComponentSetup() init { inputReviser = NonWhitespaces then ToLowerCase diff --git a/proto/src/main/kotlin/io/spine/chords/proto/net/IpAddressField.kt b/proto/src/main/kotlin/io/spine/chords/proto/net/IpAddressField.kt index 9907e1d7..c23356e7 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/net/IpAddressField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/net/IpAddressField.kt @@ -44,7 +44,7 @@ import io.spine.chords.proto.value.net.parse * A field for entering an IP address. */ public class IpAddressField : InputField() { - public companion object : ComponentSetup({ IpAddressField() }) + public companion object : ComponentSetup() init { label = "IP address" diff --git a/proto/src/main/kotlin/io/spine/chords/proto/net/UrlField.kt b/proto/src/main/kotlin/io/spine/chords/proto/net/UrlField.kt index 2a703708..8b7de5bb 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/net/UrlField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/net/UrlField.kt @@ -37,7 +37,7 @@ import io.spine.chords.proto.value.net.parse * A field that allows entering a URL. */ public class UrlField : InputField() { - public companion object : ComponentSetup({ UrlField() }) + public companion object : ComponentSetup() init { label = "URL" diff --git a/proto/src/main/kotlin/io/spine/chords/proto/people/PersonNameField.kt b/proto/src/main/kotlin/io/spine/chords/proto/people/PersonNameField.kt index a1253368..06da6711 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/people/PersonNameField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/people/PersonNameField.kt @@ -37,7 +37,7 @@ import io.spine.chords.proto.value.person.parse * A field that allows editing a [PersonName] value. */ public class PersonNameField : InputField() { - public companion object : ComponentSetup({ PersonNameField() }) + public companion object : ComponentSetup() init { label = "Person name" diff --git a/proto/src/main/kotlin/io/spine/chords/proto/time/DateTimeField.kt b/proto/src/main/kotlin/io/spine/chords/proto/time/DateTimeField.kt index ef2fb25f..8777db69 100644 --- a/proto/src/main/kotlin/io/spine/chords/proto/time/DateTimeField.kt +++ b/proto/src/main/kotlin/io/spine/chords/proto/time/DateTimeField.kt @@ -75,7 +75,7 @@ public typealias DateTimePattern = String * A field that allows specifying date and time. */ public class DateTimeField : InputField() { - public companion object : ComponentSetup({ DateTimeField() }) + public companion object : ComponentSetup() /** * A pattern for parsing and formatting a date component (as used with diff --git a/version.gradle.kts b/version.gradle.kts index cce59e16..84c69ec7 100644 --- a/version.gradle.kts +++ b/version.gradle.kts @@ -27,4 +27,4 @@ /** * The version of all Chords libraries. */ -val chordsVersion: String by extra("2.0.0-SNAPSHOT.80") +val chordsVersion: String by extra("2.0.0-SNAPSHOT.81")