From 60eb43fde7201b76bd465bda1297fcd50049c89d Mon Sep 17 00:00:00 2001
From: andreykovalev <andrey.kovalev@team.bumble.com>
Date: Mon, 2 Oct 2023 11:43:52 +0100
Subject: [PATCH] Mention breaking change in the CHANGELOG.md and allow to add
 keys to PermanentNavModel later

---
 CHANGELOG.md                                  |  2 +-
 .../appyx/core/node/PermanentChildTest.kt     |  7 +++++
 .../appyx/core/composable/PermanentChild.kt   | 26 ++++++++++++-------
 3 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6a956fcef..aec6143e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,7 @@
 
 ## Pending changes
 
-- [#606](https://github.com/bumble-tech/appyx/pull/606) – **Fixed**: Do not create permanentNavModel inside ParentNode. Provide it via constructor to ParentNode
+- [#606](https://github.com/bumble-tech/appyx/pull/606) – **Breaking change**: Do not create permanentNavModel inside ParentNode. Provide it via constructor to ParentNode
 
 ---
 
diff --git a/libraries/core/src/androidTest/kotlin/com/bumble/appyx/core/node/PermanentChildTest.kt b/libraries/core/src/androidTest/kotlin/com/bumble/appyx/core/node/PermanentChildTest.kt
index b9997e791..de13158bb 100644
--- a/libraries/core/src/androidTest/kotlin/com/bumble/appyx/core/node/PermanentChildTest.kt
+++ b/libraries/core/src/androidTest/kotlin/com/bumble/appyx/core/node/PermanentChildTest.kt
@@ -38,6 +38,13 @@ class PermanentChildTest {
         rule.onNode(hasTestTag(TestParentNode.NavTarget::class.java.name)).assertExists()
     }
 
+    @Test
+    fun `WHEN_permanent_model_does_not_contain_relevant_nav_key_THEN_permanent_child_is_not_rendered`() {
+        rule.start()
+
+        rule.onNode(hasTestTag(TestParentNode.NavTarget::class.java.name)).assertDoesNotExist()
+    }
+
     @Test
     fun `WHEN_visibility_switched_THEN_permanent_child_is_reused`() {
         createPermanentNavModelWithNavKey()
diff --git a/libraries/core/src/main/kotlin/com/bumble/appyx/core/composable/PermanentChild.kt b/libraries/core/src/main/kotlin/com/bumble/appyx/core/composable/PermanentChild.kt
index a572ef6ed..0b809f23a 100644
--- a/libraries/core/src/main/kotlin/com/bumble/appyx/core/composable/PermanentChild.kt
+++ b/libraries/core/src/main/kotlin/com/bumble/appyx/core/composable/PermanentChild.kt
@@ -1,11 +1,16 @@
 package com.bumble.appyx.core.composable
 
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Modifier
+import com.bumble.appyx.core.mapState
 import com.bumble.appyx.core.navigation.model.permanent.PermanentNavModel
 import com.bumble.appyx.core.node.Node
 import com.bumble.appyx.core.node.ParentNode
+import kotlinx.coroutines.flow.SharingStarted
 
 @Composable
 fun <NavTarget : Any> ParentNode<NavTarget>.PermanentChild(
@@ -13,19 +18,22 @@ fun <NavTarget : Any> ParentNode<NavTarget>.PermanentChild(
     navTarget: NavTarget,
     decorator: @Composable (child: ChildRenderer) -> Unit
 ) {
-    val child = remember(navTarget, permanentNavModel) {
+    val scope = rememberCoroutineScope()
+    val child by remember(navTarget, permanentNavModel) {
         permanentNavModel
             .elements
-            .value
-            .find { it.key.navTarget == navTarget }
-            ?.let { childOrCreate(it.key) }
-            ?: throw IllegalStateException(
-                "No child found for $navTarget in $permanentNavModel. " +
-                        "Add $navTarget to $permanentNavModel before calling PermanentChild."
-            )
+            // use WhileSubscribed or Lazy otherwise desynchronisation issue
+            .mapState(scope, SharingStarted.WhileSubscribed()) { navElements ->
+                navElements
+                    .find { it.key.navTarget == navTarget }
+                    ?.let { childOrCreate(it.key) }
+            }
+    }.collectAsState()
+
+    child?.let {
+        decorator(PermanentChildRender(it.node))
     }
 
-    decorator(PermanentChildRender(child.node))
 }
 
 @Composable