Quitte provides specialized observable properties and expressions with lazy variants, and observable collections.
Quitte is compatible with Java 17 or later.
The core module provides the basic set of observable building blocks.
Properties are mutable wrappers for values which support listening for changes. Simple properties are the most basic kind of observable. They are simple wrappers for values with set- and get-access.
Lazy properties provide setter overloads to support lazy updates of their
values. When, for example, LazyIntProperty#set(IntSupplier)
is used, the
properties value is not updated. Instead, the property is marked as invalid and
only invalidation listeners are notified. The new value is only computed when
the property's value is queried.
Tip: While properties are fundamentally mutable, it is generally recommended using read-only views of properties to reduce the risk of unwanted modifications. (See
ReadableProperty#asReadOnlyProperty()
)
Expressions are observables which are derived from one or more observables using some processing step. They do not have a mutable value, but instead yield the value of the calculation they represent. Similar to properties, expressions come in two flavours:
- Simple expressions which recompute their result eagerly when the value of an input is changed, and
- Lazy expressions which avoid recomputing until their result is queried.
In addition to single-value observables, Quitte also supports observable collections. To support a variety of collection implementations, Quitte's observable collections are wrappers that delegate to a concrete implementation.
List<String> strings = new ArrayList<>();
ObservableList<String> observableStrings = ObservableList.of(strings);
observableStrings.addChangeListener(change -> System.out.println("The content of observableStrings has been changed."));
observableStrings.add("foo");
/*
* WARNING: The call below does not notify the listeners since it accesses the
* list implementation directly. To avoid running into issues, holding a
* reference to the collection implementation is discouraged. Instead, use:
*
* ObservableList<String> observableStrings = ObservableList.of(new ArrayList());
*/
strings.add("bar");
The quitte-i18n
module provides a basic API for using Quitte observables for
localization.
Tip: Billi provides complete localization and pluralization support on top of Quitte.
The quitte-compose
module provides extensions for better interoperability with
Jetpack Compose.
interface MyModel {
val text: ObservableObjectValue<String>
}
@Composable
fun MyComposable(model: MyModel) {
val text by textFlow.observeAsState()
Text(text)
}
Note: The
quitte-compose
module targets Java 17 bytecode and is currently only supported for Compose for Desktop.
The quitte-kotlinx-coroutines
module provides extensions for better
interoperability with kotlinx.coroutines.
Simply convert observables to flows using any of the built-in conversion
functions. Flow conversions are available for ObservableValue
,
ObservableList
, ObservableMap
, and ObservableSet
.
This project uses Gradle's toolchain support to detect and select the JDKs required to run the build. Please refer to the build scripts to find out which toolchains are requested.
An installed JDK 1.8 (or later) is required to use Gradle.
Once the setup is complete, invoke the respective Gradle tasks using the following command on Unix/macOS:
./gradlew <tasks>
or the following command on Windows:
gradlew <tasks>
Important Gradle tasks to remember are:
clean
- clean build resultsbuild
- assemble and test the Java librarygenerate
- generates all code from the templates (see the "Editing" section below for details)publishToMavenLocal
- build and install all public artifacts to the local maven repository
Additionally tasks
may be used to print a list of all available tasks.
To reduce the amount duplication when generating specialized types, Quitte uses
a simple code-generation mechanism. The templates are simple Gradle Kotlin DSL
scripts which are located under src/{module}/{site}-templates
and discovered
automatically.
The generated code is published to the repository to make it easier to follow changes using the git history.
Quitte is available under the terms of the 3-Clause BSD license.
Copyright (c) 2018-2023 Leon Linhart,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.