LCE
Data type library that describes loading, content and error states. To better understand the concept, read the following blog post.
Type | Loading | Content | Error |
---|---|---|---|
LCE<L, C, E> |
Loading | Content | Error |
UCE<C, E> |
Unit | Content | Error |
UCT<C> |
Unit | Content | Throwable |
CE<C, E> |
- | Content | Error |
CT<C> |
- | Content | Throwable |
LC<L, C> |
Loading | Content | - |
UC<C> |
Unit | Content | - |
Types
LCE<L, C, E>
is the most flexible type which stands for Loading / Content / Error. It allows you to specify the generic parameter for each state.
val loading = LCE.loading("We are loading")
val content = LCE.content("Hello world")
val error = LCE.error(RuntimeException("boo"))
When we don't need a value for loading state, we can use UCE<C, E>
type which stands for Unit / Content / Error.
val loading = UCE.loading()
val content = UCE.content("Hello world")
val error = UCE.error("Something went wrong.")
When we use Throwable
for errors, we can use UCT<C>
which stands for Unit / Content / Throwable.
val loading = UCT.loading()
val content = UCT.content("Hello world")
val error = UCT.error(RuntimeException("boo"))
When we only care about content and error states, we can use CE<C, E>
type which stands for Content / Error.
val content = CE.content("Hello world")
val error = CE.error("My custom error message")
When we use Throwable
for errors, we can use CT<C>
type which stands for Content / Throwable.
val content = CT.content("Hello world")
val error = CT.error(RuntimeException("boo"))
When we only care about loading and content states, we can use UC<C>
which stands for Unit / Content.
val loading = UC.loading()
val content = UC.content("Hello world")
Fold
Each type has a fold extension method which allows us to unwrap the data type and handle all of the cases.
For example, this is useful when we want to update the UI based on the current state.
fun render(event: UCT<MyData>) {
event.fold(
onLoading = { view.showLoading() },
onError = { exception -> view.showError(exception) },
onContent = { data -> view.showData(data) }
)
}
This is also useful when we want to map to another type.
fun toMessage(event: CT<String>): String {
return event.fold(
onContent = { message -> message },
onError = { error -> "Something went wrong" }
)
}
Map Content
You can map from one content type to another. You can also use this to transform the content
LCE.content("Hello").mapContent {
"$it World!"
}
LCE.content(0).mapContent { it + 1 }
Map Error
val lce = LCE.error("failure").mapError { message -> RuntimeException(message) }
Type Interop
You can easily convert from one data type to another without incurring any memory allocation.
val uct = LCE.content("Hello World").asUCT()
val lce = uct.asLCE()
// When we go from LCE to CT/CE type, we treat loading state as null
val ct: CT<String>? = lce.asCT()
RxJava 3 Support
Converting a Single<T>
operation into Observable<UCT<T>>
fun fetchData(): Observable<UCT<MyData>> {
return Single.fromCallable { MyData() }.toUCT()
}
You'll need to add the lce-rxjava3
dependency to access these features.
Testing
Use lce-test
artifact in your tests to simplify making assertions on the LCE
types.
@Test fun `my test`() {
val event: LCE<String, String, Throwable> = ...
// Loading assertions
event.assertLoading()
event.assertLoading("loading value")
// Content assertions
event.assertContent()
event.assertContent("content value")
// Error assertions
event.assertError()
event.assertError(throwable)
}
Download
Add the library to your list of dependencies:
dependencies {
implementation("com.laimiux.lce:lce:0.3.1")
implementation("com.laimiux.lce:lce-rxjava3:0.3.1")
implementation("com.laimiux.lce:lce-test:0.3.1")
}
Development
To run tests
./gradlew :lce:test
./gradlew :lce-rxjava3:test
License
Copyright 2021 Laimonas Turauskas
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.