
/ Original /
A sintaxe da linguagem Kotlin é uma coisa bastante flexível e a concisão do código, que em Java pode ser alcançado apenas com a ajuda da geração de código, o Kotlin é frequentemente implementado usando ferramentas de linguagem padrão ( uma , duas ).
, Kotlin ( ), MVP- Summer Kotlin Multiplatform.
MVP ?
Android, Fragment Activity . , , , view view . , . MVP- , view . , , view, . 
APT?
- Moxy
- @InjectViewStateFragment
- , , . Moxy .
e: <...>/kapt3/stubs/debug/adev/TestFragment.java:16: error: cannot find symbol
    public TestPresenterFactory presenterFactory;
           ^
  symbol:   class TestPresenterFactory
  location: class TestFragment
e: <...>/kapt3/stubs/debug/adev/ui/TestFragment.java:22:
error: [ComponentProcessor:MiscError] dagger.internal.codegen.ComponentProcessor was unable to process this class because not all of its dependencies could be resolved. Check for compilation errors or a circular dependency with generated code.
public final class TestFragment extends adev.ui.BaseFragment implements adev.presentation.TestView {
             ^

, , Dagger , . 4 , , . , .
Fragment . . Clean Project , , .

. — AutoFactory, , .
Dagger. , , . , . APT .
APT Kotlin/MultiplatformKotlin/Multiplatform API . Annotation Processing . API .
 ?
Android-only APT. Koin/Kodein Dagger, FragmentArgs. Moxy . , Google MVVM, - , , . , , .
Kotlin/JS 2017 . property- VueJS , . : " Fragment/Activity?" . :
interface View {
    var counter: Int
}
class Presenter : BasePresenter<View>() {
    override fun createViewProxy(view: View) = object : View {
        override var counter by state(view::counter, initial = 0)
    }
    override fun onEnter() {
        viewProxy.counter = 1
    }
}
view viewProxy, view. view property delegate, state. view view . , , view , . Map. view createViewProxy state Map .
:
- createViewProxy- viewProxy. . , BottomSheet .
- , view.
. "".
№1.
, viewProxy view. , , . viewProxy view , , state, view c .
:
interface View {
    var counter: Int
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override var counter by state({ ::counter }, initial = 0)
    }
    override fun onCreate() {
        viewProxy.counter = 1
    }
}
abstract class BasePresenter<TView> {
    fun <T> state(
        rule: TView.() -> KMutableProperty0<T>
    ): StateDelegate<T> {}
}
Kotlin : obj::prop. :
class A {
    var b = 1
    val prop = ::b
}
: ", , this receiver- !".
class A {
    var b = 1
}
fun A.foo() {
    val prop = ::b
}
. ! !
:
interface View {
    var counter: Int?
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override var counter by state({ ::counter }, initial = null)
    }
}
...
e: <...>/adev/presentation/Presenter.kt: (7, 22): Type of 'counter' doesn't match the type of the overridden var-property 'public abstract var counter: Int? defined in adev.presentation.View'

, Android Studio . . ? , frontend Kotlin, , viewProxy, , IDE, , , this , state. , counter ::counter, this::counter, .
view : this .
abstract class BasePresenter<TView> {
    fun <T> state(
        rule: (TView) -> KMutableProperty0<T>
    ): StateDelegate<T> {}
}
:
interface View {
    var counter: Int?
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override var counter by state({ it::counter }, initial = null)
    }
}
. . , view . , viewProxy Intellij IDEA/Android Studio.
: ?
:
. . .object View {
    interface State {
        var counter: Int
    }
    interface Methods {
        fun showMessage(message: String)
    }
}
class Presenter : BasePresenter<View.State, View.Methods>() {
    override val viewStateProxy = object : View.State {
        override var counter by state({ it::counter }, initial = 0)
    }
    override fun onEnter() {
        viewStateProxy.counter = 1
        viewMethods?.showMessage("Hello!")
    }
}
 , viewMethods . , . :
