- ✨ The
SingleLiveEvent
(A lifecycle-aware observable that sends only new updates after subscription, used for events like navigation and Snackbar messages.) is back :) - New extension function
ViewGroup.inflate
to allows call like:viewGroup.inflate(R.layout.exchange_rates_view)
- The
Espresso
has been removed from Kaal (not used)
- ✨ #5: You can define Fragment or Activity
layout id
by using a constructorclass MainActivity : BaseActivity(R.layout.activity_main) // Fragment class MyFragment: BaseFragment(R.layout.fragment_my)
- Koin updated to v1.3.61
- Koin updated to v2.0.1
- Gradle 5.6.4
API Break:
TheScopeAware
has been removed. Since Koin 2.0.1 you should use official Scope API by Koin.
Api Break:
cz.eman.kaal.domain.Result
and subclasses has been moved intocz.eman.kaal.domain.result.Result
. This a newResult
has a new functionality to remove boilerplate code. Also all classes which are usingResult
has been changed- Dependencies update:
- Kotlin 1.3.50
- Kotlin Coroutines 1.3.2
- Espresso 3.0.2
- Added a new function
fun <Dto, T> callResult(responseCall: suspend () -> Response<Dto>, errorMessage: String? = null, map: (Dto) -> T): Result<T>
to remove a boilerplate code when you're calling a server by using a retrofit.
Old usage with callSafe
override suspend fun getPopularMovies() = callSafe(
call = { fetchPopularMovies() },
errorMessage = "Cannot fetch popular movies"
)
and old way to call remote API
private suspend fun fetchPopularMovies(): Result<List<Movie>> {
val response = movieApiService.getPopularMovies().awaitResponse()
return if (response.isSuccessful) {
val body = response.body()
if (body != null) {
Result.Success(data = MoviesMapper.mapWrapperToMovie(body))
} else {
Result.Error(
ApiErrorResult(
code = response.code(),
errorMessage = response.message(),
apiThrowable = EmptyBodyException()
)
)
}
} else {
val errorResult =
ApiErrorResult(code = response.code(), errorMessage = response.message())
logError { "Cannot fetch popular movies[$errorResult]" }
Result.Error(errorResult)
}
}
By using callResult
you will remove boilerplate code above
override suspend fun getPopularMovies() = callResult(
responseCall = { movieApiService.getPopularMovies()}
) {
MoviesMapper.mapWrapperToMovie(it)
}
You can also define your custom error message by a defining an attribute errorMessage
:
override suspend fun getPopularMovies() = callResult(
responseCall = { movieApiService.getPopularMovies()},
errorMessage = "Cannot get a popular movies!"
) {
MoviesMapper.mapWrapperToMovie(it)
}
- A new way how to create the
Result.Error
. There is a couple of standard functions but if you want to createErrorResult
without that you will define your ownMyCustomErrorResult
you can use this approach
Result.error(
errorCode = MovieErrorCode.INVALID_USER_CREDENTIALS,
message = "Invalid username or password"
)
which is similar to code below
Result.Error(
ErrorResult(
code = MovieErrorCode.INVALID_USER_CREDENTIALS,
message = "Invalid username or password"
)
)
- New
HttpStatusErrorCode
which define all HTTP error codes. You can use it by your own. In case of that you are usingcallSafe
orcallResult
- response will be parsed automatically for you with these error codes
- Added view extension functions (
hide(), show(), invisible(), hideKeyboard()
- Added a new view ext. function
TextView.textWatcher
. Byt this use can avoid to using a boilerplate code when you need to be notified if text has been changed or before change action and so on - Added
CalendarExtensions
functions to avoid boilerplate code when you are working with theCalendar
core
: Addedexhaustive
helper to force a when statement to assert all options are matched in a when statement.
when(sealedObject) {
is OneType -> //
is AnotherType -> //
}.exhaustive
- News in the
cz.eman.kaal.domain.Result
:- New function
getOrNull()
which return data in case of that are available (from remote call or local call) , otherwise null is returned. and server request.
- New function
- Introducing a Fragment's Arguments:
- You can use this feature to easily create and handle a fragments arguments
class PropertyDelegateFragment : Fragment() { private var userName by argument<String>() private var email by argument<String>() private var booksCount by argument<Int>() companion object { fun create(userName: String, email: String, booksCount: Int = 0) = PropertyDelegateFragment().apply { this.userName = userName this.email = email this.booksCount = booksCount } } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_arguments_demo, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) nameTextView.text = userName emailTextView.text = email booksCountTextView.text = booksCount.toString() addBookButton.setOnClickListener { booksCount++ booksCountTextView.text = booksCount.toString() } }
} ```
- The
Result.Error
has now output a generic parameterT
- Kotlin
1.3.40
- Coroutines scope in a base classes
- Initial version