@ -1,3 +1,3 @@
|
|||||||
# :app-nia-catalog module
|
# :app-nia-catalog module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../docs/images/graphs/dep_graph_app_nia_catalog.png)
|
![Dependency graph](../docs/images/graphs/dep_graph_app_nia_catalog.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :app module
|
# :app module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../docs/images/graphs/dep_graph_app.png)
|
![Dependency graph](../docs/images/graphs/dep_graph_app.svg)
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.samples.apps.nowinandroid.ui.interests2pane
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.interests.navigation.TOPIC_ID_ARG
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class Interests2PaneViewModel @Inject constructor(
|
||||||
|
private val savedStateHandle: SavedStateHandle,
|
||||||
|
) : ViewModel() {
|
||||||
|
val selectedTopicId: StateFlow<String?> = savedStateHandle.getStateFlow(TOPIC_ID_ARG, null)
|
||||||
|
|
||||||
|
fun onTopicClick(topicId: String?) {
|
||||||
|
savedStateHandle[TOPIC_ID_ARG] = topicId
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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.ListDetailPaneScaffold
|
||||||
|
import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffoldRole
|
||||||
|
import androidx.compose.material3.adaptive.layout.PaneAdaptedValue
|
||||||
|
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.hilt.navigation.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.NavType
|
||||||
|
import androidx.navigation.compose.NavHost
|
||||||
|
import androidx.navigation.compose.composable
|
||||||
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import androidx.navigation.navArgument
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.interests.navigation.INTERESTS_ROUTE
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.interests.navigation.TOPIC_ID_ARG
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.topic.TopicDetailPlaceholder
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TOPIC_ROUTE
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic
|
||||||
|
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen
|
||||||
|
|
||||||
|
private const val DETAIL_PANE_NAVHOST_ROUTE = "detail_pane_route"
|
||||||
|
|
||||||
|
fun NavGraphBuilder.interestsListDetailScreen() {
|
||||||
|
composable(
|
||||||
|
route = INTERESTS_ROUTE,
|
||||||
|
arguments = listOf(
|
||||||
|
navArgument(TOPIC_ID_ARG) {
|
||||||
|
type = NavType.StringType
|
||||||
|
defaultValue = null
|
||||||
|
nullable = true
|
||||||
|
},
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
InterestsListDetailScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
internal fun InterestsListDetailScreen(
|
||||||
|
viewModel: Interests2PaneViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val selectedTopicId by viewModel.selectedTopicId.collectAsStateWithLifecycle()
|
||||||
|
InterestsListDetailScreen(
|
||||||
|
selectedTopicId = selectedTopicId,
|
||||||
|
onTopicClick = viewModel::onTopicClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||||
|
@Composable
|
||||||
|
internal fun InterestsListDetailScreen(
|
||||||
|
selectedTopicId: String?,
|
||||||
|
onTopicClick: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
val listDetailNavigator = rememberListDetailPaneScaffoldNavigator<Nothing>()
|
||||||
|
BackHandler(listDetailNavigator.canNavigateBack()) {
|
||||||
|
listDetailNavigator.navigateBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
val nestedNavController = rememberNavController()
|
||||||
|
|
||||||
|
fun onTopicClickShowDetailPane(topicId: String) {
|
||||||
|
onTopicClick(topicId)
|
||||||
|
nestedNavController.navigateToTopic(topicId) {
|
||||||
|
popUpTo(DETAIL_PANE_NAVHOST_ROUTE)
|
||||||
|
}
|
||||||
|
listDetailNavigator.navigateTo(ListDetailPaneScaffoldRole.Detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
ListDetailPaneScaffold(
|
||||||
|
value = listDetailNavigator.scaffoldValue,
|
||||||
|
directive = listDetailNavigator.scaffoldDirective,
|
||||||
|
listPane = {
|
||||||
|
InterestsRoute(
|
||||||
|
onTopicClick = ::onTopicClickShowDetailPane,
|
||||||
|
highlightSelectedTopic = listDetailNavigator.isDetailPaneVisible(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
detailPane = {
|
||||||
|
NavHost(
|
||||||
|
navController = nestedNavController,
|
||||||
|
startDestination = TOPIC_ROUTE,
|
||||||
|
route = DETAIL_PANE_NAVHOST_ROUTE,
|
||||||
|
) {
|
||||||
|
topicScreen(
|
||||||
|
showBackButton = !listDetailNavigator.isListPaneVisible(),
|
||||||
|
onBackClick = listDetailNavigator::navigateBack,
|
||||||
|
onTopicClick = ::onTopicClickShowDetailPane,
|
||||||
|
)
|
||||||
|
composable(route = TOPIC_ROUTE) {
|
||||||
|
TopicDetailPlaceholder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (selectedTopicId != null) {
|
||||||
|
// Initial topic ID was provided when navigating to Interests, so show its details.
|
||||||
|
onTopicClickShowDetailPane(selectedTopicId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||||
|
private fun <T> ThreePaneScaffoldNavigator<T>.isListPaneVisible(): Boolean =
|
||||||
|
scaffoldValue[ListDetailPaneScaffoldRole.List] == PaneAdaptedValue.Expanded
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
||||||
|
private fun <T> ThreePaneScaffoldNavigator<T>.isDetailPaneVisible(): Boolean =
|
||||||
|
scaffoldValue[ListDetailPaneScaffoldRole.Detail] == PaneAdaptedValue.Expanded
|
@ -0,0 +1,3 @@
|
|||||||
|
# :core:analytics module
|
||||||
|
## Dependency graph
|
||||||
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_analytics.svg)
|
@ -1,3 +1,3 @@
|
|||||||
# :core:common module
|
# :core:common module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_common.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_common.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:data-test module
|
# :core:data-test module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_data_test.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_data_test.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:data module
|
# :core:data module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_data.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_data.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:database module
|
# :core:database module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_database.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_database.svg)
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
# :core:datastore-proto module
|
||||||
|
## Dependency graph
|
||||||
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore_proto.svg)
|
@ -1,3 +1,3 @@
|
|||||||
# :core:datastore-test module
|
# :core:datastore-test module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore_test.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore_test.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:datastore module
|
# :core:datastore module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_datastore.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:designsystem module
|
# :core:designsystem module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_designsystem.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_designsystem.svg)
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
# :core:domain module
|
||||||
|
## Dependency graph
|
||||||
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_domain.svg)
|
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2023 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.google.samples.apps.nowinandroid.core.domain
|
|
||||||
|
|
||||||
import com.google.samples.apps.nowinandroid.core.data.repository.SearchContentsRepository
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A use case which returns total count of *Fts tables
|
|
||||||
*/
|
|
||||||
class GetSearchContentsCountUseCase @Inject constructor(
|
|
||||||
private val searchContentsRepository: SearchContentsRepository,
|
|
||||||
) {
|
|
||||||
operator fun invoke(): Flow<Int> =
|
|
||||||
searchContentsRepository.getSearchContentsCount()
|
|
||||||
}
|
|
@ -1,3 +1,3 @@
|
|||||||
# :core:model module
|
# :core:model module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_model.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_model.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:network module
|
# :core:network module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_network.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_network.svg)
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
# :core:notifications module
|
||||||
|
## Dependency graph
|
||||||
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_notifications.svg)
|
@ -0,0 +1,3 @@
|
|||||||
|
# :core:screenshot-testing module
|
||||||
|
## Dependency graph
|
||||||
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_screenshot_testing.svg)
|
@ -1,3 +1,3 @@
|
|||||||
# :core:testing module
|
# :core:testing module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_testing.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_testing.svg)
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
# :core:ui module
|
# :core:ui module
|
||||||
|
## Dependency graph
|
||||||
![Dependency graph](../../docs/images/graphs/dep_graph_core_ui.png)
|
![Dependency graph](../../docs/images/graphs/dep_graph_core_ui.svg)
|
||||||
|
Before Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 863 B |
Before Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 893 B |
Before Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 872 B |
After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 851 B |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 2.6 KiB |