. . .object View {
    interface State {
        var counter: Int
    }
    interface Methods {
        fun showMessage(message: String)
    }
}
interface Router {
    fun toNext()
}
class Presenter : BasePresenter<View.State, View.Methods, Router>() {
    override val viewStateProxy = object : View.State {
        override var counter by state({ it::counter }, initial = 0)
    }
    override fun onEnter() {
        viewStateProxy.counter = 1
        viewMethods?.showMessage("Hello!")
        router.toNext()
    }
}
 , , . , , . - . : Dagger, Retrofit Moxy.
Moxy . , view.
AddToEndSingleStrategy view.
OneExecutionStrategy , , view .
SkipStrategy .
AddToEndSingleStrategy Summer state. .
, Kotlin , , .
interface View {
    var counter: Int?
    fun showMessage()
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override var counter by state({ it::counter }, initial = null)
        override fun showMessage = event { it::showMessage }
    }
}
abstract class BasePresenter<TView> {
    fun event(
        getAction: (TView) -> (() -> Unit)
    ) = Event(getAction)
}
class Event<TView>(
    getAction: (TView) -> (() -> Unit)
) : () -> Unit
. :
interface View {
    var counter: Int?
}
interface Events {
    fun showMessage(message: String)
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override var counter by state({ it::counter }, initial = null)
    }
    val showMessage = event { it::showMessage }
}
, View . , , .
?
- -, — .
- . -, .
- .
– . - , . , , , . , . Kotlin , - . . , , , . , .
- . ?
Kotlin:
override fun showMessage(message: String) {
    Toast.makeText(requireContext(), "message", Toast.LENGTH_LONG).show()
}
Kotlin:
override val showMessage = { message: String ->
    Toast.makeText(requireContext(), "message", Toast.LENGTH_LONG).show()
}
Swift:
fun showMessage(message: String) {
    printMessage(message)
}
Swift:
lazy var showMessage: (String) -> Void = { message in
    self.printMessage(message)
}
(つ✧ω✧)つ
override val showMessage = { message: String -> Unit in
    printMessage(message)
}
- . , . 5-6 , , .
№2.
view, . :
interface View {
    val showMessage: () -> Unit
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override val showMessage = doOnlyWhenAttached { it.showMessage }
    }
}
abstract class BasePresenter<TView> {
    fun doOnlyWhenAttached(
        getAction: (TView) -> (() -> Unit)
    ) = Event(getAction)
}
class Event<TView>(
    action: (TView) -> (() -> Unit)
) : () -> Unit
. , Kotlin . vararg, . view.
interface View {
    val showMessage: (message: String) -> Unit
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override val showMessage = doOnlyWhenAttached { it.showMessage }
    }
}
abstract class BasePresenter<TView> {
    fun doOnlyWhenAttached(
        getAction: (TView) -> (() -> Unit)
    ) = Event0(getAction)
    fun <T1> doOnlyWhenAttached(
        getAction: (TView) -> ((T1) -> Unit)
    ) = Event1(getAction)
}
class Event0<TView>(
    action: (TView) -> (() -> Unit)
) : () -> Unit
class Event1<TView, T1>(
    action: (TView) -> ((T1) -> Unit)
) : (T1) -> Unit
e: <...>/adev/presentation/View.kt: (10, 22): Type of 'showMessage' is not a subtype of the overridden property 'public abstract val showMessage: (message: String) -> Unit defined in adev.presentation.View'

