Merge branch 'main' into kotlinify

pull/1039/head
Don Turner 6 months ago committed by GitHub
commit 9d41ffa318
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,3 +4,4 @@
[*.{kt,kts}]
ij_kotlin_allow_trailing_comma=true
ij_kotlin_allow_trailing_comma_on_call_site=true
ktlint_function_naming_ignore_when_annotated_with=Composable, Test

@ -15,6 +15,8 @@
limitations under the License.
-->
<resources>
<!-- Allow users to distinguish between build variants by having a different background color
for the launcher icon. See https://github.com/android/nowinandroid/pull/989. -->
<color name="ic_launcher_background_tint">#FFFFFF</color>
<color name="ic_launcher_foreground_tint">#FF006780</color>
</resources>

@ -15,6 +15,8 @@
limitations under the License.
-->
<resources>
<!-- Allow users to distinguish between build variants by having a different background color
for the launcher icon. See https://github.com/android/nowinandroid/pull/989. -->
<color name="ic_launcher_background_tint">#000000</color>
<color name="ic_launcher_foreground_tint">#FF006780</color>
</resources>

@ -15,6 +15,8 @@
limitations under the License.
-->
<resources>
<!-- Allow users to distinguish between build variants by having a different background color
for the launcher icon. See https://github.com/android/nowinandroid/pull/989. -->
<color name="ic_launcher_background_tint">#FFFFFF</color>
<color name="ic_launcher_foreground_tint">#FFA23F16</color>
</resources>

@ -15,6 +15,8 @@
limitations under the License.
-->
<resources>
<!-- Allow users to distinguish between build variants by having a different background color
for the launcher icon. See https://github.com/android/nowinandroid/pull/989. -->
<color name="ic_launcher_background_tint">#000000</color>
<color name="ic_launcher_foreground_tint">#FFA23F16</color>
</resources>

