Kotlin Multiplatform Router for Android and iOS

Overview

Kompass

A powerful Kotlin Multiplatform Router for Android and iOS


GitHub top language Build Status Bintray GitHub last commit Gitter

Support

I am happy to help you with any problem on gitter
Feel free to open any new issue!

What Kompass can do for you

  • Perfect fit for MVVM, MVI, MVP, MVX architectures
  • Powerful routing concept that targets multiple platforms like Android, JVM & iOS
  • Easy to use API's
  • Highly configurable implementations

Android

  • Flexible routing with fragments
  • Built in solution for passing arguments to fragments
  • Very easy support for transitions/animations
  • No XML configuration
  • Built in DSL to configure the FragmentRouter
  • Survives configuration changes
  • Can restore the "routing stack" after process death

What Kompass can't do for now

While the core module is currently built and published for multiple platforms (JVM, iOS), there are no default Router implementations for any other platforms than Android yet. Those are currently "work in progress". Kompass can still be used as a common API for routing by providing custom implementations of a Router for your platform!

Setup

Step 1: Add the repository

Artifacts are linked to jCenter. Add jCenter repository to your root build.gradle

build.gradle

  allprojects {
     repositories {
        jcenter()
     }
  }

Step 2: Add the dependency (Multiplatform)

build.gradle.kts

kotlin {
    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation("io.sellmair:kompass-core:0.2.0-alpha.5")
            }
        }
        
        /* Optional Android module */
        val androidMain by getting {
            dependencies {
                implementation("io.sellmair:kompass-android:0.2.0-alpha.5")
            }
        }
    }
}

Step 2: Add the dependency (Android Only)

build.gradle.kts

dependencies {
    implementation("io.sellmair:kompass-android:0.2.0-alpha.4")
}

Optional Step 3: (Android: Highly encouraged) Enable Kotlin's Android extensions (with @Parcelize)

build.gradle.kts

plugins {
    // ...
    id("org.jetbrains.kotlin.android.extensions")
}

// ...

// Currently still necessary for @Parcelize annotation
androidExtensions {
    isExperimental = true
}

Usage

Example

I recommend having a look at the example app built with Kompass



Gif



Defining routes

Routes can easily be represented by data classes. Let's say your App has three routes that you might want to display: A LoginRoute, ContactListRoute and a ChatRoute:

sealed class AppRoute : Route, Parcelable

@Parcelize
class LoginRoute: AppRoute()

@Parcelize
data class ContactListRoute(val contacts: List<Contact>): AppRoute()

@Parcelize
data class ChatRoute(val contact: Contact): AppRoute() 

All the arguments necessary to display a certain route should be present in the route itself. The example above uses the @Parcelize feature from the Kotlin's Android extensions

Creating a router instance (Android)

A FragmentRouter for Android can be configured quite easily by using the built in DSL for configuration.

router = FragmentRouter {
            transitions {
                register(LoginToContactListTransition())
                register(ContactListToChatTransition())
            }
            routing {
                route<LoginRoute> { LoginFragment::class }
                route<ContactListRoute> { ContactListFragment::class }
                route<ChatRoute> { ChatFragment::class }
            }
        }

The above DSL shows two configurations:

  • transitions: configures animations/transitions that should be running when routing
  • routing: configures which Fragment should be displayed for a certain route

Setting up a router instance (Android)

A FragmentRouter needs a ViewGroup to place the fragments in. This can be setup like this:

class MainActivity : AppCompatActivity(), KompassFragmentActivity {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        router.setup(savedInstanceState, R.id.container)
    }


    override fun onBackPressed() {
        router.popRetainRootImmediateOrFinish()
    }

}

Please note: In order to call the setup method, one needs to either implement KomapssFragmentActivity or KompassFragment!

Routing (Simple push)

Let's assume that the user taps on a certain contact in the contact list displayed by the ContactListRoute:

class ContactListViewModel {
 
    private val router = TODO("Maybe use DI?")
 
    fun onContactClicked(contact: Contact) {
        router.push(ChatRoute(contact))
    }

}

The code above will push the ChatRoute onto the "routing stack" and results in the ChatFragment being shown. Popping the "routing stack" will result in the ContactListFragment being displayed again.

Routing (Replacing the current route)

Let's assume the user successfully logged into your app. This should result in the current LoginRoute being replaced by the ContactListRoute

