Skip to content
This repository has been archived by the owner on Aug 5, 2024. It is now read-only.

feat: navigation params #38

Merged
merged 9 commits into from
Nov 18, 2022
2 changes: 1 addition & 1 deletion compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val serializationVersion = "1.3.2"
val ktorVersion = "1.6.8"

dependencies {
api("br.com.zup.nimbus:nimbus-core-android:1.0.0-alpha7")
api("br.com.zup.nimbus:nimbus-core-android:1.0.0-alpha")
arthurbleilzup marked this conversation as resolved.
Show resolved Hide resolved
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
implementation("io.ktor:ktor-client-core:$ktorVersion")
Expand Down
54 changes: 54 additions & 0 deletions compose/src/main/java/br/zup/com/nimbus/compose/ComponentData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,60 @@ package br.zup.com.nimbus.compose

import androidx.compose.runtime.Composable
import com.zup.nimbus.core.tree.ServerDrivenNode
import java.util.Arrays
arthurbleilzup marked this conversation as resolved.
Show resolved Hide resolved
import kotlin.system.measureTimeMillis

private fun componentListsAreEqual(list: List<*>, comparable: List<*>): Boolean {
return list.size == comparable.size && list.toSet() == comparable.toSet()
}

private fun componentMapsAreEqual(map: Map<String, *>, comparable: Map<String, *>): Boolean {
val requiresDeepComparison = map.size == comparable.size && map.keys == comparable.keys
if (requiresDeepComparison) {
var areEqual = true
for (entry in map.iterator()) {
areEqual = when (entry.value) {
is Function<*> -> continue
is Map<*, *> -> componentMapsAreEqual(
entry.value as Map<String, *>,
comparable[entry.key] as Map<String, *>
)
is Array<*> -> (entry.value as Array<*>).contentEquals(comparable[entry.key] as Array<*>)
is List<*> -> componentListsAreEqual(entry.value as List<*>, comparable as List<*>)
else -> entry.value == comparable[entry.key]
}
if (!areEqual) break
}
return areEqual
}
return false
}

private fun componentsAreEquals(node: ServerDrivenNode, comparable: ServerDrivenNode): Boolean {
return !(
node.id != comparable.id ||
node.component != comparable.component ||
!(
(node.properties == comparable.properties) || (
node.properties?.let { otherProperties ->
comparable.properties?.let { currentProperties ->
componentMapsAreEqual(otherProperties, currentProperties)
}
} == true
)
) ||
!(
(node.children == comparable.children) || (
node.children?.let { otherChildren ->
comparable.children?.let { currentChildren ->
(otherChildren.map { it.id }).toTypedArray()
.contentEquals((currentChildren.map { it.id }).toTypedArray())
}
} == true
)
)
)
}

class ComponentData(
val node: ServerDrivenNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,19 @@ internal fun NimbusNavHost(
nimbusViewModel: NimbusViewModel = viewModel(
//Creates a new viewmodel for each unique key
key = viewModelKey,
factory = NimbusViewModel.provideFactory(
nimbusConfig = nimbusConfig
)
factory = NimbusViewModel.provideFactory(nimbusConfig = nimbusConfig)
arthurbleilzup marked this conversation as resolved.
Show resolved Hide resolved
),
modalParentHelper: ModalTransitionDialogHelper = ModalTransitionDialogHelper(),
nimbusNavHostHelper: NimbusNavHostHelper = NimbusNavHostHelperImpl(),
json: String = "",
) {

NimbusNavigationEffect(nimbusViewModel, navController)

NimbusDisposableEffect(
onCreate = {
initNavHost(nimbusViewModel, viewRequest, json)
})
}
)

ConfigureNavHostHelper(nimbusNavHostHelper, nimbusViewModel)

Expand All @@ -54,17 +52,17 @@ internal fun NimbusNavHost(
) {
composable(
route = SHOW_VIEW_DESTINATION,
arguments = listOf(navArgument(VIEW_URL) {
type = NavType.StringType
defaultValue = VIEW_INITIAL_URL
})
arguments = listOf(
navArgument(VIEW_URL) {
type = NavType.StringType
defaultValue = VIEW_INITIAL_URL
}
)
) { backStackEntry ->
val arguments = requireNotNull(backStackEntry.arguments)
val currentPageUrl = arguments.getString(VIEW_URL)
val currentPage = currentPageUrl?.let {
nimbusViewModel.getPageBy(
it
)
nimbusViewModel.getPageBy(it)
}
currentPage?.let { page ->
NimbusBackHandler()
Expand All @@ -86,7 +84,6 @@ private fun ConfigureNavHostHelper(
) {
nimbusNavHostHelper.nimbusNavHostExecutor = object : NimbusNavHostHelper.NimbusNavHostExecutor {
override fun isFirstScreen(): Boolean = nimbusViewModel.getPageCount() == 1

override fun pop(): Boolean = nimbusViewModel.pop()
}
}
Expand All @@ -96,16 +93,15 @@ private fun initNavHost(
viewRequest: ViewRequest?,
json: String
) {

if (viewRequest != null)
if (viewRequest != null) {
nimbusViewModel.initFirstViewWithRequest(viewRequest = viewRequest)
else
}
else {
nimbusViewModel.initFirstViewWithJson(json = json)

}
}

interface NimbusNavHostHelper {

var nimbusNavHostExecutor: NimbusNavHostExecutor?

interface NimbusNavHostExecutor {
Expand All @@ -121,9 +117,7 @@ interface NimbusNavHostHelper {
* This helper can be used to control some behaviour from outside the NimbusNavHost composable
*/
internal class NimbusNavHostHelperImpl : NimbusNavHostHelper {

override var nimbusNavHostExecutor: NimbusNavHostHelper.NimbusNavHostExecutor? = null
override fun isFirstScreen(): Boolean = nimbusNavHostExecutor?.isFirstScreen() ?: false

override fun pop(): Boolean = nimbusNavHostExecutor?.pop() ?: false
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@ internal fun NimbusNavigationEffect(
navController.nimbusPopTo(navigationState.url)
}
is NimbusViewModelNavigationState.Push -> {
navController.navigate(
"$SHOW_VIEW?$VIEW_URL=${
navigationState.url
}"
)
navController.navigate("$SHOW_VIEW?$VIEW_URL=${navigationState.url}")
}
else -> {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import br.zup.com.nimbus.compose.VIEW_INITIAL_URL
import br.zup.com.nimbus.compose.VIEW_JSON_DESCRIPTION
import br.zup.com.nimbus.compose.model.Page
import com.zup.nimbus.core.ServerDrivenNavigator
import com.zup.nimbus.core.ServerDrivenState
import com.zup.nimbus.core.ServerDrivenView
import com.zup.nimbus.core.network.ViewRequest
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -32,15 +33,13 @@ internal class NimbusViewModel(
private val nimbusConfig: br.zup.com.nimbus.compose.Nimbus,
private val pagesManager: PagesManager = PagesManager(),
) : ViewModel() {

private var _nimbusViewModelModalState: MutableSharedFlow<NimbusViewModelModalState> =
MutableSharedFlow(replay = CoroutineDispatcherLib.REPLAY_COUNT,
onBufferOverflow = CoroutineDispatcherLib.ON_BUFFER_OVERFLOW)

val nimbusViewModelModalState: SharedFlow<NimbusViewModelModalState>
get() = _nimbusViewModelModalState


private var _nimbusViewNavigationState: MutableSharedFlow<NimbusViewModelNavigationState> =
MutableSharedFlow(replay = CoroutineDispatcherLib.REPLAY_COUNT,
onBufferOverflow = CoroutineDispatcherLib.ON_BUFFER_OVERFLOW)
Expand All @@ -54,9 +53,7 @@ internal class NimbusViewModel(
): ViewModelProvider.Factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return NimbusViewModel(
nimbusConfig = nimbusConfig
) as T
return NimbusViewModel(nimbusConfig = nimbusConfig) as T
}
}
}
Expand Down Expand Up @@ -145,28 +142,34 @@ internal class NimbusViewModel(

private fun popNavigationTo(url: String) =
viewModelScope.launch(CoroutineDispatcherLib.backgroundPool) {
val page = pagesManager.getPageBy(url)

page?.let {
pagesManager.removePagesAfter(page)
pagesManager.getPageBy(url)?.let {
pagesManager.removePagesAfter(it)
setNavigationState(NimbusViewModelNavigationState.PopTo(url))
}
}

private fun doPushWithViewRequest(request: ViewRequest, initialRequest: Boolean = false) =
viewModelScope.launch(CoroutineDispatcherLib.inputOutputPool) {
var statesInstances: List<ServerDrivenState>? = null
if (!request.params.isNullOrEmpty()) {
statesInstances = request.params!!.entries.map {
ServerDrivenState(it.key, it.value)
}
}

arthurbleilzup marked this conversation as resolved.
Show resolved Hide resolved
val view = ServerDrivenView(
nimbus = nimbusConfig,
getNavigator = { serverDrivenNavigator },
description = request.url
description = request.url,
states = statesInstances,
)
val url = if (initialRequest) VIEW_INITIAL_URL else request.url
val page = Page(
coroutineScope = viewModelScope,
id = url,
view = view)
view = view
)
pushNavigation(page = page, initialRequest = initialRequest)

loadViewRequest(request, view, page)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,18 @@ internal class PagesManager {
return false
}
this.removeLastPage()

return true
}

fun removeAllPages() {
pages.clear()
}

private fun removeLastPage() =
CoroutineScope(CoroutineDispatcherLib.backgroundPool).launch {
pages.removeLast()
}
private fun removeLastPage() = CoroutineScope(CoroutineDispatcherLib.backgroundPool).launch {
pages.removeLast()
}

fun getPageCount() = pages.size
fun getPageBy(url: String): Page? = pages.firstOrNull { it.id == url }

fun removePagesAfter(page: Page) = page.removePagesAfter(pages)

}
4 changes: 2 additions & 2 deletions compose/src/main/java/br/zup/com/nimbus/compose/model/Page.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ data class Page(

fun setContent(tree: RootNode) {
change(NimbusPageState.PageStateOnShowPage(tree))

}

fun setLoading() {
Expand Down Expand Up @@ -73,6 +72,7 @@ data class Page(

internal fun Page.removePagesAfter(pages: MutableList<Page>) {
val index = pages.indexOf(this)
if (index < pages.lastIndex)
if (index < pages.lastIndex) {
pages.subList(index + 1, pages.size).clear()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const val BASE_URL = "http://localhost"
abstract class BaseTest {
internal val nimbusConfig: Nimbus = mockk()
internal val pagesManager: PagesManager = mockk()
internal val viewClient: ViewClient = mockk()
private val viewClient: ViewClient = mockk()

@BeforeAll
open fun setUp() {
Expand All @@ -28,7 +28,7 @@ abstract class BaseTest {
unmockkAll()
}

protected fun mockNimbusConfig(){
private fun mockNimbusConfig(){
every { nimbusConfig.baseUrl } returns BASE_URL
every { nimbusConfig.viewClient } returns viewClient
}
Expand Down
Loading