pull/1787/merge
Yuki Hamada 3 days ago committed by GitHub
commit b2d90f7f2f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -183,7 +183,7 @@ class NiaAppState(
* Stores information about navigation events to be used with JankStats * Stores information about navigation events to be used with JankStats
*/ */
@Composable @Composable
private fun NavigationTrackingSideEffect(navController: NavHostController) { internal fun NavigationTrackingSideEffect(navController: NavHostController) {
TrackDisposableJank(navController) { metricsHolder -> TrackDisposableJank(navController) { metricsHolder ->
val listener = NavController.OnDestinationChangedListener { _, destination, _ -> val listener = NavController.OnDestinationChangedListener { _, destination, _ ->
metricsHolder.state?.putState("Navigation", destination.route.toString()) metricsHolder.state?.putState("Navigation", destination.route.toString())

@ -16,6 +16,7 @@
import com.android.build.api.dsl.ApplicationExtension import com.android.build.api.dsl.ApplicationExtension
import com.google.samples.apps.nowinandroid.configureAndroidCompose import com.google.samples.apps.nowinandroid.configureAndroidCompose
import com.google.samples.apps.nowinandroid.configureAndroidComposeScreenshotTest
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.apply
@ -26,9 +27,11 @@ class AndroidApplicationComposeConventionPlugin : Plugin<Project> {
with(target) { with(target) {
apply(plugin = "com.android.application") apply(plugin = "com.android.application")
apply(plugin = "org.jetbrains.kotlin.plugin.compose") apply(plugin = "org.jetbrains.kotlin.plugin.compose")
apply(plugin = "com.android.compose.screenshot")
val extension = extensions.getByType<ApplicationExtension>() val extension = extensions.getByType<ApplicationExtension>()
configureAndroidCompose(extension) configureAndroidCompose(extension)
configureAndroidComposeScreenshotTest(extension)
} }
} }

@ -16,6 +16,7 @@
import com.android.build.api.dsl.LibraryExtension import com.android.build.api.dsl.LibraryExtension
import com.google.samples.apps.nowinandroid.configureAndroidCompose import com.google.samples.apps.nowinandroid.configureAndroidCompose
import com.google.samples.apps.nowinandroid.configureAndroidComposeScreenshotTest
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.apply
@ -26,9 +27,11 @@ class AndroidLibraryComposeConventionPlugin : Plugin<Project> {
with(target) { with(target) {
apply(plugin = "com.android.library") apply(plugin = "com.android.library")
apply(plugin = "org.jetbrains.kotlin.plugin.compose") apply(plugin = "org.jetbrains.kotlin.plugin.compose")
apply(plugin = "com.android.compose.screenshot")
val extension = extensions.getByType<LibraryExtension>() val extension = extensions.getByType<LibraryExtension>()
configureAndroidCompose(extension) configureAndroidCompose(extension)
configureAndroidComposeScreenshotTest(extension)
} }
} }

@ -0,0 +1,31 @@
/*
* 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
import com.android.build.api.dsl.CommonExtension
import org.gradle.api.Project
/**
* Configure project to enable compose screenshot test.
*/
internal fun Project.configureAndroidComposeScreenshotTest(
commonExtension: CommonExtension<*, *, *, *, *, *>,
) {
commonExtension.apply {
experimentalProperties["android.experimental.enableScreenshotTest"] = true
}
}

@ -27,6 +27,7 @@ plugins {
alias(libs.plugins.android.test) apply false alias(libs.plugins.android.test) apply false
alias(libs.plugins.baselineprofile) apply false alias(libs.plugins.baselineprofile) apply false
alias(libs.plugins.compose) apply false alias(libs.plugins.compose) apply false
alias(libs.plugins.compose.screenshot.test) apply false
alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.kotlin.serialization) apply false
alias(libs.plugins.dependencyGuard) apply false alias(libs.plugins.dependencyGuard) apply false

@ -19,7 +19,6 @@ package com.google.samples.apps.nowinandroid.core.designsystem.component
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.LocalAbsoluteTonalElevation import androidx.compose.material3.LocalAbsoluteTonalElevation
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -37,7 +36,6 @@ import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors import com.google.samples.apps.nowinandroid.core.designsystem.theme.GradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalBackgroundTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalBackgroundTheme
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalGradientColors
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import kotlin.math.tan import kotlin.math.tan
/** /**
@ -146,51 +144,3 @@ fun NiaGradientBackground(
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Light theme") @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Light theme")
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark theme") @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark theme")
annotation class ThemePreviews annotation class ThemePreviews
@ThemePreviews
@Composable
fun BackgroundDefault() {
NiaTheme(disableDynamicTheming = true) {
NiaBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun BackgroundDynamic() {
NiaTheme(disableDynamicTheming = false) {
NiaBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun BackgroundAndroid() {
NiaTheme(androidTheme = true) {
NiaBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun GradientBackgroundDefault() {
NiaTheme(disableDynamicTheming = true) {
NiaGradientBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun GradientBackgroundDynamic() {
NiaTheme(disableDynamicTheming = false) {
NiaGradientBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun GradientBackgroundAndroid() {
NiaTheme(androidTheme = true) {
NiaGradientBackground(Modifier.size(100.dp), content = {})
}
}

@ -242,7 +242,7 @@ fun NiaTextButton(
* @param leadingIcon The button leading icon content. Default is `null` for no leading icon.Ï * @param leadingIcon The button leading icon content. Default is `null` for no leading icon.Ï
*/ */
@Composable @Composable
private fun NiaButtonContent( internal fun NiaButtonContent(
text: @Composable () -> Unit, text: @Composable () -> Unit,
leadingIcon: @Composable (() -> Unit)? = null, leadingIcon: @Composable (() -> Unit)? = null,
) { ) {

@ -32,9 +32,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -73,18 +70,3 @@ fun NiaTopAppBar(
modifier = modifier.testTag("niaTopAppBar"), modifier = modifier.testTag("niaTopAppBar"),
) )
} }
@OptIn(ExperimentalMaterial3Api::class)
@Preview("Top App Bar")
@Composable
private fun NiaTopAppBarPreview() {
NiaTheme {
NiaTopAppBar(
titleRes = android.R.string.untitled,
navigationIcon = NiaIcons.Search,
navigationIconContentDescription = "Navigation icon",
actionIcon = NiaIcons.MoreVert,
actionIconContentDescription = "Action icon",
)
}
}

@ -24,15 +24,11 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProvideTextStyle import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
/** /**
* Now in Android view toggle button with included trailing icon as well as compact and expanded * Now in Android view toggle button with included trailing icon as well as compact and expanded
@ -84,7 +80,7 @@ fun NiaViewToggleButton(
* @param trailingIcon The button trailing icon content. Default is `null` for no trailing icon. * @param trailingIcon The button trailing icon content. Default is `null` for no trailing icon.
*/ */
@Composable @Composable
private fun NiaViewToggleButtonContent( internal fun NiaViewToggleButtonContent(
text: @Composable () -> Unit, text: @Composable () -> Unit,
trailingIcon: @Composable (() -> Unit)? = null, trailingIcon: @Composable (() -> Unit)? = null,
) { ) {
@ -109,36 +105,6 @@ private fun NiaViewToggleButtonContent(
} }
} }
@ThemePreviews
@Composable
fun ViewTogglePreviewExpanded() {
NiaTheme {
Surface {
NiaViewToggleButton(
expanded = true,
onExpandedChange = { },
compactText = { Text(text = "Compact view") },
expandedText = { Text(text = "Expanded view") },
)
}
}
}
@Preview
@Composable
fun ViewTogglePreviewCompact() {
NiaTheme {
Surface {
NiaViewToggleButton(
expanded = false,
onExpandedChange = { },
compactText = { Text(text = "Compact view") },
expandedText = { Text(text = "Expanded view") },
)
}
}
}
/** /**
* Now in Android view toggle default values. * Now in Android view toggle default values.
*/ */

@ -128,7 +128,7 @@ fun ScrollableState.DecorativeScrollbar(
* A scrollbar thumb that is intended to also be a touch target for fast scrolling. * A scrollbar thumb that is intended to also be a touch target for fast scrolling.
*/ */
@Composable @Composable
private fun ScrollableState.DraggableScrollbarThumb( internal fun ScrollableState.DraggableScrollbarThumb(
interactionSource: InteractionSource, interactionSource: InteractionSource,
orientation: Orientation, orientation: Orientation,
) { ) {
@ -148,7 +148,7 @@ private fun ScrollableState.DraggableScrollbarThumb(
* A decorative scrollbar thumb used solely for communicating a user's position in a list. * A decorative scrollbar thumb used solely for communicating a user's position in a list.
*/ */
@Composable @Composable
private fun ScrollableState.DecorativeScrollbarThumb( internal fun ScrollableState.DecorativeScrollbarThumb(
interactionSource: InteractionSource, interactionSource: InteractionSource,
orientation: Orientation, orientation: Orientation,
) { ) {
@ -168,7 +168,7 @@ private fun ScrollableState.DecorativeScrollbarThumb(
// remove when project is upgraded // remove when project is upgraded
@SuppressLint("ComposableModifierFactory") @SuppressLint("ComposableModifierFactory")
@Composable @Composable
private fun Modifier.scrollThumb( internal fun Modifier.scrollThumb(
scrollableState: ScrollableState, scrollableState: ScrollableState,
interactionSource: InteractionSource, interactionSource: InteractionSource,
): Modifier { ): Modifier {
@ -214,7 +214,7 @@ private class ScrollThumbNode(var colorProducer: ColorProducer) : DrawModifierNo
* @param interactionSource source of interactions in the scrolling container * @param interactionSource source of interactions in the scrolling container
*/ */
@Composable @Composable
private fun scrollbarThumbColor( internal fun scrollbarThumbColor(
scrollableState: ScrollableState, scrollableState: ScrollableState,
interactionSource: InteractionSource, interactionSource: InteractionSource,
): State<Color> { ): State<Color> {

@ -71,7 +71,7 @@ fun LazyStaggeredGridState.rememberDraggableScroller(
* @param scroll a function to be invoked when an index has been identified to scroll to. * @param scroll a function to be invoked when an index has been identified to scroll to.
*/ */
@Composable @Composable
private inline fun rememberDraggableScroller( internal inline fun rememberDraggableScroller(
itemsAvailable: Int, itemsAvailable: Int,
crossinline scroll: suspend (index: Int) -> Unit, crossinline scroll: suspend (index: Int) -> Unit,
): (Float) -> Unit { ): (Float) -> Unit {

@ -0,0 +1,71 @@
/*
* 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.core.designsystem.component
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
@ThemePreviews
@Composable
fun BackgroundDefault() {
NiaTheme(disableDynamicTheming = true) {
NiaBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun BackgroundDynamic() {
NiaTheme(disableDynamicTheming = false) {
NiaBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun BackgroundAndroid() {
NiaTheme(androidTheme = true) {
NiaBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun GradientBackgroundDefault() {
NiaTheme(disableDynamicTheming = true) {
NiaGradientBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun GradientBackgroundDynamic() {
NiaTheme(disableDynamicTheming = false) {
NiaGradientBackground(Modifier.size(100.dp), content = {})
}
}
@ThemePreviews
@Composable
fun GradientBackgroundAndroid() {
NiaTheme(androidTheme = true) {
NiaGradientBackground(Modifier.size(100.dp), content = {})
}
}

@ -0,0 +1,37 @@
/*
* 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.core.designsystem.component
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
@OptIn(ExperimentalMaterial3Api::class)
@Preview("Top App Bar")
@Composable
fun NiaTopAppBarPreview() {
NiaTheme {
NiaTopAppBar(
titleRes = android.R.string.untitled,
navigationIcon = NiaIcons.Search,
navigationIconContentDescription = "Navigation icon",
actionIcon = NiaIcons.MoreVert,
actionIconContentDescription = "Action icon",
)
}
}

@ -0,0 +1,52 @@
/*
* 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.core.designsystem.component
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
@ThemePreviews
@Composable
fun ViewTogglePreviewExpanded() {
NiaTheme {
Surface {
NiaViewToggleButton(
expanded = true,
onExpandedChange = { },
compactText = { Text(text = "Compact view") },
expandedText = { Text(text = "Expanded view") },
)
}
}
}
@Preview
@Composable
fun ViewTogglePreviewCompact() {
NiaTheme {
Surface {
NiaViewToggleButton(
expanded = false,
onExpandedChange = { },
compactText = { Text(text = "Compact view") },
expandedText = { Text(text = "Expanded view") },
)
}
}
}

@ -228,7 +228,7 @@ fun <A : ComponentActivity> AndroidComposeTestRule<ActivityScenarioRule<A>, A>.c
} }
@Composable @Composable
private fun generateDescription( internal fun generateDescription(
shouldCompareDarkMode: Boolean, shouldCompareDarkMode: Boolean,
darkMode: Boolean, darkMode: Boolean,
shouldCompareAndroidTheme: Boolean, shouldCompareAndroidTheme: Boolean,

@ -24,7 +24,6 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -32,12 +31,10 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.selected import androidx.compose.ui.semantics.selected
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.component.DynamicAsyncImage import com.google.samples.apps.nowinandroid.core.designsystem.component.DynamicAsyncImage
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.ui.R.string import com.google.samples.apps.nowinandroid.core.ui.R.string
@Composable @Composable
@ -100,7 +97,7 @@ fun InterestsItem(
} }
@Composable @Composable
private fun InterestsIcon(topicImageUrl: String, modifier: Modifier = Modifier) { internal fun InterestsIcon(topicImageUrl: String, modifier: Modifier = Modifier) {
if (topicImageUrl.isEmpty()) { if (topicImageUrl.isEmpty()) {
Icon( Icon(
modifier = modifier modifier = modifier
@ -118,90 +115,3 @@ private fun InterestsIcon(topicImageUrl: String, modifier: Modifier = Modifier)
) )
} }
} }
@Preview
@Composable
private fun InterestsCardPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "Description",
following = false,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
private fun InterestsCardLongNamePreview() {
NiaTheme {
Surface {
InterestsItem(
name = "This is a very very very very long name",
description = "Description",
following = true,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
private fun InterestsCardLongDescriptionPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "This is a very very very very very very very " +
"very very very long description",
following = false,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
private fun InterestsCardWithEmptyDescriptionPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "",
following = true,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
private fun InterestsCardSelectedPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "",
following = true,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
isSelected = true,
)
}
}
}

@ -24,20 +24,13 @@ import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridScope import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridScope
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.items import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.analytics.LocalAnalyticsHelper import com.google.samples.apps.nowinandroid.core.analytics.LocalAnalyticsHelper
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
/** /**
@ -121,37 +114,3 @@ sealed interface NewsFeedUiState {
val feed: List<UserNewsResource>, val feed: List<UserNewsResource>,
) : NewsFeedUiState ) : NewsFeedUiState
} }
@Preview
@Composable
private fun NewsFeedLoadingPreview() {
NiaTheme {
LazyVerticalStaggeredGrid(columns = StaggeredGridCells.Adaptive(300.dp)) {
newsFeed(
feedState = NewsFeedUiState.Loading,
onNewsResourcesCheckedChanged = { _, _ -> },
onNewsResourceViewed = {},
onTopicClick = {},
)
}
}
}
@Preview
@Preview(device = Devices.TABLET)
@Composable
private fun NewsFeedContentPreview(
@PreviewParameter(UserNewsResourcePreviewParameterProvider::class)
userNewsResources: List<UserNewsResource>,
) {
NiaTheme {
LazyVerticalStaggeredGrid(columns = StaggeredGridCells.Adaptive(300.dp)) {
newsFeed(
feedState = NewsFeedUiState.Success(userNewsResources),
onNewsResourcesCheckedChanged = { _, _ -> },
onNewsResourceViewed = {},
onTopicClick = {},
)
}
}
}

@ -41,10 +41,8 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -61,8 +59,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import coil.compose.AsyncImagePainter import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter import coil.compose.rememberAsyncImagePainter
@ -70,7 +66,6 @@ import com.google.samples.apps.nowinandroid.core.designsystem.R.drawable
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaIconToggleButton
import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag import com.google.samples.apps.nowinandroid.core.designsystem.component.NiaTopicTag
import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.designsystem.icon.NiaIcons
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
@ -343,47 +338,3 @@ fun NewsResourceTopics(
} }
} }
} }
@Preview("Bookmark Button")
@Composable
private fun BookmarkButtonPreview() {
NiaTheme {
Surface {
BookmarkButton(isBookmarked = false, onClick = { })
}
}
}
@Preview("Bookmark Button Bookmarked")
@Composable
private fun BookmarkButtonBookmarkedPreview() {
NiaTheme {
Surface {
BookmarkButton(isBookmarked = true, onClick = { })
}
}
}
@Preview("NewsResourceCardExpanded")
@Composable
private fun ExpandedNewsResourcePreview(
@PreviewParameter(UserNewsResourcePreviewParameterProvider::class)
userNewsResources: List<UserNewsResource>,
) {
CompositionLocalProvider(
LocalInspectionMode provides true,
) {
NiaTheme {
Surface {
NewsResourceCardExpanded(
userNewsResource = userNewsResources[0],
isBookmarked = true,
hasBeenViewed = false,
onToggleBookmark = {},
onClick = {},
onTopicClick = {},
)
}
}
}
}

@ -0,0 +1,108 @@
/*
* 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.core.ui
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
@Preview
@Composable
fun InterestsCardPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "Description",
following = false,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
fun InterestsCardLongNamePreview() {
NiaTheme {
Surface {
InterestsItem(
name = "This is a very very very very long name",
description = "Description",
following = true,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
fun InterestsCardLongDescriptionPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "This is a very very very very very very very " +
"very very very long description",
following = false,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
fun InterestsCardWithEmptyDescriptionPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "",
following = true,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
)
}
}
}
@Preview
@Composable
fun InterestsCardSelectedPreview() {
NiaTheme {
Surface {
InterestsItem(
name = "Compose",
description = "",
following = true,
topicImageUrl = "",
onClick = { },
onFollowButtonClick = { },
isSelected = true,
)
}
}
}

@ -0,0 +1,60 @@
/*
* 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.core.ui
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
@Preview
@Composable
fun NewsFeedLoadingPreview() {
NiaTheme {
LazyVerticalStaggeredGrid(columns = StaggeredGridCells.Adaptive(300.dp)) {
newsFeed(
feedState = NewsFeedUiState.Loading,
onNewsResourcesCheckedChanged = { _, _ -> },
onNewsResourceViewed = {},
onTopicClick = {},
)
}
}
}
@Preview
@Preview(device = Devices.TABLET)
@Composable
fun NewsFeedContentPreview(
@PreviewParameter(UserNewsResourcePreviewParameterProvider::class)
userNewsResources: List<UserNewsResource>,
) {
NiaTheme {
LazyVerticalStaggeredGrid(columns = StaggeredGridCells.Adaptive(300.dp)) {
newsFeed(
feedState = NewsFeedUiState.Success(userNewsResources),
onNewsResourcesCheckedChanged = { _, _ -> },
onNewsResourceViewed = {},
onTopicClick = {},
)
}
}
}

@ -0,0 +1,72 @@
/*
* 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.core.ui
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
@Preview("Bookmark Button")
@Composable
fun BookmarkButtonPreview() {
NiaTheme {
Surface {
BookmarkButton(isBookmarked = false, onClick = { })
}
}
}
@Preview("Bookmark Button Bookmarked")
@Composable
fun BookmarkButtonBookmarkedPreview() {
NiaTheme {
Surface {
BookmarkButton(isBookmarked = true, onClick = { })
}
}
}
@Preview("NewsResourceCardExpanded")
@Composable
fun ExpandedNewsResourcePreview(
@PreviewParameter(UserNewsResourcePreviewParameterProvider::class)
userNewsResources: List<UserNewsResource>,
) {
CompositionLocalProvider(
LocalInspectionMode provides true,
) {
NiaTheme {
Surface {
NewsResourceCardExpanded(
userNewsResource = userNewsResources[0],
isBookmarked = true,
hasBeenViewed = false,
onToggleBookmark = {},
onClick = {},
onTopicClick = {},
)
}
}
}
}

@ -53,8 +53,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@ -65,14 +63,11 @@ import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollba
import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.rememberDraggableScroller import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.rememberDraggableScroller
import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.scrollbarState import com.google.samples.apps.nowinandroid.core.designsystem.component.scrollbar.scrollbarState
import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme import com.google.samples.apps.nowinandroid.core.designsystem.theme.LocalTintTheme
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Loading 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.core.ui.NewsFeedUiState.Success
import com.google.samples.apps.nowinandroid.core.ui.TrackScreenViewEvent 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.TrackScrollJank
import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider
import com.google.samples.apps.nowinandroid.core.ui.newsFeed import com.google.samples.apps.nowinandroid.core.ui.newsFeed
@Composable @Composable
@ -149,7 +144,7 @@ internal fun BookmarksScreen(
} }
@Composable @Composable
private fun LoadingState(modifier: Modifier = Modifier) { internal fun LoadingState(modifier: Modifier = Modifier) {
NiaLoadingWheel( NiaLoadingWheel(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
@ -160,7 +155,7 @@ private fun LoadingState(modifier: Modifier = Modifier) {
} }
@Composable @Composable
private fun BookmarksGrid( internal fun BookmarksGrid(
feedState: NewsFeedUiState, feedState: NewsFeedUiState,
removeFromBookmarks: (String) -> Unit, removeFromBookmarks: (String) -> Unit,
onNewsResourceViewed: (String) -> Unit, onNewsResourceViewed: (String) -> Unit,
@ -216,7 +211,7 @@ private fun BookmarksGrid(
} }
@Composable @Composable
private fun EmptyState(modifier: Modifier = Modifier) { internal fun EmptyState(modifier: Modifier = Modifier) {
Column( Column(
modifier = modifier modifier = modifier
.padding(16.dp) .padding(16.dp)
@ -253,35 +248,3 @@ private fun EmptyState(modifier: Modifier = Modifier) {
) )
} }
} }
@Preview
@Composable
private fun LoadingStatePreview() {
NiaTheme {
LoadingState()
}
}
@Preview
@Composable
private fun BookmarksGridPreview(
@PreviewParameter(UserNewsResourcePreviewParameterProvider::class)
userNewsResources: List<UserNewsResource>,
) {
NiaTheme {
BookmarksGrid(
feedState = Success(userNewsResources),
removeFromBookmarks = {},
onNewsResourceViewed = {},
onTopicClick = {},
)
}
}
@Preview
@Composable
private fun EmptyStatePreview() {
NiaTheme {
EmptyState()
}
}

@ -0,0 +1,57 @@
/*
* 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.feature.bookmarks
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import com.google.samples.apps.nowinandroid.core.designsystem.theme.NiaTheme
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
import com.google.samples.apps.nowinandroid.core.ui.NewsFeedUiState.Success
import com.google.samples.apps.nowinandroid.core.ui.UserNewsResourcePreviewParameterProvider
@Preview
@Composable
fun LoadingStatePreview() {
NiaTheme {
LoadingState()
}
}
@Preview
@Composable
fun BookmarksGridPreview(
@PreviewParameter(UserNewsResourcePreviewParameterProvider::class)
userNewsResources: List<UserNewsResource>,
) {
NiaTheme {
BookmarksGrid(
feedState = Success(userNewsResources),
removeFromBookmarks = {},
onNewsResourceViewed = {},
onTopicClick = {},
)
}
}
@Preview
@Composable
fun EmptyStatePreview() {
NiaTheme {
EmptyState()
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save