class LoginViewModel {

    private val router = TODO("What about Dagger?")
    
    fun onLoginSuccessful(user: User) {
        router.replaceTopWith(ContactListRoute(user.contacts))
    }
}

Wrapping multiple instructions into one lambda block will bundle them to one single operation on the routing stack. So you could alternatively write something like

fun onLoginSuccessful(user: User) {
    router { pop().push(ContactListRoute(user.contacts)) }
}

Routing (Arbitrary)

Kompass supports arbitrary routing: A instruction to the router is nothing more than a function from a list of routes to a new list of routes. Let's say your app would like to remove all ChatRoute with a certain contact

fun removeContactFromStack(contact: Contact) {
     router {
        with(filter { it.route.contact == contact })
     }
     
     //or
     
     router.plainStackInstruction { filter { it.route.contact == contact } }
}

Receiving the current route inside a Fragment

Accessing the route from within the any Fragment implementation is easily done by conforming to the KompassFragment interface:

class ContactListFragment : Fragment(), KompassFragment {
   
    override val router: FragmentRouter<AppRoute> = TODO() 
   
    private val route: ContactListRoute by route()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        val contacts = route.contacts 
        
       //...
    }

}

Fragment Transitions

In order to support animations (fragment transitions) when routing you just need to implement a FragmentTransition. Example: Your chat app should show a Slide transition when going from the ContactListFragment to the ChatFragment and back. Simply implement the transition, check for your constraints and apply the transitions to the fragment. It is also possible to apply generic constraints to your transition using the GenericFragmentTransition API.

class ContactListToChatTransition : FragmentTransition {
    @SuppressLint("RtlHardcoded")
    override fun setup(
        transaction: FragmentTransaction,
        exitFragment: Fragment, exitRoute: Route,
        enterFragment: Fragment, enterRoute: Route
    ) {
        if (exitFragment is ContactListFragment && enterFragment is ChatFragment) {
            exitFragment.exitTransition = Slide(Gravity.LEFT)
            enterFragment.enterTransition = Slide(Gravity.RIGHT)
        }

        if (exitFragment is ChatFragment && enterFragment is ContactListFragment) {
            exitFragment.exitTransition = Slide(Gravity.RIGHT)
            enterFragment.enterTransition = Slide(Gravity.LEFT)
        }
    }
}

After the transition is implemented, just add it to the configuration of the FragmentRouter like seen above!

