Split feature modules into api and impl modules

Source code is still left in api module. impl module is empty at this point.
pull/1902/head
Clara Fok 3 months ago
parent 8092c60c0f
commit 7cc2b1ae42

@ -67,12 +67,12 @@ android {
}
dependencies {
implementation(projects.feature.interests)
implementation(projects.feature.foryou)
implementation(projects.feature.bookmarks)
implementation(projects.feature.topic)
implementation(projects.feature.search)
implementation(projects.feature.settings)
implementation(projects.feature.interests.api)
implementation(projects.feature.foryou.api)
implementation(projects.feature.bookmarks.api)
implementation(projects.feature.topic.api)
implementation(projects.feature.search.api)
implementation(projects.feature.settings.api)
implementation(projects.core.common)
implementation(projects.core.ui)

@ -47,10 +47,10 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import javax.inject.Inject
import com.google.samples.apps.nowinandroid.feature.bookmarks.R as BookmarksR
import com.google.samples.apps.nowinandroid.feature.foryou.R as FeatureForyouR
import com.google.samples.apps.nowinandroid.feature.search.R as FeatureSearchR
import com.google.samples.apps.nowinandroid.feature.settings.R as SettingsR
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.R as BookmarksR
import com.google.samples.apps.nowinandroid.feature.foryou.api.R as FeatureForyouR
import com.google.samples.apps.nowinandroid.feature.search.api.R as FeatureSearchR
import com.google.samples.apps.nowinandroid.feature.settings.api.R as SettingsR
/**
* Tests all the navigation flows that are handled by the navigation library.
@ -83,8 +83,8 @@ class NavigationTest {
lateinit var newsRepository: NewsRepository
// The strings used for matching in these tests
private val navigateUp by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_navigate_up)
private val forYou by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_title)
private val navigateUp by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_api_navigate_up)
private val forYou by composeTestRule.stringResource(FeatureForyouR.string.feature_foryou_api_title)
private val interests by composeTestRule.stringResource(FeatureSearchR.string.feature_search_interests)
private val sampleTopic = "Headlines"
private val appName by composeTestRule.stringResource(R.string.app_name)

@ -19,13 +19,13 @@ package com.google.samples.apps.nowinandroid.navigation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.NavHost
import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.bookmarksScreen
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouBaseRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.forYouSection
import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests
import com.google.samples.apps.nowinandroid.feature.search.navigation.searchScreen
import com.google.samples.apps.nowinandroid.feature.topic.navigation.navigateToTopic
import com.google.samples.apps.nowinandroid.feature.topic.navigation.topicScreen
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.navigation.bookmarksScreen
import com.google.samples.apps.nowinandroid.feature.foryou.api.navigation.ForYouBaseRoute
import com.google.samples.apps.nowinandroid.feature.foryou.api.navigation.forYouSection
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.navigateToInterests
import com.google.samples.apps.nowinandroid.feature.search.api.navigation.searchScreen
import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.navigateToTopic
import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.topicScreen
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.INTERESTS
import com.google.samples.apps.nowinandroid.ui.NiaAppState
import com.google.samples.apps.nowinandroid.ui.interests2pane.interestsListDetailScreen

@ -20,14 +20,14 @@ import androidx.annotation.StringRes
import androidx.compose.ui.graphics.vector.ImageVector
import com.google.samples.apps.nowinandroid.R
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.BookmarksRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouBaseRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.ForYouRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.navigation.BookmarksRoute
import com.google.samples.apps.nowinandroid.feature.foryou.api.navigation.ForYouBaseRoute
import com.google.samples.apps.nowinandroid.feature.foryou.api.navigation.ForYouRoute
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsRoute
import kotlin.reflect.KClass
import com.google.samples.apps.nowinandroid.feature.bookmarks.R as bookmarksR
import com.google.samples.apps.nowinandroid.feature.foryou.R as forYouR
import com.google.samples.apps.nowinandroid.feature.search.R as searchR
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.R as bookmarksR
import com.google.samples.apps.nowinandroid.feature.foryou.api.R as forYouR
import com.google.samples.apps.nowinandroid.feature.search.api.R as searchR
/**
* Type for the top level destinations in the application. Contains metadata about the destination
@ -54,7 +54,7 @@ enum class TopLevelDestination(
FOR_YOU(
selectedIcon = NiaIcons.Upcoming,
unselectedIcon = NiaIcons.UpcomingBorder,
iconTextId = forYouR.string.feature_foryou_title,
iconTextId = forYouR.string.feature_foryou_api_title,
titleTextId = R.string.app_name,
route = ForYouRoute::class,
baseRoute = ForYouBaseRoute::class,
@ -62,15 +62,15 @@ enum class TopLevelDestination(
BOOKMARKS(
selectedIcon = NiaIcons.Bookmarks,
unselectedIcon = NiaIcons.BookmarksBorder,
iconTextId = bookmarksR.string.feature_bookmarks_title,
titleTextId = bookmarksR.string.feature_bookmarks_title,
iconTextId = bookmarksR.string.feature_bookmarks_api_title,
titleTextId = bookmarksR.string.feature_bookmarks_api_title,
route = BookmarksRoute::class,
),
INTERESTS(
selectedIcon = NiaIcons.Grid3x3,
unselectedIcon = NiaIcons.Grid3x3,
iconTextId = searchR.string.feature_search_interests,
titleTextId = searchR.string.feature_search_interests,
iconTextId = searchR.string.feature_search_api_interests,
titleTextId = searchR.string.feature_search_api_interests,
route = InterestsRoute::class,
),
}

@ -71,11 +71,11 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopAp
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors
import com.google.samples.apps.nowinandroid.feature.settings.SettingsDialog
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsDialog
import com.google.samples.apps.nowinandroid.navigation.NiaNavHost
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
import kotlin.reflect.KClass
import com.google.samples.apps.nowinandroid.feature.settings.R as settingsR
import com.google.samples.apps.nowinandroid.feature.settings.api.R as settingsR
@Composable
fun NiaApp(

@ -34,10 +34,10 @@ import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourc
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import com.google.samples.apps.nowinandroid.core.ui.TrackDisposableJank
import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.navigateToBookmarks
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.navigateToForYou
import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterests
import com.google.samples.apps.nowinandroid.feature.search.navigation.navigateToSearch
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.navigation.navigateToBookmarks
import com.google.samples.apps.nowinandroid.feature.foryou.api.navigation.navigateToForYou
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.navigateToInterests
import com.google.samples.apps.nowinandroid.feature.search.api.navigation.navigateToSearch
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.BOOKMARKS
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination.FOR_YOU

@ -19,7 +19,7 @@ package com.google.samples.apps.nowinandroid.ui.interests2pane
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.navigation.toRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsRoute
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject

@ -52,12 +52,12 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.composable
import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.topic.TopicDetailPlaceholder
import com.google.samples.apps.nowinandroid.feature.topic.TopicScreen
import com.google.samples.apps.nowinandroid.feature.topic.TopicViewModel
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TopicRoute
import com.google.samples.apps.nowinandroid.feature.interests.api.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicDetailPlaceholder
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicScreen
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicViewModel
import com.google.samples.apps.nowinandroid.feature.topic.api.navigation.TopicRoute
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import kotlin.math.max

@ -45,7 +45,7 @@ import org.robolectric.annotation.Config
import javax.inject.Inject
import kotlin.properties.ReadOnlyProperty
import kotlin.test.assertTrue
import com.google.samples.apps.nowinandroid.feature.topic.R as FeatureTopicR
import com.google.samples.apps.nowinandroid.feature.topic.api.R as FeatureTopicR
private const val EXPANDED_WIDTH = "w1200dp-h840dp"
private const val COMPACT_WIDTH = "w412dp-h915dp"

@ -1,3 +0,0 @@
# :feature:bookmarks module
## Dependency graph
![Dependency graph](../../docs/images/graphs/dep_graph_feature_bookmarks.svg)

@ -21,7 +21,7 @@ plugins {
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.bookmarks"
namespace = "com.google.samples.apps.nowinandroid.feature.bookmarks.api"
}
dependencies {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.bookmarks
package com.google.samples.apps.nowinandroid.feature.bookmarks.api
import androidx.activity.ComponentActivity
import androidx.compose.runtime.CompositionLocalProvider
@ -35,7 +35,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.testing.TestLifecycleOwner
import com.google.samples.apps.nowinandroid.core.testing.data.userNewsResourcesTestData
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.bookmarks
package com.google.samples.apps.nowinandroid.feature.bookmarks.api
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.Image
@ -112,8 +112,8 @@ internal fun BookmarksScreen(
undoBookmarkRemoval: () -> Unit = {},
clearUndoState: () -> Unit = {},
) {
val bookmarkRemovedMessage = stringResource(id = R.string.feature_bookmarks_removed)
val undoText = stringResource(id = R.string.feature_bookmarks_undo)
val bookmarkRemovedMessage = stringResource(id = R.string.feature_bookmarks_api_removed)
val undoText = stringResource(id = R.string.feature_bookmarks_api_undo)
LaunchedEffect(shouldDisplayUndoBookmark) {
if (shouldDisplayUndoBookmark) {
@ -155,7 +155,7 @@ private fun LoadingState(modifier: Modifier = Modifier) {
.fillMaxWidth()
.wrapContentSize()
.testTag("forYou:loading"),
contentDesc = stringResource(id = R.string.feature_bookmarks_loading),
contentDesc = stringResource(id = R.string.feature_bookmarks_api_loading),
)
}
@ -228,7 +228,7 @@ private fun EmptyState(modifier: Modifier = Modifier) {
val iconTint = LocalTintTheme.current.iconTint
Image(
modifier = Modifier.fillMaxWidth(),
painter = painterResource(id = R.drawable.feature_bookmarks_img_empty_bookmarks),
painter = painterResource(id = R.drawable.feature_bookmarks_api_mg_empty_bookmarks),
colorFilter = if (iconTint != Color.Unspecified) ColorFilter.tint(iconTint) else null,
contentDescription = null,
)
@ -236,7 +236,7 @@ private fun EmptyState(modifier: Modifier = Modifier) {
Spacer(modifier = Modifier.height(48.dp))
Text(
text = stringResource(id = R.string.feature_bookmarks_empty_error),
text = stringResource(id = R.string.feature_bookmarks_api_empty_error),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.titleMedium,
@ -246,7 +246,7 @@ private fun EmptyState(modifier: Modifier = Modifier) {
Spacer(modifier = Modifier.height(8.dp))
Text(
text = stringResource(id = R.string.feature_bookmarks_empty_description),
text = stringResource(id = R.string.feature_bookmarks_api_empty_description),
modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.bookmarks
package com.google.samples.apps.nowinandroid.feature.bookmarks.api
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf

@ -14,13 +14,13 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.bookmarks.navigation
package com.google.samples.apps.nowinandroid.feature.bookmarks.api.navigation
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.google.samples.apps.nowinandroid.feature.bookmarks.BookmarksRoute
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.BookmarksRoute
import kotlinx.serialization.Serializable
@Serializable object BookmarksRoute

@ -15,10 +15,10 @@
limitations under the License.
-->
<resources>
<string name="feature_bookmarks_title">Saved</string>
<string name="feature_bookmarks_loading">Loading saved…</string>
<string name="feature_bookmarks_empty_error">No saved updates</string>
<string name="feature_bookmarks_empty_description">Updates you save will be stored here\nto read later</string>
<string name="feature_bookmarks_removed">Bookmark removed</string>
<string name="feature_bookmarks_undo">UNDO</string>
<string name="feature_bookmarks_api_title">Saved</string>
<string name="feature_bookmarks_api_loading">Loading saved…</string>
<string name="feature_bookmarks_api_empty_error">No saved updates</string>
<string name="feature_bookmarks_api_empty_description">Updates you save will be stored here\nto read later</string>
<string name="feature_bookmarks_api_removed">Bookmark removed</string>
<string name="feature_bookmarks_api_undo">UNDO</string>
</resources>

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.bookmarks
package com.google.samples.apps.nowinandroid.feature.bookmarks.api
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.testing.data.newsResourcesTestData
@ -23,6 +23,7 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserData
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success
import com.google.samples.apps.nowinandroid.feature.bookmarks.api.BookmarksViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher

@ -0,0 +1,26 @@
/*
* Copyright 2022 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.
*/
plugins {
alias(libs.plugins.nowinandroid.android.feature)
alias(libs.plugins.nowinandroid.android.library.compose)
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.bookmarks.impl"
}
dependencies { }

@ -22,7 +22,7 @@ plugins {
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.foryou"
namespace = "com.google.samples.apps.nowinandroid.feature.foryou.api"
testOptions.unitTests.isIncludeAndroidResources = true
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
package com.google.samples.apps.nowinandroid.feature.foryou.api
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
@ -45,7 +45,7 @@ class ForYouScreenTest {
private val doneButtonMatcher by lazy {
hasText(
composeTestRule.activity.resources.getString(R.string.feature_foryou_done),
composeTestRule.activity.resources.getString(R.string.feature_foryou_api_done),
)
}
@ -70,7 +70,7 @@ class ForYouScreenTest {
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.feature_foryou_loading),
composeTestRule.activity.resources.getString(R.string.feature_foryou_api_loading),
)
.assertExists()
}
@ -96,7 +96,7 @@ class ForYouScreenTest {
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.feature_foryou_loading),
composeTestRule.activity.resources.getString(R.string.feature_foryou_api_loading),
)
.assertExists()
}
@ -215,7 +215,7 @@ class ForYouScreenTest {
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.feature_foryou_loading),
composeTestRule.activity.resources.getString(R.string.feature_foryou_api_loading),
)
.assertExists()
}
@ -241,7 +241,7 @@ class ForYouScreenTest {
composeTestRule
.onNodeWithContentDescription(
composeTestRule.activity.resources.getString(R.string.feature_foryou_loading),
composeTestRule.activity.resources.getString(R.string.feature_foryou_api_loading),
)
.assertExists()
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
package com.google.samples.apps.nowinandroid.feature.foryou.api
import android.net.Uri
import android.os.Build.VERSION
@ -215,7 +215,7 @@ internal fun ForYouScreen(
targetOffsetY = { fullHeight -> -fullHeight },
) + fadeOut(),
) {
val loadingContentDescription = stringResource(id = R.string.feature_foryou_loading)
val loadingContentDescription = stringResource(id = R.string.feature_foryou_api_loading)
Box(
modifier = Modifier
.fillMaxWidth()
@ -270,7 +270,7 @@ private fun LazyStaggeredGridScope.onboarding(
item(span = StaggeredGridItemSpan.FullLine, contentType = "onboarding") {
Column(modifier = interestsItemModifier) {
Text(
text = stringResource(R.string.feature_foryou_onboarding_guidance_title),
text = stringResource(R.string.feature_foryou_api_onboarding_guidance_title),
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
@ -278,7 +278,7 @@ private fun LazyStaggeredGridScope.onboarding(
style = MaterialTheme.typography.titleMedium,
)
Text(
text = stringResource(R.string.feature_foryou_onboarding_guidance_subtitle),
text = stringResource(R.string.feature_foryou_api_onboarding_guidance_subtitle),
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp, start = 24.dp, end = 24.dp),
@ -304,7 +304,7 @@ private fun LazyStaggeredGridScope.onboarding(
.fillMaxWidth(),
) {
Text(
text = stringResource(R.string.feature_foryou_done),
text = stringResource(R.string.feature_foryou_api_done),
)
}
}
@ -433,7 +433,7 @@ fun TopicIcon(
modifier: Modifier = Modifier,
) {
DynamicAsyncImage(
placeholder = painterResource(R.drawable.feature_foryou_ic_icon_placeholder),
placeholder = painterResource(R.drawable.feature_foryou_api_ic_icon_placeholder),
imageUrl = imageUrl,
// decorative
contentDescription = null,

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
package com.google.samples.apps.nowinandroid.feature.foryou.api
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
package com.google.samples.apps.nowinandroid.feature.foryou.api
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou.navigation
package com.google.samples.apps.nowinandroid.feature.foryou.api.navigation
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
@ -23,7 +23,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.navigation
import androidx.navigation.navDeepLink
import com.google.samples.apps.nowinandroid.core.notifications.DEEP_LINK_URI_PATTERN
import com.google.samples.apps.nowinandroid.feature.foryou.ForYouScreen
import com.google.samples.apps.nowinandroid.feature.foryou.api.ForYouScreen
import kotlinx.serialization.Serializable
@Serializable data object ForYouRoute // route to ForYou screen

@ -15,11 +15,11 @@
limitations under the License.
-->
<resources>
<string name="feature_foryou_title">For you</string>
<string name="feature_foryou_done">Done</string>
<string name="feature_foryou_loading">Loading for you…</string>
<string name="feature_foryou_navigate_up">Navigate up</string>
<string name="feature_foryou_onboarding_guidance_title">What are you interested in?</string>
<string name="feature_foryou_onboarding_guidance_subtitle">Updates from topics you follow will appear here. Follow some things to get started.</string>
<string name="feature_foryou_api_title">For you</string>
<string name="feature_foryou_api_done">Done</string>
<string name="feature_foryou_api_loading">Loading for you…</string>
<string name="feature_foryou_api_navigate_up">Navigate up</string>
<string name="feature_foryou_api_onboarding_guidance_title">What are you interested in?</string>
<string name="feature_foryou_api_onboarding_guidance_subtitle">Updates from topics you follow will appear here. Follow some things to get started.</string>
</resources>

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
package com.google.samples.apps.nowinandroid.feature.foryou.api
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
@ -31,9 +31,9 @@ import com.google.samples.apps.nowinandroid.core.testing.util.captureMultiDevice
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success
import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider
import com.google.samples.apps.nowinandroid.feature.foryou.OnboardingUiState.Loading
import com.google.samples.apps.nowinandroid.feature.foryou.OnboardingUiState.NotShown
import com.google.samples.apps.nowinandroid.feature.foryou.OnboardingUiState.Shown
import com.google.samples.apps.nowinandroid.feature.foryou.api.OnboardingUiState.Loading
import com.google.samples.apps.nowinandroid.feature.foryou.api.OnboardingUiState.NotShown
import com.google.samples.apps.nowinandroid.feature.foryou.api.OnboardingUiState.Shown
import dagger.hilt.android.testing.HiltTestApplication
import org.hamcrest.Matchers
import org.junit.Before

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.foryou
package com.google.samples.apps.nowinandroid.feature.foryou.api
import androidx.lifecycle.SavedStateHandle
import com.google.samples.apps.nowinandroid.core.analytics.AnalyticsEvent

@ -0,0 +1,26 @@
/*
* Copyright 2022 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.
*/
plugins {
alias(libs.plugins.nowinandroid.android.feature)
alias(libs.plugins.nowinandroid.android.library.compose)
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.foryou.impl"
}
dependencies { }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

@ -20,7 +20,7 @@ plugins {
alias(libs.plugins.nowinandroid.android.library.jacoco)
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.interests"
namespace = "com.google.samples.apps.nowinandroid.feature.interests.api"
}
dependencies {

@ -25,13 +25,13 @@ import androidx.compose.ui.test.onAllNodesWithContentDescription
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import com.google.samples.apps.nowinandroid.core.testing.data.followableTopicTestData
import com.google.samples.apps.nowinandroid.feature.interests.InterestsScreen
import com.google.samples.apps.nowinandroid.feature.interests.InterestsUiState
import com.google.samples.apps.nowinandroid.feature.interests.api.InterestsScreen
import com.google.samples.apps.nowinandroid.feature.interests.api.InterestsUiState
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import com.google.samples.apps.nowinandroid.core.ui.R as CoreUiR
import com.google.samples.apps.nowinandroid.feature.interests.R as InterestsR
import com.google.samples.apps.nowinandroid.feature.interests.api.R as InterestsR
/**
* UI test for checking the correct behaviour of the Interests screen;
@ -51,8 +51,8 @@ class InterestsScreenTest {
@Before
fun setup() {
composeTestRule.activity.apply {
interestsLoading = getString(InterestsR.string.feature_interests_loading)
interestsEmptyHeader = getString(InterestsR.string.feature_interests_empty_header)
interestsLoading = getString(InterestsR.string.feature_interests_api_loading)
interestsEmptyHeader = getString(InterestsR.string.feature_interests_api_empty_header)
interestsTopicCardFollowButton =
getString(CoreUiR.string.core_ui_interests_card_follow_button_content_desc)
interestsTopicCardUnfollowButton =

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.interests
package com.google.samples.apps.nowinandroid.feature.interests.api
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Text
@ -70,7 +70,7 @@ internal fun InterestsScreen(
when (uiState) {
InterestsUiState.Loading ->
NiaLoadingWheel(
contentDesc = stringResource(id = R.string.feature_interests_loading),
contentDesc = stringResource(id = R.string.feature_interests_api_loading),
)
is InterestsUiState.Interests ->
@ -90,7 +90,7 @@ internal fun InterestsScreen(
@Composable
private fun InterestsEmptyScreen() {
Text(text = stringResource(id = R.string.feature_interests_empty_header))
Text(text = stringResource(id = R.string.feature_interests_api_empty_header))
}
@DevicePreviews

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.interests
package com.google.samples.apps.nowinandroid.feature.interests.api
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
@ -24,7 +24,7 @@ import com.google.samples.apps.nowinandroid.core.data.repository.UserDataReposit
import com.google.samples.apps.nowinandroid.core.domain.GetFollowableTopicsUseCase
import com.google.samples.apps.nowinandroid.core.domain.TopicSortField
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.feature.interests.navigation.InterestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.api.navigation.InterestsRoute
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.interests
package com.google.samples.apps.nowinandroid.feature.interests.api
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.interests.navigation
package com.google.samples.apps.nowinandroid.feature.interests.api.navigation
import androidx.navigation.NavController
import androidx.navigation.NavOptions

@ -15,7 +15,7 @@
limitations under the License.
-->
<resources>
<string name="feature_interests_title">Interests</string>
<string name="feature_interests_loading">Loading data</string>
<string name="feature_interests_empty_header">"No available data"</string>
<string name="feature_interests_api_title">Interests</string>
<string name="feature_interests_api_loading">Loading data</string>
<string name="feature_interests_api_empty_header">"No available data"</string>
</resources>

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.interests
package com.google.samples.apps.nowinandroid.interests.api
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.testing.invoke

@ -0,0 +1,24 @@
/*
* Copyright 2022 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.
*/
plugins {
alias(libs.plugins.nowinandroid.android.feature)
alias(libs.plugins.nowinandroid.android.library.compose)
alias(libs.plugins.nowinandroid.android.library.jacoco)
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.interests.impl"
}

@ -21,7 +21,7 @@ plugins {
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.search"
namespace = "com.google.samples.apps.nowinandroid.feature.search.api"
}
dependencies {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertCountEquals

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import com.google.samples.apps.nowinandroid.core.data.model.RecentSearchQuery

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.Orientation
@ -93,7 +93,7 @@ import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success
import com.google.samples.apps.nowinandroid.core.ui.R.string
import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent
import com.google.samples.apps.nowinandroid.core.ui.newsFeed
import com.google.samples.apps.nowinandroid.feature.search.R as searchR
import com.google.samples.apps.nowinandroid.feature.search.api.R as searchR
@Composable
internal fun SearchRoute(
@ -211,7 +211,7 @@ fun EmptySearchResultBody(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(horizontal = 48.dp),
) {
val message = stringResource(id = searchR.string.feature_search_result_not_found, searchQuery)
val message = stringResource(id = searchR.string.feature_search_api_result_not_found, searchQuery)
val start = message.indexOf(searchQuery)
Text(
text = AnnotatedString(
@ -229,7 +229,7 @@ fun EmptySearchResultBody(
modifier = Modifier.padding(vertical = 24.dp),
)
val tryAnotherSearchString = buildAnnotatedString {
append(stringResource(id = searchR.string.feature_search_try_another_search))
append(stringResource(id = searchR.string.feature_search_api_try_another_search))
append(" ")
withLink(
LinkAnnotation.Clickable(
@ -245,12 +245,12 @@ fun EmptySearchResultBody(
fontWeight = FontWeight.Bold,
),
) {
append(stringResource(id = searchR.string.feature_search_interests))
append(stringResource(id = searchR.string.feature_search_api_interests))
}
}
append(" ")
append(stringResource(id = searchR.string.feature_search_to_browse_topics))
append(stringResource(id = searchR.string.feature_search_api_to_browse_topics))
}
Text(
text = tryAnotherSearchString,
@ -273,7 +273,7 @@ private fun SearchNotReadyBody() {
modifier = Modifier.padding(horizontal = 48.dp),
) {
Text(
text = stringResource(id = searchR.string.feature_search_not_ready),
text = stringResource(id = searchR.string.feature_search_api_not_ready),
style = MaterialTheme.typography.bodyLarge,
textAlign = TextAlign.Center,
modifier = Modifier.padding(vertical = 24.dp),
@ -314,7 +314,7 @@ private fun SearchResultBody(
Text(
text = buildAnnotatedString {
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(stringResource(id = searchR.string.feature_search_topics))
append(stringResource(id = searchR.string.feature_search_api_topics))
}
},
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
@ -350,7 +350,7 @@ private fun SearchResultBody(
Text(
text = buildAnnotatedString {
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(stringResource(id = searchR.string.feature_search_updates))
append(stringResource(id = searchR.string.feature_search_api_updates))
}
},
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
@ -402,7 +402,7 @@ private fun RecentSearchesBody(
Text(
text = buildAnnotatedString {
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(stringResource(id = searchR.string.feature_search_recent_searches))
append(stringResource(id = searchR.string.feature_search_api_recent_searches))
}
},
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
@ -417,7 +417,7 @@ private fun RecentSearchesBody(
Icon(
imageVector = NiaIcons.Close,
contentDescription = stringResource(
id = searchR.string.feature_search_clear_recent_searches_content_desc,
id = searchR.string.feature_search_api_clear_recent_searches_content_desc,
),
tint = MaterialTheme.colorScheme.onSurface,
)
@ -491,7 +491,7 @@ private fun SearchTextField(
Icon(
imageVector = NiaIcons.Search,
contentDescription = stringResource(
id = searchR.string.feature_search_title,
id = searchR.string.feature_search_api_title,
),
tint = MaterialTheme.colorScheme.onSurface,
)
@ -506,7 +506,7 @@ private fun SearchTextField(
Icon(
imageVector = NiaIcons.Close,
contentDescription = stringResource(
id = searchR.string.feature_search_clear_search_text_content_desc,
id = searchR.string.feature_search_api_clear_search_text_content_desc,
),
tint = MaterialTheme.colorScheme.onSurface,
)

@ -1,5 +1,5 @@
/*
* Copyright 2023 The Android Open Source Project
* Copyright 2022 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.
@ -16,12 +16,13 @@
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.ui.PreviewParameterData.newsResources
import com.google.samples.apps.nowinandroid.core.ui.PreviewParameterData.topics
import com.google.samples.apps.nowinandroid.feature.search.api.SearchResultUiState.Success
/**
* This [PreviewParameterProvider](https://developer.android.com/reference/kotlin/androidx/compose/ui/tooling/preview/PreviewParameterProvider)
@ -29,7 +30,7 @@ import com.google.samples.apps.nowinandroid.core.ui.PreviewParameterData.topics
*/
class SearchUiStatePreviewParameterProvider : PreviewParameterProvider<SearchResultUiState> {
override val values: Sequence<SearchResultUiState> = sequenceOf(
SearchResultUiState.Success(
Success(
topics = topics.mapIndexed { i, topic ->
FollowableTopic(topic = topic, isFollowed = i % 2 == 0)
},

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel

@ -14,13 +14,13 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search.navigation
package com.google.samples.apps.nowinandroid.feature.search.api.navigation
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.google.samples.apps.nowinandroid.feature.search.SearchRoute
import com.google.samples.apps.nowinandroid.feature.search.api.SearchRoute
import kotlinx.serialization.Serializable
@Serializable data object SearchRoute
@ -36,7 +36,7 @@ fun NavGraphBuilder.searchScreen(
// TODO: Handle back stack for each top-level destination. At the moment each top-level
// destination may have own search screen's back stack.
composable<SearchRoute> {
SearchRoute(
com.google.samples.apps.nowinandroid.feature.search.api.SearchRoute(
onBackClick = onBackClick,
onInterestsClick = onInterestsClick,
onTopicClick = onTopicClick,

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
http://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.
-->
<resources>
<string name="feature_search_api_title">Search</string>
<string name="feature_search_api_clear_search_text_content_desc">Clear search text</string>
<string name="feature_search_api_result_not_found">Sorry, there is no content found for your search \"%1$s\"</string>
<string name="feature_search_api_not_ready">Sorry, we are still processing the search index. Please come back later</string>
<string name="feature_search_api_try_another_search">Try another search or explorer </string>
<string name="feature_search_api_interests">Interests</string>
<string name="feature_search_api_to_browse_topics"> to browse topics</string>
<string name="feature_search_api_topics">Topics</string>
<string name="feature_search_api_updates">Updates</string>
<string name="feature_search_api_recent_searches">Recent searches</string>
<string name="feature_search_api_clear_recent_searches_content_desc">Clear searches</string>
</resources>

@ -1,5 +1,5 @@
/*
* Copyright 2023 The Android Open Source Project
* Copyright 2022 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.
@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.search
package com.google.samples.apps.nowinandroid.feature.search.api
import androidx.lifecycle.SavedStateHandle
import com.google.samples.apps.nowinandroid.core.analytics.NoOpAnalyticsHelper
@ -27,10 +27,10 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestSearchCo
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.emptyUserData
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.search.RecentSearchQueriesUiState.Success
import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.EmptyQuery
import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.Loading
import com.google.samples.apps.nowinandroid.feature.search.SearchResultUiState.SearchNotReady
import com.google.samples.apps.nowinandroid.feature.search.api.RecentSearchQueriesUiState.Success
import com.google.samples.apps.nowinandroid.feature.search.api.SearchResultUiState.EmptyQuery
import com.google.samples.apps.nowinandroid.feature.search.api.SearchResultUiState.Loading
import com.google.samples.apps.nowinandroid.feature.search.api.SearchResultUiState.SearchNotReady
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch

@ -0,0 +1,25 @@
/*
* 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.
*/
plugins {
alias(libs.plugins.nowinandroid.android.feature)
alias(libs.plugins.nowinandroid.android.library.compose)
alias(libs.plugins.nowinandroid.android.library.jacoco)
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.search.impl"
}

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
http://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.
-->
<resources>
<string name="feature_search_title">Search</string>
<string name="feature_search_clear_search_text_content_desc">Clear search text</string>
<string name="feature_search_result_not_found">Sorry, there is no content found for your search \"%1$s\"</string>
<string name="feature_search_not_ready">Sorry, we are still processing the search index. Please come back later</string>
<string name="feature_search_try_another_search">Try another search or explorer </string>
<string name="feature_search_interests">Interests</string>
<string name="feature_search_to_browse_topics"> to browse topics</string>
<string name="feature_search_topics">Topics</string>
<string name="feature_search_updates">Updates</string>
<string name="feature_search_recent_searches">Recent searches</string>
<string name="feature_search_clear_recent_searches_content_desc">Clear searches</string>
</resources>

@ -21,7 +21,7 @@ plugins {
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.settings"
namespace = "com.google.samples.apps.nowinandroid.feature.settings.api"
}
dependencies {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.settings
package com.google.samples.apps.nowinandroid.feature.settings.api
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertIsSelected
@ -23,8 +23,8 @@ import androidx.compose.ui.test.onNodeWithText
import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.DARK
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.DEFAULT
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import org.junit.Rule
import org.junit.Test

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2022 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/Theme.AppCompat" />
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
android:theme="@style/Theme.AppCompat" />
</application>
</manifest>

@ -16,7 +16,7 @@
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.feature.settings
package com.google.samples.apps.nowinandroid.feature.settings.api
import android.content.Intent
import androidx.compose.animation.AnimatedVisibility
@ -66,9 +66,9 @@ import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.DEFAULT
import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent
import com.google.samples.apps.nowinandroid.feature.settings.R.string
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.api.R.string
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
@Composable
fun SettingsDialog(

@ -14,15 +14,15 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.settings
package com.google.samples.apps.nowinandroid.feature.settings.api
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
import kotlinx.coroutines.flow.StateFlow

@ -14,14 +14,14 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.settings
package com.google.samples.apps.nowinandroid.feature.settings.api
import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig.DARK
import com.google.samples.apps.nowinandroid.core.model.data.ThemeBrand.ANDROID
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
import com.google.samples.apps.nowinandroid.core.testing.util.MainDispatcherRule
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.SettingsUiState.Success
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Loading
import com.google.samples.apps.nowinandroid.feature.settings.api.SettingsUiState.Success
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 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
http://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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/Theme.AppCompat" />
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
android:theme="@style/Theme.AppCompat" />
</application>
</manifest>

@ -0,0 +1 @@
/build

@ -21,7 +21,7 @@ plugins {
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.topic"
namespace = "com.google.samples.apps.nowinandroid.feature.topic.api"
}
dependencies {

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic
package com.google.samples.apps.nowinandroid.feature.topic.api
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.hasScrollToNodeAction
@ -45,7 +45,7 @@ class TopicScreenTest {
@Before
fun setup() {
composeTestRule.activity.apply {
topicLoading = getString(R.string.feature_topic_loading)
topicLoading = getString(R.string.feature_topic_api_loading)
}
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic
package com.google.samples.apps.nowinandroid.feature.topic.api
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@ -50,12 +50,12 @@ fun TopicDetailPlaceholder(modifier: Modifier = Modifier) {
),
) {
Icon(
painter = painterResource(id = R.drawable.feature_topic_ic_topic_placeholder),
painter = painterResource(id = R.drawable.feature_topic_api_ic_topic_placeholder),
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
Text(
text = stringResource(id = R.string.feature_topic_select_an_interest),
text = stringResource(id = R.string.feature_topic_api_select_an_interest),
style = MaterialTheme.typography.titleLarge,
)
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic
package com.google.samples.apps.nowinandroid.feature.topic.api
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.gestures.Orientation
@ -68,7 +68,7 @@ import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent
import com.google.samples.apps.nowinandroid.core.ui.TrackScrollJank
import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider
import com.google.samples.apps.nowinandroid.core.ui.userNewsResourceCardItems
import com.google.samples.apps.nowinandroid.feature.topic.R.string
import com.google.samples.apps.nowinandroid.feature.topic.api.R.string
@Composable
fun TopicScreen(
@ -124,7 +124,7 @@ internal fun TopicScreen(
TopicUiState.Loading -> item {
NiaLoadingWheel(
modifier = modifier,
contentDesc = stringResource(id = string.feature_topic_loading),
contentDesc = stringResource(id = string.feature_topic_api_loading),
)
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic
package com.google.samples.apps.nowinandroid.feature.topic.api
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic.navigation
package com.google.samples.apps.nowinandroid.feature.topic.api.navigation
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
@ -22,8 +22,8 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptionsBuilder
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
import com.google.samples.apps.nowinandroid.feature.topic.TopicScreen
import com.google.samples.apps.nowinandroid.feature.topic.TopicViewModel
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicScreen
import com.google.samples.apps.nowinandroid.feature.topic.api.TopicViewModel
import kotlinx.serialization.Serializable
@Serializable data class TopicRoute(val id: String)

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
http://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.
-->
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
@ -52,4 +52,4 @@
android:strokeColor="#8C4190"
android:strokeLineCap="round"
android:strokeWidth="2" />
</vector>
</vector>

@ -15,6 +15,6 @@
limitations under the License.
-->
<resources>
<string name="feature_topic_loading">Loading topic</string>
<string name="feature_topic_select_an_interest">Select an Interest</string>
<string name="feature_topic_api_loading">Loading topic</string>
<string name="feature_topic_api_select_an_interest">Select an Interest</string>
</resources>

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.google.samples.apps.nowinandroid.feature.topic
package com.google.samples.apps.nowinandroid.feature.topic.api
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic

@ -0,0 +1,25 @@
/*
* Copyright 2022 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.
*/
plugins {
alias(libs.plugins.nowinandroid.android.feature)
alias(libs.plugins.nowinandroid.android.library.compose)
alias(libs.plugins.nowinandroid.android.library.jacoco)
}
android {
namespace = "com.google.samples.apps.nowinandroid.feature.topic.impl"
}

@ -65,12 +65,17 @@ include(":core:screenshot-testing")
include(":core:testing")
include(":core:ui")
include(":feature:foryou")
include(":feature:interests")
include(":feature:bookmarks")
include(":feature:topic")
include(":feature:search")
include(":feature:settings")
include(":feature:foryou:api")
include(":feature:foryou:impl")
include(":feature:interests:api")
include(":feature:interests:impl")
include(":feature:bookmarks:api")
include(":feature:bookmarks:impl")
include(":feature:topic:api")
include(":feature:topic:impl")
include(":feature:search:api")
include(":feature:search:impl")
include(":feature:settings:api")
include(":lint")
include(":sync:work")
include(":sync:sync-test")

Loading…
Cancel
Save