-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
505 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.myunidays.library"/> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.myunidays.direkt"/> |
26 changes: 26 additions & 0 deletions
26
library/src/androidTest/kotlin/com/myunidays/dispatcher/CoroutineTestDispatchersManager.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.myunidays.dispatcher | ||
|
||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.test.TestDispatcher | ||
import kotlinx.coroutines.test.resetMain | ||
import kotlinx.coroutines.test.setMain | ||
|
||
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) | ||
actual class CoroutineTestDispatchersManager actual constructor(actual val testDispatcher: TestDispatcher) { | ||
|
||
// We can use a different dispatched when running tests for Android | ||
actual val dispatcherProvider = object : DispatcherProvider { | ||
override fun default(): CoroutineDispatcher = testDispatcher | ||
override fun main(): CoroutineDispatcher = testDispatcher | ||
override fun unconfined(): CoroutineDispatcher = testDispatcher | ||
} | ||
|
||
actual fun start() { | ||
Dispatchers.setMain(testDispatcher) | ||
} | ||
|
||
actual fun stop() { | ||
Dispatchers.resetMain() | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
library/src/commonMain/kotlin/com/myunidays/dispatcher/DefaultDispatcherProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.myunidays.dispatcher | ||
|
||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.Dispatchers | ||
|
||
interface DispatcherProvider { | ||
|
||
fun main(): CoroutineDispatcher | ||
fun default(): CoroutineDispatcher | ||
fun unconfined(): CoroutineDispatcher | ||
} | ||
|
||
class DefaultDispatcherProvider : DispatcherProvider { | ||
override fun main(): CoroutineDispatcher = Dispatchers.Main | ||
override fun default(): CoroutineDispatcher = Dispatchers.Default | ||
override fun unconfined(): CoroutineDispatcher = Dispatchers.Unconfined | ||
} |
19 changes: 19 additions & 0 deletions
19
library/src/commonMain/kotlin/com/myunidays/router/EmptyRouterImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.myunidays.router | ||
|
||
import com.myunidays.transition.Transition | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.StateFlow | ||
|
||
// We can use this empty router for the 'native' views which are unbound by KMM - maybe could be used for testing too. | ||
class EmptyRouterImpl<Config : RoutingConfig, Child> : Router<Config, Child> { | ||
override val stack = MutableSharedFlow<Pair<Transition, Config>>(0) | ||
override val stackHistory: StateFlow<List<Pair<Transition, Config>>> = MutableStateFlow(emptyList()) | ||
override val canGoBack = false | ||
|
||
override val activeChild: Config? = null | ||
|
||
override suspend fun handleDeeplink(deeplink: String) = throw EmptyRouterException() | ||
|
||
class EmptyRouterException : Exception("Cannot call method on Empty Router") | ||
} |
18 changes: 18 additions & 0 deletions
18
library/src/commonMain/kotlin/com/myunidays/router/Router.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.myunidays.router | ||
|
||
import com.myunidays.transition.Transition | ||
import kotlinx.coroutines.flow.SharedFlow | ||
import kotlinx.coroutines.flow.StateFlow | ||
|
||
// The router is COMPLETELY decoupled from the project, its using Generics | ||
// and doesnt need to know about view models etc. | ||
// Consider how we could potentially handle deeplinks from here?? - | ||
// using the key from Routing config. | ||
interface Router<Config : RoutingConfig, Child> { | ||
val stack: SharedFlow<Pair<Transition, Config>> | ||
val stackHistory: StateFlow<List<Pair<Transition, Config>>> | ||
val activeChild: Config? | ||
val canGoBack: Boolean | ||
// deeplink stuff | ||
suspend fun handleDeeplink(deeplink: String): String? | ||
} |
88 changes: 88 additions & 0 deletions
88
library/src/commonMain/kotlin/com/myunidays/router/RouterImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package com.myunidays.router | ||
|
||
import com.myunidays.dispatcher.DefaultDispatcherProvider | ||
import com.myunidays.dispatcher.DispatcherProvider | ||
import com.myunidays.transition.Transition | ||
import io.ktor.http.Url | ||
import io.ktor.util.toMap | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.flow.MutableSharedFlow | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.StateFlow | ||
import kotlinx.coroutines.launch | ||
|
||
class RouterImpl<Config : RoutingConfig, Child>( | ||
initial: Config, | ||
private val configForName: (name: String, params: Map<String, List<String>>) -> Config?, | ||
dispatcher: DispatcherProvider = DefaultDispatcherProvider() | ||
) : Router<Config, Child>, RouterTransitions<Config, Child> { | ||
|
||
override val activeChild: Config? get() = _stack.lastOrNull() | ||
override val stack: MutableSharedFlow<Pair<Transition, Config>> = MutableSharedFlow(1) | ||
private val _stack: MutableList<Config> = mutableListOf() | ||
|
||
// Jacobs Idea: We could store the whole list of changes, so that we could replay in the case of a crash. | ||
private val _stackHistory: MutableStateFlow<List<Pair<Transition, Config>>> = MutableStateFlow(emptyList()) | ||
override val stackHistory: StateFlow<List<Pair<Transition, Config>>> = _stackHistory | ||
|
||
override val canGoBack: Boolean get() = _stack.size > 1 | ||
|
||
init { | ||
CoroutineScope(dispatcher.default()).launch { | ||
stack.collect { transitionConfig -> | ||
_stackHistory.emit(_stackHistory.value + transitionConfig) | ||
} | ||
} | ||
CoroutineScope(dispatcher.default()).launch { | ||
push(initial) | ||
} | ||
} | ||
|
||
override suspend fun push(config: Config) { | ||
_stack.add(config) | ||
stack.emit(Transition.Push to config) | ||
} | ||
|
||
override suspend fun pop() { | ||
_stack.removeLast() | ||
stack.emit(Transition.Pop to _stack.last()) | ||
} | ||
|
||
override suspend fun replace(config: Config) { | ||
_stack.removeLast() | ||
_stack.add(config) | ||
stack.emit(Transition.Replace to config) | ||
} | ||
|
||
override suspend fun update(config: Config) { | ||
_stack.add(config) | ||
stack.emit(Transition.Update to config) | ||
} | ||
|
||
// we could have a more generic function, router.supportsConfig(key)? | ||
// Deeplinking stuff | ||
override suspend fun handleDeeplink(deeplink: String): String? = | ||
runCatching { | ||
Url(deeplink).let { deeplinkUrl -> | ||
val parameters = deeplinkUrl.parameters.toMap() | ||
if (parameters[Transition.key]?.firstOrNull() == Transition.Pop.name) { | ||
pop() | ||
return deeplink | ||
} | ||
return@runCatching configForName( | ||
deeplinkUrl.host, | ||
parameters | ||
)?.let { config -> | ||
when (config.transition) { | ||
Transition.Push -> push(config) | ||
Transition.Pop -> pop() | ||
Transition.Replace -> replace(config) | ||
Transition.Update -> update(config) | ||
} | ||
return deeplink | ||
} | ||
} | ||
} | ||
.onFailure { println("Failed to parse deeplink $deeplink $it") } | ||
.getOrNull() | ||
} |
8 changes: 8 additions & 0 deletions
8
library/src/commonMain/kotlin/com/myunidays/router/RouterTransitions.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.myunidays.router | ||
|
||
internal interface RouterTransitions<Config : RoutingConfig, Child> { | ||
suspend fun push(config: Config) | ||
suspend fun pop() | ||
suspend fun replace(config: Config) | ||
suspend fun update(config: Config) | ||
} |
8 changes: 8 additions & 0 deletions
8
library/src/commonMain/kotlin/com/myunidays/router/RoutingConfig.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.myunidays.router | ||
|
||
import com.myunidays.transition.Transition | ||
|
||
open class RoutingConfig( | ||
val key: String, | ||
val transition: Transition = Transition.Push | ||
) |
Oops, something went wrong.