FragmentRouter { 
    transitions {
        register(LoginToContactListTransition())
    }
}
Comments
  • Can't use objects as destination

    Can't use objects as destination

    The annotation processor fails to generate the serialization methods for object destinations.

    Suppose the following destination:

    @Destination
    object HomeDestination: PodDestination()
    

    Kompass generates the following method:

    fun Kompass.Companion.bundleAsHomeDestination(bundle: Bundle): HomeDestination = HomeDestination()
    

    This calls HomeDestination() but should instead call HomeDestination.

    opened by heinrichreimer 7
  • Failing Build when using AndroidX.

    Failing Build when using AndroidX.

    The annotation processor is failing when using androidX libs. Here's the stacktrace. [kapt] An exception occurred: java.lang.IllegalStateException: elementUtils.getTypeElement(this) must not be null at io.sellmair.kompass.compiler.extension.RenderContextUse$DefaultImpls.asElement(ProcessingEnvironment+use.kt:91) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.asElement(AutoMapVisitor.kt:13) at io.sellmair.kompass.compiler.extension.RenderContextUse$DefaultImpls.asType(ProcessingEnvironment+use.kt:95) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.asType(AutoMapVisitor.kt:13) at io.sellmair.kompass.compiler.extension.RenderContextUse$DefaultImpls.asType(ProcessingEnvironment+use.kt:119) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.asType(AutoMapVisitor.kt:13) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.destinationCase(AutoMapVisitor.kt:72) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.destinationCase(AutoMapVisitor.kt:61) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.buildImplementation(AutoMapVisitor.kt:39) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.visit(AutoMapVisitor.kt:26) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.visit(AutoMapVisitor.kt:16) at io.sellmair.kompass.compiler.destination.visitor.AutoMapVisitor.visit(AutoMapVisitor.kt:13) at io.sellmair.kompass.compiler.common.VisitorKt$plus$1.visit(Visitor.kt:10) at io.sellmair.kompass.compiler.common.VisitorKt$plus$1.visit(Visitor.kt:9) at io.sellmair.kompass.compiler.common.VisitorKt$plus$1.visit(Visitor.kt:9) at io.sellmair.kompass.compiler.DestinationProcessor.process(DestinationProcessor.kt:54) at org.jetbrains.kotlin.kapt3.base.ProcessorWrapper.process(annotationProcessing.kt:99) at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794) at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705) at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91) at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035) at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176) at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170) at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1068) at org.jetbrains.kotlin.kapt3.base.AnnotationProcessingKt.doAnnotationProcessing(annotationProcessing.kt:55) at org.jetbrains.kotlin.kapt3.base.AnnotationProcessingKt.doAnnotationProcessing$default(annotationProcessing.kt:27) at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.runAnnotationProcessing(Kapt3Extension.kt:210) at org.jetbrains.kotlin.kapt3.AbstractKapt3Extension.analysisCompleted(Kapt3Extension.kt:175) at org.jetbrains.kotlin.kapt3.ClasspathBasedKapt3Extension.analysisCompleted(Kapt3Extension.kt:93) at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM$analyzeFilesWithJavaIntegration$2.invoke(TopDownAnalyzerFacadeForJVM.kt:98) at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:108) at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:85) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:370) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:61) at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:101) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:361) at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:126) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:154) at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:51) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:94) at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.java:50) at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:88) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$1$2.invoke(CompileServiceImpl.kt:408) at org.jetbrains.kotlin.daemon.CompileServiceImpl$compile$1$1$2.invoke(CompileServiceImpl.kt:101) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:929) at org.jetbrains.kotlin.daemon.CompileServiceImpl$doCompile$$inlined$ifAlive$lambda$2.invoke(CompileServiceImpl.kt:101) at org.jetbrains.kotlin.daemon.common.DummyProfiler.withMeasure(PerfUtils.kt:137) at org.jetbrains.kotlin.daemon.CompileServiceImpl.checkedCompile(CompileServiceImpl.kt:969) at org.jetbrains.kotlin.daemon.CompileServiceImpl.doCompile(CompileServiceImpl.kt:928) at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:407) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346) at sun.rmi.transport.Transport$1.run(Transport.java:200) at sun.rmi.transport.Transport$1.run(Transport.java:197) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:196) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)

    opened by roshanpisharody 5
  • Keep state on Process-Death

    Keep state on Process-Death

    Kompass doesn't keep the current state on process-death. Routing to a certain destination, terminating the app, re-opening will lead route to the last destination. This could be changed by separating lambdas and destinations from inside the backstack and serializing the backstack to the onSaveInstance bundle.

    feature 0.2.0 
    opened by fablue 4
  • [73] LoginProcessingFragment stuck loading

    [73] LoginProcessingFragment stuck loading

    Fix issue where LoginProcessingFragment gets stuck loading.

    It's actually not required to remove the Handler callback, as this will be handled correctly without the stop method in the case of both configuration change and process death. onCleared already does a perfect job of cleaning these up when they need to be cleaned up!

    opened by isaac-udy 3
  • Decouple Android dependencies

    Decouple Android dependencies

    I believe, Kompass is a great router not only for Android. If we decouple the Android-related implementation detail into separate modules, we could use Kompass also for other frameworks. I guess that would have a clear benefit and shouldn't even be too complicated as the only Android-dependent stuff is Bundle and how to set a sail, which of course can be generalized using some clever interfaces and modules.

    Clearly, this would break some code, but I would like to investigate the idea further.

    0.2.0 
    opened by heinrichreimer 3
  • Question about destination .

    Question about destination .

    Hi , currently im using your library its great and ease to implement and may i know how to identify which is destination is currently is active? or is there a currently function to that please let me know thanks.

    opened by maccam04 3
  • Sample: LoginProcessingFragment can get stuck in loading state forever

    Sample: LoginProcessingFragment can get stuck in loading state forever

    https://github.com/sellmair/kompass/blob/ceed98827b5aa5687df78b83d9de8060ffc7e0dc/android-example--fragment/src/main/java/io/sellmair/kompass/android/example/viewmodel/LoginProcessingViewModel.kt#L37-L39

    Because of viewModel.stop() in onPause, if app is put to background and brought to foreground while LoginProcessingFragment is on front, then the app gets stuck here forever.

    You might want to consider some form of observable that the is bound to onStart/onStop rather than onPause (and no counterpart).

    After rotation, it still gets stuck on the screen:

    Screenshot 2019-05-06 at 13 39 37 bug example 
    opened by Zhuinden 2
  • androidx lifecycle dependency needed

    androidx lifecycle dependency needed

    The app crashes since it can not find LifecycleEventObserver which is part of androidx.lifecycle:lifecycle-extensions:2.1.0-alpha04. It would be nice if this extra dependency is not needed 🤙🏼.

    opened by JulianBissekkou 1
  • `RoutingStack.Element`: Enforce correct hashCode and equals

    `RoutingStack.Element`: Enforce correct hashCode and equals

    Wrong equals or hashCode implementations will result in silently breaking behaviours in DefaultFragmentStackPatcher . e.g. fragments will be removed to early, since they cannot be found in the newStack

    enhancement 0.2.0 
    opened by sellmair 1
  • Check if target is suitable

    Check if target is suitable

    Currently, the compiler itself does not check whether or not the target for a given destination makes sense (if it is a suitable view, fragment or activity). This will lead to a build failure that is hard to understand.

    We should:

    • Check the correctness at kapt-time
    • Print a nice error message telling the user what is wrong
    enhancement 
    opened by sellmair 1
  • Convenience extensions for Activity and Fragment

    Convenience extensions for Activity and Fragment

    As an user of this library I want to get my destinations more straight forward. I want to type

    val myDestination = myDestination()
    

    Instead of

    val myDestination = arguments?.tryAsMyDestination()?:throw IllegalArgumentException()
    

    Inside my fragment/activity

    opened by sellmair 1
  • kotlinx-coroutines-core/jvm/test/flow/TickerFlowsTest.kt

    kotlinx-coroutines-core/jvm/test/flow/TickerFlowsTest.kt

    kotlinx-coroutines-core/jvm/test/flow/TickerFlowsTest.kt

    Originally posted by @hugo891 in https://github.com/sellmair/kompass/issues/9#issuecomment-1156885440

    opened by hugo891 0
  • Discussion: DSL syntax

    Discussion: DSL syntax

    I'd like to start a bit of a discussion around the DSL syntax.

    Multiple paths to one goal:

    router.clear()
    router.push(Route())
    
    router { 
        clear() push Route()
    }
    
    router {
        clear()
        push(Route())
    }
    

    There are several ways to perform similar actions. The first way isn't correct, as it won't bundle up the actions as a single item, but my understanding is the last two ways are essentially the same. ̛I think it would be a better idea to have a single syntax, even if it means that a single "push" needs to be performed as:

    router { push() }
    

    Builder syntax:

    router {
        clear() push RouteA() push RouteB() push RouteC()
    }
    

    The builder continuation syntax that allows a user to push a series of routes like this is inconsistent with the use of infix functions, as a user is unable to split these onto different lines. The following code will not compile:

    router {
        clear() push RouteA()
            push RouteB()
            push RouteC()
    }
    

    I have two questions:

    1. Is the builder/continuation syntax actually useful? Could commands just be split onto different lines?
    2. If the builder/continuation syntax is useful, should the use of infix be removed, so a user can split the continuation over multple lines?
    opened by isaac-udy 15
  • Direct `FragmentRouteStorage`

    Direct `FragmentRouteStorage`

    It may be possible to implement a FragmentRouteStorage that takes the key of a route and retrieves the router later from the router by using the key again

    opened by sellmair 10
