Skip to content

Commit

Permalink
Merge pull request #34 from icerockdev/develop
Browse files Browse the repository at this point in the history
Release 0.5.0
  • Loading branch information
Alex009 authored Mar 6, 2020
2 parents 22b50b8 + 801d238 commit 979f32b
Show file tree
Hide file tree
Showing 38 changed files with 690 additions and 360 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ This is a Kotlin Multiplatform library that provides architecture components of
- 0.3.1
- kotlin 1.3.61
- 0.4.0
- 0.5.0

## Installation
root build.gradle
Expand All @@ -48,7 +49,8 @@ allprojects {
project build.gradle
```groovy
dependencies {
commonMainApi("dev.icerock.moko:mvvm:0.4.0")
commonMainApi("dev.icerock.moko:mvvm:0.5.0")
androidMainImplementation("androidx.lifecycle:lifecycle-extensions:2.0.0")
}
```

Expand All @@ -59,7 +61,7 @@ enableFeaturePreview("GRADLE_METADATA")

On iOS, in addition to the Kotlin library add in Podfile
```ruby
pod 'MultiPlatformLibraryMvvm', :git => 'https://github.com/icerockdev/moko-mvvm.git', :tag => 'release/0.4.0'
pod 'MultiPlatformLibraryMvvm', :git => 'https://github.com/icerockdev/moko-mvvm.git', :tag => 'release/0.5.0'
```
**`MultiPlatformLibraryMvvm` CocoaPod requires that the framework compiled from Kotlin be named
`MultiPlatformLibrary` and be connected as a CocoaPod `MultiPlatformLibrary`.
Expand Down Expand Up @@ -153,8 +155,8 @@ class SimpleViewController: UIViewController {
viewModel.onCounterButtonPressed()
}

deinit {
viewModel.onCleared()
override func didMove(toParentViewController parent: UIViewController?) {
if(parent == nil) { viewModel.onCleared() }
}
}
```
Expand Down Expand Up @@ -265,8 +267,8 @@ class EventsViewController: UIViewController {
viewModel.onButtonPressed()
}

deinit {
viewModel.onCleared()
override func didMove(toParentViewController parent: UIViewController?) {
if(parent == nil) { viewModel.onCleared() }
}
}

Expand Down Expand Up @@ -462,8 +464,8 @@ class LoginViewController: UIViewController {
viewModel.onLoginButtonPressed()
}

deinit {
viewModel.onCleared()
override func didMove(toParentViewController parent: UIViewController?) {
if(parent == nil) { viewModel.onCleared() }
}
}

Expand All @@ -484,7 +486,7 @@ Please see more examples in the [sample directory](sample).
## Set Up Locally
- The [mvvm directory](mvvm) contains the `mvvm` library;
- In [sample directory](sample) contains sample apps for Android and iOS; plus the mpp-library connected to the apps;
- For local testing use the `:mvvm:publishToMavenLocal` gradle task - so that sample apps use the locally published version.
- For local testing use the `./publishToMavenLocal.sh` script - so that sample apps use the locally published version.

## Contributing
All development (both new features and bug fixes) is performed in the `develop` branch. This way `master` always contains the sources of the most recently released version. Please send PRs with bug fixes to the `develop` branch. Documentation fixes in the markdown files are an exception to this rule. They are updated directly in `master`.
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ object Versions {
object MultiPlatform {
const val coroutines = "1.3.3"
const val mokoResources: String = "0.6.0"
const val mokoMvvm: String = "0.4.0"
const val mokoMvvm: String = "0.5.0"
}
}
}
11 changes: 11 additions & 0 deletions mvvm/src/androidMain/kotlin/dev/icerock/moko/mvvm/UI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

actual val Dispatchers.UI: CoroutineDispatcher
get() = Dispatchers.Main
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,18 @@ import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import java.util.concurrent.Executor

actual class EventsDispatcher<ListenerType : Any>(private val executor: Executor) {
actual class EventsDispatcher<ListenerType : Any> {
private var eventsListener: ListenerType? = null
private val blocks = mutableListOf<ListenerType.() -> Unit>()
private val executor: Executor

internal val blocks = mutableListOf<ListenerType.() -> Unit>()
actual constructor() {
this.executor = createExecutorOnMainLooper()
}

constructor(executor: Executor) {
this.executor = executor
}

fun bind(lifecycleOwner: LifecycleOwner, listener: ListenerType) {
val observer = object : LifecycleObserver {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ import android.os.Handler
import android.os.Looper
import java.util.concurrent.Executor

inline fun <reified T : Any> eventsDispatcherOnMain(): EventsDispatcher<T> {
fun createExecutorOnMainLooper(): Executor {
val mainLooper = Looper.getMainLooper()
val mainHandler = Handler(mainLooper)
val mainExecutor = Executor { mainHandler.post(it) }
return EventsDispatcher(mainExecutor)
}
return Executor { mainHandler.post(it) }
}

inline fun <reified T : Any> eventsDispatcherOnMain(): EventsDispatcher<T> {
return EventsDispatcher(createExecutorOnMainLooper())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm.utils

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.Observer
import dev.icerock.moko.mvvm.livedata.LiveData

fun <T> LiveData<T>.bind(lifecycleOwner: LifecycleOwner, observer: (T?) -> Unit) {
observer(value)

this.ld().observe(lifecycleOwner, Observer { value ->
observer(value)
})
}

fun <T> LiveData<T>.bindNotNull(lifecycleOwner: LifecycleOwner, observer: (T) -> Unit) {
bind(lifecycleOwner) { value ->
if (value == null) return@bind

observer(value)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
package dev.icerock.moko.mvvm.viewmodel

import androidx.lifecycle.ViewModel
import dev.icerock.moko.mvvm.UI
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel

actual open class ViewModel actual constructor() : ViewModel() {
// for now dispatcher fixed on Main. after implementing multithread coroutines on native - we can change it
protected actual val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.Main)
protected actual val viewModelScope: CoroutineScope = CoroutineScope(Dispatchers.UI)

public actual override fun onCleared() {
super.onCleared()
Expand Down
10 changes: 10 additions & 0 deletions mvvm/src/commonMain/kotlin/dev/icerock/moko/mvvm/UI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm

import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

expect val Dispatchers.UI: CoroutineDispatcher
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

package dev.icerock.moko.mvvm.dispatcher

expect class EventsDispatcher<ListenerType : Any> {
expect class EventsDispatcher<ListenerType : Any>() {
fun dispatchEvent(block: ListenerType.() -> Unit)
}
12 changes: 12 additions & 0 deletions mvvm/src/iosMain/kotlin/dev/icerock/moko/mvvm/UI.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm

import dev.icerock.moko.mvvm.viewmodel.UIDispatcher
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers

actual val Dispatchers.UI: CoroutineDispatcher
get() = UIDispatcher()
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm.binding

import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.mvvm.livedata.map
import dev.icerock.moko.resources.desc.StringDesc
import platform.UIKit.UIButton
import platform.UIKit.UIColor
import platform.UIKit.UIControlStateNormal
import platform.UIKit.UIImage
import platform.UIKit.backgroundColor
import dev.icerock.moko.mvvm.utils.bind

fun UIButton.bindEnabled(
liveData: LiveData<Boolean>,
enabledColor: UIColor? = null,
disabledColor: UIColor? = null
) {
liveData.bind(this) { value ->
this.enabled = value

val color = when (value) {
true -> enabledColor
false -> disabledColor
}

color?.also { backgroundColor = it }
}
}

fun UIButton.bindTitle(
liveData: LiveData<String>
) {
liveData.bind(this) { value ->
setTitle(value, forState = UIControlStateNormal)
}
}

fun UIButton.bindTitle(
liveData: LiveData<StringDesc>
) {
bindTitle(liveData.map { it.localized() })
}

fun UIButton.bindImages(
liveData: LiveData<Boolean>,
trueImage: UIImage,
falseImage: UIImage
) {
liveData.bind(this) { value ->
val image = when (value) {
true -> trueImage
false -> falseImage
}
setImage(image, forState = UIControlStateNormal)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm.binding

import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.mvvm.livedata.map
import dev.icerock.moko.resources.desc.StringDesc
import platform.UIKit.UILabel
import dev.icerock.moko.mvvm.utils.bind

fun UILabel.bindText(
liveData: LiveData<String>,
formatter: ((String) -> String) = { it }
) {
liveData.bind(this) { value ->
val newText = formatter(value)

if (newText == text) return@bind

text = newText
}
}

fun UILabel.bindText(
liveData: LiveData<StringDesc>,
formatter: ((String) -> String) = { it }
) {
bindText(
liveData = liveData.map { it.localized() },
formatter = formatter
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2020 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.mvvm.binding

import dev.icerock.moko.mvvm.livedata.LiveData
import dev.icerock.moko.mvvm.livedata.MutableLiveData
import platform.UIKit.UIControlEventValueChanged
import platform.UIKit.UISwitch
import dev.icerock.moko.mvvm.utils.bind
import dev.icerock.moko.mvvm.utils.setEventHandler

fun UISwitch.bindValue(liveData: LiveData<Boolean>) {
liveData.bind(this) { value ->
on = value
}
}

fun UISwitch.bindValueTwoWay(liveData: MutableLiveData<Boolean>) {
bindValue(liveData)
setEventHandler(UIControlEventValueChanged) {
if (liveData.value == on) return@setEventHandler

liveData.value = on
}
}
Loading

0 comments on commit 979f32b

Please sign in to comment.