@ -177,7 +177,7 @@ class MainActivity : ComponentActivity() {
To see quick turnaround of the ProfileVerifier, we recommend using `speed-profile`.
If you don't do either of these steps, you might only see the profile status reported as
"enqueued for compilation" when running the sample locally.
*/
*/
withContext(Dispatchers.IO) {
val status = ProfileVerifier.getCompilationStatusAsync().await()
Log.d(TAG, "ProfileInstaller status code: ${status.profileInstallResultCode}")

@ -20,7 +20,7 @@ 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.forYouNavigationRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.FOR_YOU_ROUTE
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.forYouScreen
import com.google.samples.apps.nowinandroid.feature.interests.navigation.interestsGraph
import com.google.samples.apps.nowinandroid.feature.search.navigation.searchScreen
@ -41,7 +41,7 @@ fun NiaNavHost(
appState: NiaAppState,
onShowSnackbar: suspend (String, String?) -> Boolean,
modifier: Modifier = Modifier,
startDestination: String = forYouNavigationRoute,
startDestination: String = FOR_YOU_ROUTE,
) {
val navController = appState.navController
NavHost(

@ -33,11 +33,11 @@ import androidx.tracing.trace
import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.ui.TrackDisposableJank
import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.bookmarksRoute
import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.BOOKMARKS_ROUTE
import com.google.samples.apps.nowinandroid.feature.bookmarks.navigation.navigateToBookmarks
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.forYouNavigationRoute
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.FOR_YOU_ROUTE
import com.google.samples.apps.nowinandroid.feature.foryou.navigation.navigateToForYou
import com.google.samples.apps.nowinandroid.feature.interests.navigation.interestsRoute
import com.google.samples.apps.nowinandroid.feature.interests.navigation.INTERESTS_ROUTE
import com.google.samples.apps.nowinandroid.feature.interests.navigation.navigateToInterestsGraph
import com.google.samples.apps.nowinandroid.feature.search.navigation.navigateToSearch
import com.google.samples.apps.nowinandroid.navigation.TopLevelDestination
@ -91,9 +91,9 @@ class NiaAppState(
val currentTopLevelDestination: TopLevelDestination?
@Composable get() = when (currentDestination?.route) {
forYouNavigationRoute -> FOR_YOU
bookmarksRoute -> BOOKMARKS
interestsRoute -> INTERESTS
FOR_YOU_ROUTE -> FOR_YOU
BOOKMARKS_ROUTE -> BOOKMARKS
INTERESTS_ROUTE -> INTERESTS
else -> null
}

@ -60,7 +60,8 @@ class StartupBenchmark {
packageName = PACKAGE_NAME,
metrics = listOf(StartupTimingMetric()),
compilationMode = compilationMode,
iterations = 20, // More iterations result in higher statistical significance.
// More iterations result in higher statistical significance.
iterations = 20,
startupMode = COLD,
setupBlock = {
pressHome()

@ -35,6 +35,8 @@ abstract class AnalyticsModule {
companion object {
@Provides
@Singleton
fun provideFirebaseAnalytics(): FirebaseAnalytics { return Firebase.analytics }
fun provideFirebaseAnalytics(): FirebaseAnalytics {
return Firebase.analytics
}
}
}

@ -134,7 +134,7 @@ fun NiaOutlinedButton(
MaterialTheme.colorScheme.outline
} else {
MaterialTheme.colorScheme.onSurface.copy(
alpha = NiaButtonDefaults.DisabledOutlinedButtonBorderAlpha,
alpha = NiaButtonDefaults.DISABLED_OUTLINED_BUTTON_BORDER_ALPHA,
)
},
),
@ -278,7 +278,7 @@ fun NiaButtonPreview() {
@ThemePreviews
@Composable
fun NiaOutlinedButtonPreview() {
NiaTheme() {
NiaTheme {
NiaBackground(modifier = Modifier.size(150.dp, 50.dp)) {
NiaOutlinedButton(onClick = {}, text = { Text("Test button") })
}
@ -315,7 +315,7 @@ fun NiaButtonLeadingIconPreview() {
object NiaButtonDefaults {
// TODO: File bug
// OutlinedButton border color doesn't respect disabled state by default
const val DisabledOutlinedButtonBorderAlpha = 0.12f
const val DISABLED_OUTLINED_BUTTON_BORDER_ALPHA = 0.12f
// TODO: File bug
// OutlinedButton default border width isn't exposed via ButtonDefaults

@ -76,10 +76,10 @@ fun NiaFilterChip(
borderColor = MaterialTheme.colorScheme.onBackground,
selectedBorderColor = MaterialTheme.colorScheme.onBackground,
disabledBorderColor = MaterialTheme.colorScheme.onBackground.copy(
alpha = NiaChipDefaults.DisabledChipContentAlpha,
alpha = NiaChipDefaults.DISABLED_CHIP_CONTENT_ALPHA,
),
disabledSelectedBorderColor = MaterialTheme.colorScheme.onBackground.copy(
alpha = NiaChipDefaults.DisabledChipContentAlpha,
alpha = NiaChipDefaults.DISABLED_CHIP_CONTENT_ALPHA,
),
selectedBorderWidth = NiaChipDefaults.ChipBorderWidth,
),
@ -88,16 +88,16 @@ fun NiaFilterChip(
iconColor = MaterialTheme.colorScheme.onBackground,
disabledContainerColor = if (selected) {
MaterialTheme.colorScheme.onBackground.copy(
alpha = NiaChipDefaults.DisabledChipContainerAlpha,
alpha = NiaChipDefaults.DISABLED_CHIP_CONTAINER_ALPHA,
)
} else {
Color.Transparent
},
disabledLabelColor = MaterialTheme.colorScheme.onBackground.copy(
alpha = NiaChipDefaults.DisabledChipContentAlpha,
alpha = NiaChipDefaults.DISABLED_CHIP_CONTENT_ALPHA,
),
disabledLeadingIconColor = MaterialTheme.colorScheme.onBackground.copy(
alpha = NiaChipDefaults.DisabledChipContentAlpha,
alpha = NiaChipDefaults.DISABLED_CHIP_CONTENT_ALPHA,
),
selectedContainerColor = MaterialTheme.colorScheme.primaryContainer,
selectedLabelColor = MaterialTheme.colorScheme.onBackground,
@ -124,7 +124,7 @@ fun ChipPreview() {
object NiaChipDefaults {
// TODO: File bug
// FilterChip default values aren't exposed via FilterChipDefaults
const val DisabledChipContainerAlpha = 0.12f
const val DisabledChipContentAlpha = 0.38f
const val DISABLED_CHIP_CONTAINER_ALPHA = 0.12f
const val DISABLED_CHIP_CONTENT_ALPHA = 0.38f
val ChipBorderWidth = 1.dp
}

@ -60,7 +60,7 @@ fun NiaIconToggleButton(
checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
disabledContainerColor = if (checked) {
MaterialTheme.colorScheme.onBackground.copy(
alpha = NiaIconButtonDefaults.DisabledIconButtonContainerAlpha,
alpha = NiaIconButtonDefaults.DISABLED_ICON_BUTTON_CONTAINER_ALPHA,
)
} else {
Color.Transparent
@ -123,5 +123,5 @@ fun IconButtonPreviewUnchecked() {
object NiaIconButtonDefaults {
// TODO: File bug
// IconToggleButton disabled container alpha not exposed by IconButtonDefaults
const val DisabledIconButtonContainerAlpha = 0.12f
const val DISABLED_ICON_BUTTON_CONTAINER_ALPHA = 0.12f
}

@ -40,7 +40,7 @@ fun NiaTopicTag(
MaterialTheme.colorScheme.primaryContainer
} else {
MaterialTheme.colorScheme.surfaceVariant.copy(
alpha = NiaTagDefaults.UnfollowedTopicTagContainerAlpha,
alpha = NiaTagDefaults.UNFOLLOWED_TOPIC_TAG_CONTAINER_ALPHA,
)
}
TextButton(
@ -50,7 +50,7 @@ fun NiaTopicTag(
containerColor = containerColor,
contentColor = contentColorFor(backgroundColor = containerColor),
disabledContainerColor = MaterialTheme.colorScheme.onSurface.copy(
alpha = NiaTagDefaults.DisabledTopicTagContainerAlpha,
alpha = NiaTagDefaults.DISABLED_TOPIC_TAG_CONTAINER_ALPHA,
),
),
) {
@ -75,9 +75,9 @@ fun TagPreview() {
* Now in Android tag default values.
*/
object NiaTagDefaults {
const val UnfollowedTopicTagContainerAlpha = 0.5f
const val UNFOLLOWED_TOPIC_TAG_CONTAINER_ALPHA = 0.5f
// TODO: File bug
// Button disabled container alpha value not exposed by ButtonDefaults
const val DisabledTopicTagContainerAlpha = 0.12f
const val DISABLED_TOPIC_TAG_CONTAINER_ALPHA = 0.12f
}

@ -251,5 +251,7 @@ private fun scrollbarThumbColor(
}
private enum class ThumbState {
Active, Inactive, Dormant
Active,
Inactive,
Dormant,
}

@ -66,7 +66,7 @@ class LoadingWheelScreenshotTests() {
fun loadingWheelAnimation() {
composeTestRule.mainClock.autoAdvance = false
composeTestRule.setContent {
NiaTheme() {
NiaTheme {
NiaLoadingWheel(contentDesc = "")
}
}

@ -17,5 +17,7 @@
package com.google.samples.apps.nowinandroid.core.model.data
enum class DarkThemeConfig {
FOLLOW_SYSTEM, LIGHT, DARK
FOLLOW_SYSTEM,
LIGHT,
DARK,
}

@ -19,7 +19,8 @@ package com.google.samples.apps.nowinandroid.core.model.data
/**
* A [topic] with the additional information for whether or not it is followed.
*/
data class FollowableTopic( // TODO consider changing to UserTopic and flattening
// TODO consider changing to UserTopic and flattening
data class FollowableTopic(
val topic: Topic,
val isFollowed: Boolean,
)

@ -17,5 +17,6 @@
package com.google.samples.apps.nowinandroid.core.model.data
enum class ThemeBrand {
DEFAULT, ANDROID
DEFAULT,
ANDROID,
}

@ -44,10 +44,10 @@ class FakeNiaNetworkDataSourceTest {
)
}
@Suppress("ktlint:standard:max-line-length")
@Test
fun testDeserializationOfTopics() = runTest(testDispatcher) {
assertEquals(
/* ktlint-disable max-line-length */
NetworkTopic(
id = "1",
name = "Headlines",
@ -56,15 +56,14 @@ class FakeNiaNetworkDataSourceTest {
url = "",
imageUrl = "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Headlines.svg?alt=media&token=506faab0-617a-4668-9e63-4a2fb996603f",
),
/* ktlint-enable max-line-length */
subject.getTopics().first(),
)
}
@Suppress("ktlint:standard:max-line-length")
@Test
fun testDeserializationOfNewsResources() = runTest(testDispatcher) {
assertEquals(
/* ktlint-disable max-line-length */
NetworkNewsResource(
id = "125",
title = "Android Basics with Compose",
@ -83,7 +82,6 @@ class FakeNiaNetworkDataSourceTest {
type = "Codelab",
topics = listOf("2", "3", "10"),
),
/* ktlint-enable max-line-length */
subject.getNewsResources().find { it.id == "125" },
)
}

@ -14,12 +14,13 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.core.testing.data
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.Topic
/* ktlint-disable max-line-length */
val followableTopicTestData: List<FollowableTopic> = listOf(
FollowableTopic(
topic = Topic(

@ -14,12 +14,13 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.core.testing.data
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import kotlinx.datetime.Instant
/* ktlint-disable max-line-length */
val newsResourcesTestData: List<NewsResource> = listOf(
NewsResource(
id = "1",

@ -14,11 +14,12 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.core.testing.data
import com.google.samples.apps.nowinandroid.core.model.data.Topic
/* ktlint-disable max-line-length */
val topicsTestData: List<Topic> = listOf(
Topic(
id = "2",

@ -14,6 +14,8 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.core.testing.data
import com.google.samples.apps.nowinandroid.core.model.data.DarkThemeConfig
@ -26,7 +28,6 @@ import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
/* ktlint-disable max-line-length */
val userNewsResourcesTestData: List<UserNewsResource> = UserData(
bookmarkedNewsResources = setOf("1", "4"),
viewedNewsResources = setOf("1", "2", "4"),

@ -38,8 +38,10 @@ import org.robolectric.RuntimeEnvironment
val DefaultRoborazziOptions =
RoborazziOptions(
compareOptions = CompareOptions(changeThreshold = 0f), // Pixel-perfect matching
recordOptions = RecordOptions(resizeScale = 0.5), // Reduce the size of the PNGs
// Pixel-perfect matching
compareOptions = CompareOptions(changeThreshold = 0f),
// Reduce the size of the PNGs
recordOptions = RecordOptions(resizeScale = 0.5),
)
enum class DefaultTestDevices(val description: String, val spec: String) {

@ -14,13 +14,14 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.core.ui
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.Topic
/* ktlint-disable max-line-length */
/**
* This [PreviewParameterProvider](https://developer.android.com/reference/kotlin/androidx/compose/ui/tooling/preview/PreviewParameterProvider)
* provides list of [FollowableTopic] for Composable previews.

@ -186,7 +186,8 @@ fun NewsResourceHeaderImage(
painterResource(drawable.ic_placeholder_default)
},
// TODO b/226661685: Investigate using alt text of image to populate content description
contentDescription = null, // decorative image,
// decorative image,
contentDescription = null,
)
}
}
@ -295,7 +296,8 @@ fun NewsResourceTopics(
modifier: Modifier = Modifier,
) {
Row(
modifier = modifier.horizontalScroll(rememberScrollState()), // causes narrow chips
// causes narrow chips
modifier = modifier.horizontalScroll(rememberScrollState()),
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
for (followableTopic in topics) {

@ -14,6 +14,8 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.core.ui
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -29,7 +31,6 @@ import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
/* ktlint-disable max-line-length */
/**
* This [PreviewParameterProvider](https://developer.android.com/reference/kotlin/androidx/compose/ui/tooling/preview/PreviewParameterProvider)
* provides list of [UserNewsResource] for Composable previews.

@ -22,17 +22,17 @@ import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.google.samples.apps.nowinandroid.feature.bookmarks.BookmarksRoute
const val bookmarksRoute = "bookmarks_route"
const val BOOKMARKS_ROUTE = "bookmarks_route"
fun NavController.navigateToBookmarks(navOptions: NavOptions) {
this.navigate(bookmarksRoute, navOptions)
this.navigate(BOOKMARKS_ROUTE, navOptions)
}
fun NavGraphBuilder.bookmarksScreen(
onTopicClick: (String) -> Unit,
onShowSnackbar: suspend (String, String?) -> Boolean,
) {
composable(route = bookmarksRoute) {
composable(route = BOOKMARKS_ROUTE) {
BookmarksRoute(onTopicClick, onShowSnackbar)
}
}

@ -437,7 +437,8 @@ fun TopicIcon(
DynamicAsyncImage(
placeholder = painterResource(R.drawable.ic_icon_placeholder),
imageUrl = imageUrl,
contentDescription = null, // decorative
// decorative
contentDescription = null,
modifier = modifier
.padding(10.dp)
.size(32.dp),

@ -26,17 +26,17 @@ import androidx.navigation.navDeepLink
import com.google.samples.apps.nowinandroid.feature.foryou.ForYouRoute
const val LINKED_NEWS_RESOURCE_ID = "linkedNewsResourceId"
const val forYouNavigationRoute = "for_you_route/{$LINKED_NEWS_RESOURCE_ID}"
const val FOR_YOU_ROUTE = "for_you_route/{$LINKED_NEWS_RESOURCE_ID}"
private const val DEEP_LINK_URI_PATTERN =
"https://www.nowinandroid.apps.samples.google.com/foryou/{$LINKED_NEWS_RESOURCE_ID}"
fun NavController.navigateToForYou(navOptions: NavOptions) {
this.navigate(forYouNavigationRoute, navOptions)
this.navigate(FOR_YOU_ROUTE, navOptions)
}
fun NavGraphBuilder.forYouScreen(onTopicClick: (String) -> Unit) {
composable(
route = forYouNavigationRoute,
route = FOR_YOU_ROUTE,
deepLinks = listOf(
navDeepLink { uriPattern = DEEP_LINK_URI_PATTERN },
),

@ -99,7 +99,8 @@ private fun InterestsIcon(topicImageUrl: String, modifier: Modifier = Modifier)
.background(MaterialTheme.colorScheme.surface)
.padding(4.dp),
imageVector = NiaIcons.Person,
contentDescription = null, // decorative image
// decorative image
contentDescription = null,
)
} else {
DynamicAsyncImage(

@ -24,7 +24,7 @@ import androidx.navigation.navigation
import com.google.samples.apps.nowinandroid.feature.interests.InterestsRoute
private const val INTERESTS_GRAPH_ROUTE_PATTERN = "interests_graph"
const val interestsRoute = "interests_route"
const val INTERESTS_ROUTE = "interests_route"
fun NavController.navigateToInterestsGraph(navOptions: NavOptions) {
this.navigate(INTERESTS_GRAPH_ROUTE_PATTERN, navOptions)
@ -36,9 +36,9 @@ fun NavGraphBuilder.interestsGraph(
) {
navigation(
route = INTERESTS_GRAPH_ROUTE_PATTERN,
startDestination = interestsRoute,
startDestination = INTERESTS_ROUTE,
) {
composable(route = interestsRoute) {
composable(route = INTERESTS_ROUTE) {
InterestsRoute(onTopicClick)
}
nestedGraphs()

@ -326,7 +326,8 @@ private fun SearchResultBody(
topics.forEach { followableTopic ->
val topicId = followableTopic.topic.id
item(
key = "topic-$topicId", // Append a prefix to distinguish a key for news resources
// Append a prefix to distinguish a key for news resources
key = "topic-$topicId",
span = StaggeredGridItemSpan.FullLine,
) {
InterestsItem(

@ -14,6 +14,8 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.feature.search
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
@ -21,7 +23,6 @@ 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
/* ktlint-disable max-line-length */
/**
* This [PreviewParameterProvider](https://developer.android.com/reference/kotlin/androidx/compose/ui/tooling/preview/PreviewParameterProvider)
* provides list of [SearchResultUiState] for Composable previews.

@ -22,10 +22,10 @@ import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.google.samples.apps.nowinandroid.feature.search.SearchRoute
const val searchRoute = "search_route"
const val SEARCH_ROUTE = "search_route"
fun NavController.navigateToSearch(navOptions: NavOptions? = null) {
this.navigate(searchRoute, navOptions)
this.navigate(SEARCH_ROUTE, navOptions)
}
fun NavGraphBuilder.searchScreen(
@ -35,7 +35,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(route = searchRoute) {
composable(route = SEARCH_ROUTE) {
SearchRoute(
onBackClick = onBackClick,
onInterestsClick = onInterestsClick,

@ -14,6 +14,8 @@
* limitations under the License.
*/
@file:Suppress("ktlint:standard:max-line-length")
package com.google.samples.apps.nowinandroid.feature.settings
import android.content.Intent
@ -316,7 +318,6 @@ private fun PreviewSettingsDialogLoading() {
}
}
/* ktlint-disable max-line-length */
private const val PRIVACY_POLICY_URL = "https://policies.google.com/privacy"
private const val BRAND_GUIDELINES_URL = "https://developer.android.com/distribute/marketing-tools/brand-guidelines"
private const val FEEDBACK_URL = "https://goo.gle/nia-app-feedback"

@ -31,11 +31,11 @@ import kotlin.text.Charsets.UTF_8
private val URL_CHARACTER_ENCODING = UTF_8.name()
@VisibleForTesting
internal const val topicIdArg = "topicId"
internal const val TOPIC_ID_ARG = "topicId"
internal class TopicArgs(val topicId: String) {
constructor(savedStateHandle: SavedStateHandle) :
this(URLDecoder.decode(checkNotNull(savedStateHandle[topicIdArg]), URL_CHARACTER_ENCODING))
this(URLDecoder.decode(checkNotNull(savedStateHandle[TOPIC_ID_ARG]), URL_CHARACTER_ENCODING))
}
fun NavController.navigateToTopic(topicId: String) {
@ -50,9 +50,9 @@ fun NavGraphBuilder.topicScreen(
onTopicClick: (String) -> Unit,
) {
composable(
route = "topic_route/{$topicIdArg}",
route = "topic_route/{$TOPIC_ID_ARG}",
arguments = listOf(
navArgument(topicIdArg) { type = NavType.StringType },
navArgument(TOPIC_ID_ARG) { type = NavType.StringType },
),
) {
TopicRoute(onBackClick = onBackClick, onTopicClick = onTopicClick)

@ -25,7 +25,7 @@ import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepo
import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
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.topic.navigation.topicIdArg
import com.google.samples.apps.nowinandroid.feature.topic.navigation.TOPIC_ID_ARG
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
@ -60,7 +60,7 @@ class TopicViewModelTest {
@Before
fun setup() {
viewModel = TopicViewModel(
savedStateHandle = SavedStateHandle(mapOf(topicIdArg to testInputTopics[0].topic.id)),
savedStateHandle = SavedStateHandle(mapOf(TOPIC_ID_ARG to testInputTopics[0].topic.id)),
userDataRepository = userDataRepository,
topicsRepository = topicsRepository,
userNewsResourceRepository = userNewsResourceRepository,

@ -14,10 +14,10 @@
* limitations under the License.
*/
val ktlintVersion = "0.48.1"
val ktlintVersion = "1.0.1"
initscript {
val spotlessVersion = "6.22.0"
val spotlessVersion = "6.23.3"
repositories {
mavenCentral()
@ -35,7 +35,11 @@ rootProject {
kotlin {
target("**/*.kt")
targetExclude("**/build/**/*.kt")
ktlint(ktlintVersion).userData(mapOf("android" to "true"))
ktlint(ktlintVersion).editorConfigOverride(
mapOf(
"android" to "true",
),
)
licenseHeaderFile(rootProject.file("spotless/copyright.kt"))
}
format("kts") {

@ -29,7 +29,7 @@ androidxTestRunner = "1.5.2"
androidxTracing = "1.1.0"
androidxUiAutomator = "2.2.0"
androidxWindowManager = "1.2.0"
androidxWork = "2.9.0-rc01"
androidxWork = "2.9.0"
coil = "2.5.0"
dependencyGuard = "0.4.3"
firebaseBom = "32.4.0"
@ -152,7 +152,7 @@ firebase-crashlytics-gradlePlugin = { group = "com.google.firebase", name = "fir
firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" }
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" }
work-testing = { group = "androidx.work", name = "work-testing", version = "2.8.1" }
work-testing = { group = "androidx.work", name = "work-testing", version = "2.9.0" }
[plugins]
android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }

@ -28,7 +28,7 @@ object Sync {
WorkManager.getInstance(context).apply {
// Run sync on app startup and ensure only one sync worker runs at any time
enqueueUniqueWork(
SyncWorkName,
SYNC_WORK_NAME,
ExistingWorkPolicy.KEEP,
SyncWorker.startUpSyncWork(),
)
@ -37,4 +37,4 @@ object Sync {
}
// This name should not be changed otherwise the app may have concurrent sync requests running
internal const val SyncWorkName = "SyncWorkName"
internal const val SYNC_WORK_NAME = "SyncWorkName"

@ -22,7 +22,7 @@ import androidx.work.WorkInfo
import androidx.work.WorkInfo.State
import androidx.work.WorkManager
import com.google.samples.apps.nowinandroid.core.data.util.SyncManager
import com.google.samples.apps.nowinandroid.sync.initializers.SyncWorkName
import com.google.samples.apps.nowinandroid.sync.initializers.SYNC_WORK_NAME
import com.google.samples.apps.nowinandroid.sync.workers.SyncWorker
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
@ -37,7 +37,7 @@ class WorkManagerSyncManager @Inject constructor(
@ApplicationContext private val context: Context,
) : SyncManager {
override val isSyncing: Flow<Boolean> =
WorkManager.getInstance(context).getWorkInfosForUniqueWorkFlow(SyncWorkName)
WorkManager.getInstance(context).getWorkInfosForUniqueWorkFlow(SYNC_WORK_NAME)
.map(List<WorkInfo>::anyRunning)
.conflate()
@ -45,7 +45,7 @@ class WorkManagerSyncManager @Inject constructor(
val workManager = WorkManager.getInstance(context)
// Run sync on app startup and ensure only one sync worker runs at any time
workManager.enqueueUniqueWork(
SyncWorkName,
SYNC_WORK_NAME,
ExistingWorkPolicy.KEEP,
SyncWorker.startUpSyncWork(),
)

Loading…
Cancel
Save