Releases(v0.2.0-alpha.5)
  • v0.2.0-alpha.5(Aug 28, 2019)

  • v0.2.0-alpha.3(Aug 26, 2019)

    • Upgrade Kotlin to 1.3.50
    • Lower minSdk to 19
    • Android: Declare AndroidX lifecycle extensions as a transitive dependency
    • Android: Declare AndriodX Fragment as a transitive dependency
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0-alpha.1(May 5, 2019)

  • v0.2.0-alpha.0(May 4, 2019)

    First alpha release of version 0.2.x Major changes:

    • Project is now fully migrated to AndroidX
    • Project is now build for multiplatform (JVM, Android, iOS, MacOS)
    • Replaced "funny" naming schema (after a lot of internal criticism at QuickBird Studios)
    • Fully replaced annotation processing (recommendation is @Parcelize) now
    • Fixed a lot of issues with the pre 0.2.x concept (like process death, or configuration changes)

    While this project changed a lot with this 0.2.x release, the migration should be fairly simple. Right now, there is no migration guide available, but I am happy to help anyone over gitter https://gitter.im/kompass-android/Help

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Apr 14, 2019)

    Changes prior to v0.1.0-beta.0

    The is just a version bump, since the last release (v0.1.0-beta.0) has proven to work reliable in many projects.

    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-beta.0(Nov 6, 2018)

  • v0.1.0-alpha.2(Sep 23, 2018)

  • v0.1.0-alpha.1(Sep 1, 2018)

    Changes prior to 0.1.0-alpha.0

    • Fragments now also have a convenience .sail() method to create a new KompassSail #30
    • Fixed bug when accessing ship for the first time from background thread #34
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-alpha.0(Aug 21, 2018)

    Changes prior to 0.1.0-pre-alpha.3

    • Added convenience value kompass.main to retrieve a ship "main"
    • Support for constructors with default values #19
    • Support for method accessors #20
    • SUPPORT FOR MULTIPLE CONSTRUCTORS #19
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0-pre-alpha.3(Aug 19, 2018)

    v0.1.0-pre-alpha.3

    This is the first public release of 0.1.0. 0.1.0 is completely written from scratch. Main goals:

    • Refine the API
    • Refine the architecture of the software to support multiple ways of routing
    • Support raw View based routing
    • Create high-quality unit and integration tests for this project

    Changes to 0.0.10

    • popBackImmediate is now backImmediate
    • popBack is now back
    • setSail now returns a KompassReleasable instead of KompassSail
    • setSail expects a KompassSail wich can be retrieved by Activity.sail
    • KompassReleasable can be released by Lifecycle or LifecycleOwner
    • Kompass.builder does not require Context anymore
    • autoPilot is now autoDetour
    • asBundle is now toBundle
    • MISSING SUPPORT for multiple constructors and default params in constructors

    Additional notes

    • Upgrade requires the project to be cleaned
    Source code(tar.gz)
    Source code(zip)
  • v0.0.10(Feb 22, 2018)

  • v0.0.7(Feb 9, 2018)

    closes #10 closes #9

    • Infix/Operator notation/for navigation

      • ship.navigateTo(destination) can be expressed as ship += destination
      • ...
    • Support optional and boxed primitves for autoCrane

    Source code(tar.gz)
    Source code(zip)
  • v0.0.6(Feb 8, 2018)

    Implemented chain based routing

    • navigateTo(destination, replaceCurrent) is now deprecated
    • Three new operators are introduced:
      • startAt(destination)
      • navigateTo(destination)
      • beamTo(destination)
    Source code(tar.gz)
    Source code(zip)
