Merge branch 'main' into dt/nav-safe-args (AnimatedPane broken)

* main:
  Save nested nav key in instance state
  🤖 Updates baselines for Dependency Guard
  Recreate nested nav to work with AnimatedPane
  Remove forgotten Trace.endSection()
  Offload connectivity monitor to a background thread

Change-Id: I4002a07484a4d633c57406aedabf9f5d813a8592
dt/nav-safe-args-android-dependency
Don Turner 8 months ago
commit f711e69cd2

@ -18,14 +18,22 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane
import androidx.activity.compose.BackHandler
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.material3.adaptive.layout.AnimatedPane
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldDestinationItem
import androidx.compose.material3.adaptive.navigation.ThreePaneScaffoldNavigator
import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.Saver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.setValue
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -36,8 +44,10 @@ import androidx.navigation.compose.rememberNavController
import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsDestination
import com.google.samples.apps.nowinandroid.feature.topic.TopicDetailPlaceholder
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicDestination
import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen
import java.util.UUID
import kotlinx.serialization.Serializable
@Serializable object TopicPlaceholderDestination
@ -67,18 +77,46 @@ internal fun InterestsListDetailScreen(
selectedTopicId: String?,
onTopicClick: (String) -> Unit,
) {
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator()
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator(
initialDestinationHistory = listOfNotNull(
ThreePaneScaffoldDestinationItem(ListDetailPaneScaffoldRole.List),
ThreePaneScaffoldDestinationItem<Nothing>(ListDetailPaneScaffoldRole.Detail).takeIf {
selectedTopicId != null
},
),
)
BackHandler(listDetailNavigator.canNavigateBack()) {
listDetailNavigator.navigateBack()
}
val nestedNavController = rememberNavController()
var nestedNavHostStartDestination by remember {
val destination = selectedTopicId?.let { TopicDestination(id = it) } ?: TopicPlaceholderDestination
mutableStateOf(destination)
}
var nestedNavKey by rememberSaveable(
stateSaver = Saver({ it.toString() }, UUID::fromString),
) {
mutableStateOf(UUID.randomUUID())
}
val nestedNavController = key(nestedNavKey) {
rememberNavController()
}
fun onTopicClickShowDetailPane(topicId: String) {
onTopicClick(topicId)
// TODO (merge): Fix this
//if (listDetailNavigator.isDetailPaneVisible()) {
// If the detail pane was visible, then use the nestedNavController navigate call
// directly
nestedNavController.navigateToTopic(topicId) {
popUpTo<DetailPaneNavHostDestination>()
}
/*} else {
// Otherwise, recreate the NavHost entirely, and start at the new destination
nestedNavHostStartDestination = TopicDestination(id = topicId)
nestedNavKey = UUID.randomUUID()
}*/
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
}
@ -86,15 +124,21 @@ internal fun InterestsListDetailScreen(
value = listDetailNavigator.scaffoldValue,
directive = listDetailNavigator.scaffoldDirective,
listPane = {
// TODO (merge): Fix this
//AnimatedPane {
InterestsRoute(
onTopicClick = ::onTopicClickShowDetailPane,
highlightSelectedTopic = listDetailNavigator.isDetailPaneVisible(),
)
//}
},
detailPane = {
// TODO (merge): Fix this
//AnimatedPane {
// key(nestedNavKey) {
NavHost(
navController = nestedNavController,
startDestination = TopicPlaceholderDestination,
startDestination = nestedNavHostStartDestination,
route = DetailPaneNavHostDestination::class,
) {
topicScreen(
@ -106,8 +150,11 @@ internal fun InterestsListDetailScreen(
TopicDetailPlaceholder()
}
}
// }
//}
},
)
// TODO (merge): Remove
LaunchedEffect(Unit) {
if (selectedTopicId != null) {
// Initial topic ID was provided when navigating to Interests, so show its details.

@ -26,17 +26,24 @@ import android.net.NetworkRequest.Builder
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import androidx.core.content.getSystemService
import androidx.tracing.trace
import com.google.samples.apps.nowinandroid.core.network.Dispatcher
import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers.IO
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import javax.inject.Inject
internal class ConnectivityManagerNetworkMonitor @Inject constructor(
@ApplicationContext private val context: Context,
@Dispatcher(IO) private val ioDispatcher: CoroutineDispatcher,
) : NetworkMonitor {
override val isOnline: Flow<Boolean> = callbackFlow {
trace("NetworkMonitor.callbackFlow") {
val connectivityManager = context.getSystemService<ConnectivityManager>()
if (connectivityManager == null) {
channel.trySend(false)
@ -63,10 +70,12 @@ internal class ConnectivityManagerNetworkMonitor @Inject constructor(
}
}
trace("NetworkMonitor.registerNetworkCallback") {
val request = Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build()
connectivityManager.registerNetworkCallback(request, callback)
}
/**
* Sends the latest connectivity status to the underlying channel.
@ -77,6 +86,8 @@ internal class ConnectivityManagerNetworkMonitor @Inject constructor(
connectivityManager.unregisterNetworkCallback(callback)
}
}
}
.flowOn(ioDispatcher)
.conflate()
@Suppress("DEPRECATION")

Loading…
Cancel
Save