Kotlin , . , Kotlin , . doOnlyWhenAttached TView , T1. , .
"" – Event 2 :
- TView
- Event
interface View {
    val showMessage: (message: String) -> Unit
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override val showMessage = event { it.showMessage }.doOnlyWhenAttached()
    }
}
abstract class BasePresenter<TView> {
    fun <TAction> event(getAction: (TView) -> TAction) = EventBuilder(getAction)
    fun EventBuilder<TView, () -> Unit>.doOnlyWhenAttached() {
        return Event0(this.getAction)
    }
    fun <T1> EventBuilder<TView, (T1) -> Unit>.doOnlyWhenAttached() {
        return Event1(this.getAction)
    }
}
inline class EventBuilder<TView, TAction>(
    val getAction: (TView) -> TAction
)
class Event0<TView>(
    action: (TView) -> (() -> Unit)
) : () -> Unit
class Event1<TView, T1>(
    action: (TView) -> ((T1) -> Unit)
) : (T1) -> Unit
. shorthands . :
interface View {
    val showMessage: (message: String) -> Unit
    val showMessage1: (message: String) -> Unit
    val showMessage2: (message: String) -> Unit
}
class Presenter : BasePresenter<View>() {
    override val viewProxy = object : View {
        override val showMessage = event { it.showMessage }.build(RepeatLastStrategy())
        override val showMessage1 = event { it.showMessage1 }.doOnlyWhenAttached()
        override val showMessage2 = event { it.showMessage2 }.doExactlyOnce()
    }
}
, !
. , 30. , , production. 2- . , , !
Summer 5 production . 2 – . MaksimNovikov, metnyov deks1309 , . XanderZhu umpteenthdev mowenik iOS .
, Summer, . :
android.widget.View, UIView . , - . , . , .
interface View {}
class Presenter : SummerPresenter<View> {
    override val viewProxy = object : View {}
    val subPresenter = SubPresenter(
        onAction = { doSomething() }
    )
}
class Fragment : SummerFragment(R.layout.fragment), View {
    private val presenter by bindPresenter { Presenter() }
    private lateinit var popup: Popup
    override fun onViewCreated(...) {
        super.onViewCreated(...)
        popup = Popup(presenter.subPresenter)
    }
}
interface SubView {
    var counter: Int
}
class SubPresenter(
    private val onAction: () -> Unit
): SummerPresenter<SubView>() {
    override val viewProxy = object : SubView {
        override var counter by state({ it::counter }, initial = 0)
    }
}
class Popup(
    private val presenter: SubPresenter
) : <...>, SubView {
    init {
        bindPresenter { presenter }
    }
}
- VueJS ReactJS.
sealed State
AddToEndSingleTagStrategy Moxy, Summer state sealed .
sealed class ViewState {
    object Loading : ViewState()
    class Content(val counter) : ViewState()
}
interface View {
    var state: ViewState
}
class Presenter : SummerPresenter<View>() {
    override val viewProxy = object : View {
        override var state by state({ it::state }, initial = ViewState.Loading)
    }
}
MaksimNovikov .
didSet in Kotlin
Kotlin set . didSet didSetNotNull, didSet Swift. 
:
data class Item(val id: Int, val count: Int)
interface View {
    var items: List<Item>
}
class Presenter : SummerPresenter<View>() {
    override val viewProxy = object : View {
        override var items by state({ it::items }, initial = emptyList())
    }
    fun increment(id: Int) {
        viewProxy.items = viewProxy.items.map { item ->
            if (item.id == id)
                item.copy(count = item.count + 1)
            else
                item
        }
    }
}
, view, . , state, store view .
Summer Kotlin/Multiplatform :
Kotlin/Multiplatform . iOS-, , , . , , . iOS 0. , .
Summer iOS-. XCode. Swift. Kotlin XCode TouchLab. , , iOS-. VIPER, Clean Swift .. MVP.
, Kotlin. Summer , unsafe casts , Kotlin . , , — iOS Swift view. .
, , APT, Summer, .
, viewProxy boilerplate.
interface View {
    var counter: Int
}
class Presenter : SummerPresenter<View>() {
    override val viewProxy = object : View {
        override var state by state({ it::counter }, initial = 0)
    }
}
{ it::counter } . , . , - . , lint .
viewstate , , Swift. Kotlin didSet didSetNotNull view. Swift view . , , . nil. — , , .
, , state initial , state, event RepeatLastStrategy init .
 , Moxy Summer Summer Moxy . 15-20 . iOS Android- Summer 3-4 . , VIPER. ViewController-, iOS- . , Kotlin. iOS, , .
Você também pode traduzir 1-2 telas para tentar. Kotlin tem uma boa interoperabilidade com o Swift, e o Swift não importa em qual idioma o código está escrito. As aulas escritas em Kotlin olham para Swift como se tivessem sido escritas no Objective-C com anotações de compatibilidade colocadas nos lugares certos.
Conclusão
Obrigado a todos que leram até o fim! Espero que você tenha aprendido algo novo sobre Kotlin por si mesmo e talvez até tente Summer . Ficaria muito grato pelo feedback construtivo.