Owner
Sebastian Sellmair
Sebastian Sellmair
Extendable MVI framework for Kotlin Multiplatform with powerful debugging tools (logging and time travel), inspired by Badoo MVICore library

Should you have any questions or ideas please welcome to the Slack channel: #mvikotlin Inspiration This project is inspired by Badoo MVICore library.

Arkadii Ivanov 460 Dec 31, 2022
MVU for Kotlin Multiplatform

Oolong Oolong is an Elm inspired Model-View-Update (MVU) implementation for Kotlin multiplatform. As the name implies, three core concepts comprise th

Oolong 288 Nov 29, 2022
Redux implementation for Kotlin (supports multiplatform JVM, native, JS, WASM)

Redux-Kotlin ![badge][badge-ios] A redux standard for Kotlin that supports multiplatform projects. Full documentation at http://reduxkotlin.org. Misso

Redux-Kotlin 301 Dec 25, 2022
Unidirectional Data Flow in Kotlin - Port of https://github.com/ReSwift/ReSwift to Kotlin

ReKotlin Port of ReSwift to Kotlin, which corresponds to ReSwift/4.0.0 Introduction ReKotlin is a Redux-like implementation of the unidirectional data

null 538 Dec 13, 2022
Android Clean Architecture💎 Base Project Android with Kotlin and MVVM applying clean architecture

Android Clean Architecture?? Base Project Android with Kotlin and MVVM applying clean architecture

Mina Mikhail 103 Dec 2, 2022
MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, Kotlin, navigation component, and so on...

MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, kotlin, navigation component, and so on...

Isaias Cuvula 23 Dec 5, 2022
JeTaxi is built on Clean Architecture-MVVM with Kotlin and follows modern android development trends.

JeTaxi is built on Clean Architecture-MVVM with Kotlin and follows modern android development trends. Also, It uses some of Jetpack and popular libraries. These are Kotlin Coroutine-Flow, kotlinx.serialization, Hilt, Compose, Accompanist, Retrofit2, OkHttp3, Chucker, MockWebServer, Truth.

Tolga Bolatcan 13 Nov 2, 2022
Android App using Kotlin, MVVM, ViewModel, LiveData, Coroutines, Room and DataBinding

Words Android App using Kotlin, MVVM, ViewModel, LiveData, Coroutines, Room and

Viacheslav Veselov 0 Jul 16, 2022
A sample project in Kotlin to demonstrate AndroidX, MVVM, Coroutines, Hilt, Room, Data Binding, View Binding, Retrofit, Moshi, Leak Canary and Repository pattern.

This repository contains a sample project in Kotlin to demonstrate AndroidX, MVVM, Coroutines, Hilt, Room, Data Binding, View Binding, Retrofit, Moshi, Leak Canary and Repository pattern

Areg Petrosyan 42 Dec 23, 2022
A sample to showcase Kotlin, MVVM, Koin, Coroutines, StateFlow, Room, WorkManager, Retrofit and Unit test.

TVMaze-Cache A sample to showcase Kotlin, MVVM, Koin, Coroutines, StateFlow, Room, WorkManager, Retrofit and Unit test. Features MVVM Architecture + R

Mohammadali Rezaei 25 Jul 21, 2022
📒Note taking app, MVVM with Google Architectural components Room, LiveData and ViewModel written in Kotlin, androidx libraries

?? MyNotes Note taking Android App using androidx libraries, MVVM with Google Architectural components Room, LiveData and ViewModel. Written in Kotlin

Akshat Bhuhagal 60 Dec 5, 2022
An android app built using Kotlin following Multi-Module Clean Architecture MVVM

RickyandMorty An android app built using Kotlin that consumes RickyadMorty API to display characters.It has been built following Clean Architecture Pr

Kibet 14 Sep 2, 2022
MVVM Kotlin Android Architecture

Model-View-ViewModel (ie MVVM) Model-View-ViewModel (ie MVVM) is a template of a client application architecture, proposed by John Gossman as an alter

Tuan 2 Mar 13, 2022
MVVM Android Studio Kotlin Project Dog Images

MVVM Android Studio Kotlin Project Dog Images This project implement: MVVM Retro

Teulys Jiménez 1 Apr 17, 2022
Android MVVM with Single Activity sample app that uses kotlin coroutines flow

Android MVVM with Single Activity sample app that uses kotlin coroutines flow. This is a sample app that uses kotlin coroutines flow , stateflow. This

null 4 Jul 15, 2022
Pour apprendre en Kotlin, voici une proposition de corrigé pour le Projet 5 "Todoc" du Parcours OC Android

Démo Sujets abordés / démontrés Kotlin Architecture MVVM (Model View ViewModel) LiveData (en particulier le 'pont' liveData {} vers les coroutines) Co

Nino 5 Dec 1, 2022
simple app used Kotlin MVVM Dagger2 Room Coroutines Retrofit2

Exhibits Application which retrieves data from Webserver (via Retrofit), saves it into Room and get from it if user is offline. There are applying MVV

Ahmed Eid 0 Oct 14, 2021
Clean Architecture - Kotlin, MVVM, Use cases

CleanArchitecture Is Clean Architecture only MVVM ? NO, MVVM is a part of clean architecture. MVVM includes Model, View and ViewModel and in addition

Deepanshi bajaj 25 Nov 29, 2022
Kotlin+Flow+Retrofit+OKHttp+ViewBanding+ViewModel+LiveData封装的一个Kotlin版本的MVVM框架

Gitee 地址:kmvvm Github 地址:kmvvm CHANGE LOG 技术要点 支持Flow+Retrofit+OkHttp实现链式http请求 支持Rxjava+Retrofit+OkHttp实现链式http请求 封装基类:BaseActivity、BaseVMActivity、Ba

抓猪 82 Dec 23, 2022