diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index 8923296bd..e61626a2d 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 @@ -46,27 +46,37 @@ jobs: - name: Check lint run: ./gradlew lintDebug --stacktrace - - name: Build debug - run: ./gradlew assembleDebug --stacktrace - - - name: Build release - run: ./gradlew assembleRelease --stacktrace + - name: Build all build type and flavor permutations + run: ./gradlew assemble --stacktrace - name: Run local tests - run: ./gradlew testDebug --stacktrace + run: ./gradlew testDemoDebug testProdDebug --stacktrace + + - name: Upload Demo build outputs (APKs) + uses: actions/upload-artifact@v2 + with: + name: build-outputs-demo + path: app/demo/build/outputs - - name: Upload build outputs (APKs) + - name: Upload Prod build outputs (APKs) + uses: actions/upload-artifact@v2 + with: + name: build-outputs-prod + path: app/prod/build/outputs + + - name: Upload Demo build reports + if: always() uses: actions/upload-artifact@v2 with: - name: build-outputs - path: app/build/outputs + name: build-reports-demo + path: app/demo/build/reports - - name: Upload build reports + - name: Upload Prod build reports if: always() uses: actions/upload-artifact@v2 with: - name: build-reports - path: app/build/reports + name: build-reports-prod + path: app/prod/build/reports androidTest: needs: build @@ -78,7 +88,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Copy CI gradle.properties run: mkdir -p ~/.gradle ; cp .github/ci-gradle.properties ~/.gradle/gradle.properties @@ -107,7 +117,7 @@ jobs: disable-animations: true disk-size: 1500M heap-size: 512M - script: ./gradlew connectedAndroidTest -x :benchmark:connectedBenchmarkAndroidTest + script: ./gradlew connectedProdDebugAndroidTest -x :benchmark:connectedBenchmarkAndroidTest - name: Upload test reports if: always() diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index ccaa3dd86..6283809a4 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Validate Gradle Wrapper uses: gradle/wrapper-validation-action@v1 diff --git a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Author.kt b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Author.kt index 519c1fd82..c292d979f 100644 --- a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Author.kt +++ b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Author.kt @@ -16,6 +16,8 @@ package com.google.samples.apps.nowinandroid.core.model.data +/* ktlint-disable max-line-length */ + /** * External data layer representation of an NiA Author */ @@ -27,3 +29,22 @@ data class Author( val mediumPage: String, val bio: String, ) + +val previewAuthors = listOf( + Author( + id = "22", + name = "Alex Vanyo", + mediumPage = "https://medium.com/@alexvanyo", + twitter = "https://twitter.com/alex_vanyo", + imageUrl = "https://pbs.twimg.com/profile_images/1431339735931305989/nOE2mmi2_400x400.jpg", + bio = "Alex joined Android DevRel in 2021, and has worked supporting form factors from small watches to large foldables and tablets. His special interests include insets, Compose, testing and state." + ), + Author( + id = "3", + name = "Simona Stojanovic", + mediumPage = "https://medium.com/@anomisSi", + twitter = "https://twitter.com/anomisSi", + imageUrl = "https://pbs.twimg.com/profile_images/1437506849016778756/pG0NZALw_400x400.jpg", + bio = "Android Developer Relations Engineer @Google, working on the Compose team and taking care of Layouts & Navigation." + ) +) diff --git a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/NewsResource.kt b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/NewsResource.kt index d6faff63a..c75c72ea7 100644 --- a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/NewsResource.kt +++ b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/NewsResource.kt @@ -16,7 +16,13 @@ package com.google.samples.apps.nowinandroid.core.model.data +import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Codelab import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toInstant + +/* ktlint-disable max-line-length */ /** * External data layer representation of a fully populated NiA news resource @@ -33,3 +39,26 @@ data class NewsResource( val authors: List, val topics: List ) + +val previewNewsResources = listOf( + NewsResource( + id = "1", + episodeId = "60", + title = "Android Basics with Compose", + content = "We released the first two units of Android Basics with Compose, our first free course that teaches Android Development with Jetpack Compose to anyone; you do not need any prior programming experience other than basic computer literacy to get started. You’ll learn the fundamentals of programming in Kotlin while building Android apps using Jetpack Compose, Android’s modern toolkit that simplifies and accelerates native UI development. These two units are just the beginning; more will be coming soon. Check out Android Basics with Compose to get started on your Android development journey", + url = "https://android-developers.googleblog.com/2022/05/new-android-basics-with-compose-course.html", + headerImageUrl = "https://developer.android.com/images/hero-assets/android-basics-compose.svg", + authors = listOf(previewAuthors[0]), + publishDate = LocalDateTime( + year = 2022, + monthNumber = 5, + dayOfMonth = 4, + hour = 23, + minute = 0, + second = 0, + nanosecond = 0 + ).toInstant(TimeZone.UTC), + type = Codelab, + topics = listOf(previewTopics[1]) + ) +) diff --git a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt index cc45937b6..16dd4e464 100644 --- a/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt +++ b/core-model/src/main/java/com/google/samples/apps/nowinandroid/core/model/data/Topic.kt @@ -16,6 +16,8 @@ package com.google.samples.apps.nowinandroid.core.model.data +/* ktlint-disable max-line-length */ + /** * External data layer representation of a NiA Topic */ @@ -27,3 +29,30 @@ data class Topic( val url: String, val imageUrl: String, ) + +val previewTopics = listOf( + Topic( + id = "2", + name = "Headlines", + shortDescription = "News we want everyone to see", + longDescription = "Stay up to date with the latest events and announcements from Android!", + 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", + url = "" + ), + Topic( + id = "3", + name = "UI", + shortDescription = "Material Design, Navigation, Text, Paging, Accessibility (a11y), Internationalization (i18n), Localization (l10n), Animations, Large Screens, Widgets", + longDescription = "Learn how to optimize your app's user interface - everything that users can see and interact with. Stay up to date on tocpis such as Material Design, Navigation, Text, Paging, Compose, Accessibility (a11y), Internationalization (i18n), Localization (l10n), Animations, Large Screens, Widgets, and many more!", + imageUrl = "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_UI.svg?alt=media&token=0ee1842b-12e8-435f-87ba-a5bb02c47594", + url = "" + ), + Topic( + id = "4", + name = "Testing", + shortDescription = "CI, Espresso, TestLab, etc", + longDescription = "Testing is an integral part of the app development process. By running tests against your app consistently, you can verify your app's correctness, functional behavior, and usability before you release it publicly. Stay up to date on the latest tricks in CI, Espresso, and Firebase TestLab.", + imageUrl = "https://firebasestorage.googleapis.com/v0/b/now-in-android.appspot.com/o/img%2Fic_topic_Testing.svg?alt=media&token=a11533c4-7cc8-4b11-91a3-806158ebf428", + url = "" + ), +) diff --git a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializer.kt b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializer.kt index fbc526753..4100a956c 100644 --- a/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializer.kt +++ b/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializer.kt @@ -35,5 +35,5 @@ object NewsResourceTypeSerializer : KSerializer { ) override fun serialize(encoder: Encoder, value: NewsResourceType) = - encoder.encodeString(value.name) + encoder.encodeString(value.serializedName) } diff --git a/core-network/src/test/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializerTest.kt b/core-network/src/test/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializerTest.kt index 20d12bc51..c446c7ec3 100644 --- a/core-network/src/test/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializerTest.kt +++ b/core-network/src/test/java/com/google/samples/apps/nowinandroid/core/network/model/util/NewsResourceTypeSerializerTest.kt @@ -94,4 +94,13 @@ class NewsResourceTypeSerializerTest { Json.decodeFromString(NewsResourceTypeSerializer, """"umm"""") ) } + + @Test + fun test_serialize_and_deserialize() { + val json = Json.encodeToString(NewsResourceTypeSerializer, NewsResourceType.Video) + assertEquals( + NewsResourceType.Video, + Json.decodeFromString(NewsResourceTypeSerializer, json) + ) + } } diff --git a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt index d31f988ce..718840d17 100644 --- a/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt +++ b/core-ui/src/main/java/com/google/samples/apps/nowinandroid/core/ui/NewsResourceCard.kt @@ -156,8 +156,14 @@ fun NewsResourceAuthors( if (authors.isNotEmpty()) { // Only display first author for now val author = authors[0] - val authorNameFormatted = - author.name.uppercase(ConfigurationCompat.getLocales(LocalConfiguration.current).get(0)) + + val locale = ConfigurationCompat.getLocales(LocalConfiguration.current).get(0) + + val authorNameFormatted = if (locale != null) { + author.name.uppercase(locale) + } else { + author.name.uppercase() + } val authorImageUrl = author.imageUrl diff --git a/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt b/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt index 75df35202..74c72624d 100644 --- a/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt +++ b/feature-author/src/main/java/com/google/samples/apps/nowinandroid/feature/author/AuthorScreen.kt @@ -17,7 +17,6 @@ package com.google.samples.apps.nowinandroid.feature.author import androidx.annotation.VisibleForTesting -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -53,11 +52,13 @@ import androidx.hilt.navigation.compose.hiltViewModel import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor +import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors +import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources import com.google.samples.apps.nowinandroid.core.ui.LoadingWheel +import com.google.samples.apps.nowinandroid.core.ui.component.NiaBackground import com.google.samples.apps.nowinandroid.core.ui.component.NiaFilterChip import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems -import com.google.samples.apps.nowinandroid.feature.author.AuthorUiState.Loading -import com.google.samples.apps.nowinandroid.feature.author.R.string +import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme @Composable fun AuthorRoute( @@ -76,7 +77,6 @@ fun AuthorRoute( ) } -@OptIn(ExperimentalFoundationApi::class) @VisibleForTesting @Composable internal fun AuthorScreen( @@ -100,11 +100,11 @@ internal fun AuthorScreen( ) } when (authorState) { - Loading -> { + AuthorUiState.Loading -> { item { LoadingWheel( modifier = modifier, - contentDesc = stringResource(id = string.author_loading), + contentDesc = stringResource(id = R.string.author_loading), ) } } @@ -221,29 +221,45 @@ private fun AuthorToolbar( onCheckedChange = onFollowClick, ) { if (selected) { - Text(stringResource(id = string.author_following)) + Text(stringResource(id = R.string.author_following)) } else { - Text(stringResource(id = string.author_not_following)) + Text(stringResource(id = R.string.author_not_following)) } } } } -@Preview +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") @Composable -private fun AuthorBodyPreview() { - MaterialTheme { - LazyColumn { - authorBody( - author = Author( - id = "0", - name = "Android Dev", - bio = "Works on Compose", - twitter = "dev", - mediumPage = "", - imageUrl = "", - ), - news = NewsUiState.Success(emptyList()) +fun AuthorScreenPopulated() { + NiaTheme { + NiaBackground { + AuthorScreen( + authorState = AuthorUiState.Success(FollowableAuthor(previewAuthors[0], false)), + newsState = NewsUiState.Success(previewNewsResources), + onBackClick = {}, + onFollowClick = {} + ) + } + } +} + +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Composable +fun AuthorScreenLoading() { + NiaTheme { + NiaBackground { + AuthorScreen( + authorState = AuthorUiState.Loading, + newsState = NewsUiState.Loading, + onBackClick = {}, + onFollowClick = {} ) } } diff --git a/feature-author/src/test/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModelTest.kt b/feature-author/src/test/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModelTest.kt index be2228cf5..9ab24160b 100644 --- a/feature-author/src/test/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModelTest.kt +++ b/feature-author/src/test/java/com/google/samples/apps/nowinandroid/feature/author/AuthorViewModelTest.kt @@ -78,8 +78,6 @@ class AuthorViewModelTest { successAuthorUiState.followableAuthor.author assertEquals(authorFromRepository, successAuthorUiState.followableAuthor.author) - - cancel() } } @@ -87,7 +85,6 @@ class AuthorViewModelTest { fun uiStateNews_whenInitialized_thenShowLoading() = runTest { viewModel.uiState.test { assertEquals(NewsUiState.Loading, awaitItem().newsState) - cancel() } } @@ -95,7 +92,6 @@ class AuthorViewModelTest { fun uiStateAuthor_whenInitialized_thenShowLoading() = runTest { viewModel.uiState.test { assertEquals(AuthorUiState.Loading, awaitItem().authorState) - cancel() } } @@ -104,7 +100,6 @@ class AuthorViewModelTest { viewModel.uiState.test { userDataRepository.setFollowedAuthorIds(setOf(testInputAuthors[1].author.id)) assertEquals(AuthorUiState.Loading, awaitItem().authorState) - cancel() } } @@ -118,7 +113,6 @@ class AuthorViewModelTest { val item = awaitItem() assertTrue(item.authorState is AuthorUiState.Success) assertTrue(item.newsState is NewsUiState.Loading) - cancel() } } @@ -133,7 +127,6 @@ class AuthorViewModelTest { val item = awaitItem() assertTrue(item.authorState is AuthorUiState.Success) assertTrue(item.newsState is NewsUiState.Success) - cancel() } } @@ -152,7 +145,6 @@ class AuthorViewModelTest { AuthorUiState.Success(followableAuthor = testOutputAuthors[0]), awaitItem().authorState ) - cancel() } } } diff --git a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt index 1bce189a5..cd996c3f3 100644 --- a/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt +++ b/feature-foryou/src/main/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouScreen.kt @@ -79,13 +79,12 @@ import androidx.compose.ui.unit.sp import androidx.core.content.ContextCompat import androidx.hilt.navigation.compose.hiltViewModel import coil.compose.AsyncImage -import com.google.samples.apps.nowinandroid.core.model.data.Author import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor 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.NewsResourceType.Video import com.google.samples.apps.nowinandroid.core.model.data.SaveableNewsResource -import com.google.samples.apps.nowinandroid.core.model.data.Topic +import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors +import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources +import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.ui.LoadingWheel import com.google.samples.apps.nowinandroid.core.ui.NewsResourceCardExpanded import com.google.samples.apps.nowinandroid.core.ui.component.NiaFilledButton @@ -96,7 +95,6 @@ import com.google.samples.apps.nowinandroid.core.ui.icon.NiaIcons import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTypography import kotlin.math.floor -import kotlinx.datetime.Instant @Composable fun ForYouRoute( @@ -482,17 +480,22 @@ private fun LazyListScope.Feed( } @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -@Preview(device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") -@Preview(device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") -@Preview(device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") @Composable -fun ForYouScreenLoading() { +fun ForYouScreenPopulatedFeed() { BoxWithConstraints { NiaTheme { ForYouScreen( windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(maxWidth, maxHeight)), - interestsSelectionState = ForYouInterestsSelectionUiState.Loading, - feedState = ForYouFeedUiState.Loading, + interestsSelectionState = ForYouInterestsSelectionUiState.NoInterestsSelection, + feedState = ForYouFeedUiState.Success( + feed = previewNewsResources.map { + SaveableNewsResource(it, false) + } + ), onTopicCheckedChanged = { _, _ -> }, onAuthorCheckedChanged = { _, _ -> }, saveFollowedTopics = {}, @@ -503,9 +506,10 @@ fun ForYouScreenLoading() { } @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -@Preview(device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") -@Preview(device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") -@Preview(device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") @Composable fun ForYouScreenTopicSelection() { BoxWithConstraints { @@ -513,79 +517,13 @@ fun ForYouScreenTopicSelection() { ForYouScreen( windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(maxWidth, maxHeight)), interestsSelectionState = ForYouInterestsSelectionUiState.WithInterestsSelection( - topics = listOf( - FollowableTopic( - topic = Topic( - id = "0", - name = "Headlines", - shortDescription = "", - longDescription = "", - url = "", - imageUrl = "" - ), - isFollowed = false - ), - FollowableTopic( - topic = Topic( - id = "1", - name = "UI", - shortDescription = "", - longDescription = "", - url = "", - imageUrl = "" - ), - isFollowed = false - ), - FollowableTopic( - topic = Topic( - id = "2", - name = "Publishing and Distribution", - shortDescription = "", - longDescription = "", - url = "", - imageUrl = "" - ), - isFollowed = false - ), - ), - authors = listOf( - FollowableAuthor( - author = Author( - id = "0", - name = "Android Dev", - imageUrl = "", - twitter = "", - mediumPage = "", - bio = "", - ), - isFollowed = false - ), - FollowableAuthor( - author = Author( - id = "1", - name = "Android Dev 2", - imageUrl = "", - twitter = "", - mediumPage = "", - bio = "", - ), - isFollowed = false - ), - FollowableAuthor( - author = Author( - id = "2", - name = "Android Dev 3", - imageUrl = "", - twitter = "", - mediumPage = "", - bio = "", - ), - isFollowed = false - ) - ) + topics = previewTopics.map { FollowableTopic(it, false) }, + authors = previewAuthors.map { FollowableAuthor(it, false) } ), feedState = ForYouFeedUiState.Success( - feed = saveableNewsResource, + feed = previewNewsResources.map { + SaveableNewsResource(it, false) + } ), onAuthorCheckedChanged = { _, _ -> }, onTopicCheckedChanged = { _, _ -> }, @@ -597,19 +535,18 @@ fun ForYouScreenTopicSelection() { } @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -@Preview(device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") -@Preview(device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") -@Preview(device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") @Composable -fun PopulatedFeed() { +fun ForYouScreenLoading() { BoxWithConstraints { NiaTheme { ForYouScreen( windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(maxWidth, maxHeight)), - interestsSelectionState = ForYouInterestsSelectionUiState.NoInterestsSelection, - feedState = ForYouFeedUiState.Success( - feed = saveableNewsResource - ), + interestsSelectionState = ForYouInterestsSelectionUiState.Loading, + feedState = ForYouFeedUiState.Loading, onTopicCheckedChanged = { _, _ -> }, onAuthorCheckedChanged = { _, _ -> }, saveFollowedTopics = {}, @@ -618,84 +555,3 @@ fun PopulatedFeed() { } } } - -private val saveableNewsResource = listOf( - SaveableNewsResource( - newsResource = NewsResource( - id = "1", - episodeId = "52", - title = "Thanks for helping us reach 1M YouTube Subscribers", - content = "Thank you everyone for following the Now in Android series " + - "and everything the Android Developers YouTube channel has to offer. " + - "During the Android Developer Summit, our YouTube channel reached 1 " + - "million subscribers! Here’s a small video to thank you all.", - url = "https://youtu.be/-fJ6poHQrjM", - headerImageUrl = "https://i.ytimg.com/vi/-fJ6poHQrjM/maxresdefault.jpg", - publishDate = Instant.parse("2021-11-09T00:00:00.000Z"), - type = Video, - topics = listOf( - Topic( - id = "0", - name = "Headlines", - shortDescription = "", - longDescription = "", - url = "", - imageUrl = "" - ) - ), - authors = emptyList() - ), - isSaved = false - ), - SaveableNewsResource( - newsResource = NewsResource( - id = "2", - episodeId = "52", - title = "Transformations and customisations in the Paging Library", - content = "A demonstration of different operations that can be performed " + - "with Paging. Transformations like inserting separators, when to " + - "create a new pager, and customisation options for consuming " + - "PagingData.", - url = "https://youtu.be/ZARz0pjm5YM", - headerImageUrl = "https://i.ytimg.com/vi/ZARz0pjm5YM/maxresdefault.jpg", - publishDate = Instant.parse("2021-11-01T00:00:00.000Z"), - type = Video, - topics = listOf( - Topic( - id = "1", - name = "UI", - shortDescription = "", - longDescription = "", - url = "", - imageUrl = "" - ), - ), - authors = emptyList() - ), - isSaved = false - ), - SaveableNewsResource( - newsResource = NewsResource( - id = "3", - episodeId = "52", - title = "Community tip on Paging", - content = "Tips for using the Paging library from the developer community", - url = "https://youtu.be/r5JgIyS3t3s", - headerImageUrl = "https://i.ytimg.com/vi/r5JgIyS3t3s/maxresdefault.jpg", - publishDate = Instant.parse("2021-11-08T00:00:00.000Z"), - type = Video, - topics = listOf( - Topic( - id = "1", - name = "UI", - shortDescription = "", - longDescription = "", - url = "", - imageUrl = "" - ), - ), - authors = emptyList() - ), - isSaved = false - ), -) diff --git a/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt b/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt index e39f10f3b..dba50dccb 100644 --- a/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt +++ b/feature-foryou/src/test/java/com/google/samples/apps/nowinandroid/feature/foryou/ForYouViewModelTest.kt @@ -87,7 +87,6 @@ class ForYouViewModelTest { ), awaitItem() ) - cancel() } } @@ -102,8 +101,6 @@ class ForYouViewModelTest { awaitItem() ) topicsRepository.sendTopics(sampleTopics) - - cancel() } } @@ -118,8 +115,6 @@ class ForYouViewModelTest { awaitItem() ) authorsRepository.sendAuthors(sampleAuthors) - - cancel() } } @@ -134,8 +129,6 @@ class ForYouViewModelTest { awaitItem() ) userDataRepository.setFollowedTopicIds(emptySet()) - - cancel() } } @@ -150,8 +143,6 @@ class ForYouViewModelTest { awaitItem() ) userDataRepository.setFollowedAuthorIds(emptySet()) - - cancel() } } @@ -247,8 +238,6 @@ class ForYouViewModelTest { ), expectMostRecentItem() ) - - cancel() } } @@ -344,7 +333,6 @@ class ForYouViewModelTest { ), expectMostRecentItem() ) - cancel() } } @@ -385,7 +373,6 @@ class ForYouViewModelTest { ), awaitItem() ) - cancel() } } @@ -426,7 +413,6 @@ class ForYouViewModelTest { ), awaitItem() ) - cancel() } } @@ -695,7 +681,6 @@ class ForYouViewModelTest { ), awaitItem() ) - cancel() } } @@ -964,7 +949,6 @@ class ForYouViewModelTest { ), awaitItem() ) - cancel() } } @@ -1062,7 +1046,6 @@ class ForYouViewModelTest { ), expectMostRecentItem() ) - cancel() } } @@ -1160,7 +1143,6 @@ class ForYouViewModelTest { ), expectMostRecentItem() ) - cancel() } } @@ -1202,7 +1184,6 @@ class ForYouViewModelTest { ) assertEquals(setOf("1"), userDataRepository.getCurrentFollowedTopics()) assertEquals(emptySet(), userDataRepository.getCurrentFollowedAuthors()) - cancel() } } @@ -1240,7 +1221,6 @@ class ForYouViewModelTest { ) assertEquals(emptySet(), userDataRepository.getCurrentFollowedTopics()) assertEquals(setOf("0"), userDataRepository.getCurrentFollowedAuthors()) - cancel() } } @@ -1283,7 +1263,6 @@ class ForYouViewModelTest { ) assertEquals(setOf("1"), userDataRepository.getCurrentFollowedTopics()) assertEquals(setOf("1"), userDataRepository.getCurrentFollowedAuthors()) - cancel() } } @@ -1387,7 +1366,6 @@ class ForYouViewModelTest { expectMostRecentItem() ) - cancel() } } @@ -1490,7 +1468,6 @@ class ForYouViewModelTest { ), expectMostRecentItem() ) - cancel() } } @@ -1525,7 +1502,6 @@ class ForYouViewModelTest { ), expectMostRecentItem() ) - cancel() } } } diff --git a/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt b/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt index 7be087ccb..fa47eb26e 100644 --- a/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt +++ b/feature-interests/src/main/java/com/google/samples/apps/nowinandroid/feature/interests/InterestsScreen.kt @@ -34,12 +34,19 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import com.google.samples.apps.nowinandroid.core.model.data.FollowableAuthor +import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic +import com.google.samples.apps.nowinandroid.core.model.data.previewAuthors +import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.ui.LoadingWheel +import com.google.samples.apps.nowinandroid.core.ui.component.NiaBackground import com.google.samples.apps.nowinandroid.core.ui.component.NiaTab import com.google.samples.apps.nowinandroid.core.ui.component.NiaTabRow import com.google.samples.apps.nowinandroid.core.ui.component.NiaTopAppBar +import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme @Composable fun InterestsRoute( @@ -164,3 +171,78 @@ private fun InterestsContent( private fun InterestsEmptyScreen() { Text(text = stringResource(id = R.string.interests_empty_header)) } + +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Composable +fun InterestsScreenPopulated() { + NiaTheme { + NiaBackground { + InterestsScreen( + uiState = InterestsUiState.Interests( + authors = previewAuthors.map { FollowableAuthor(it, false) }, + topics = previewTopics.map { FollowableTopic(it, false) } + ), + tabState = InterestsTabState( + titles = listOf(R.string.interests_topics, R.string.interests_people), + currentIndex = 0 + ), + followAuthor = { _, _ -> }, + followTopic = { _, _ -> }, + navigateToAuthor = {}, + navigateToTopic = {}, + switchTab = {} + ) + } + } +} + +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Composable +fun InterestsScreenLoading() { + NiaTheme { + NiaBackground { + InterestsScreen( + uiState = InterestsUiState.Loading, + tabState = InterestsTabState( + titles = listOf(R.string.interests_topics, R.string.interests_people), + currentIndex = 0 + ), + followAuthor = { _, _ -> }, + followTopic = { _, _ -> }, + navigateToAuthor = {}, + navigateToTopic = {}, + switchTab = {}, + ) + } + } +} + +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Composable +fun InterestsScreenEmpty() { + NiaTheme { + NiaBackground { + InterestsScreen( + uiState = InterestsUiState.Empty, + tabState = InterestsTabState( + titles = listOf(R.string.interests_topics, R.string.interests_people), + currentIndex = 0 + ), + followAuthor = { _, _ -> }, + followTopic = { _, _ -> }, + navigateToAuthor = {}, + navigateToTopic = {}, + switchTab = {} + ) + } + } +} diff --git a/feature-interests/src/test/java/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt b/feature-interests/src/test/java/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt index 249b3329c..a341f7fd6 100644 --- a/feature-interests/src/test/java/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt +++ b/feature-interests/src/test/java/com/google/samples/apps/nowinandroid/interests/InterestsViewModelTest.kt @@ -56,7 +56,6 @@ class InterestsViewModelTest { fun uiState_whenInitialized_thenShowLoading() = runTest { viewModel.uiState.test { assertEquals(InterestsUiState.Loading, awaitItem()) - cancel() } } @@ -66,7 +65,6 @@ class InterestsViewModelTest { assertEquals(InterestsUiState.Loading, awaitItem()) userDataRepository.setFollowedAuthorIds(setOf("1")) userDataRepository.setFollowedTopicIds(emptySet()) - cancel() } } @@ -76,7 +74,6 @@ class InterestsViewModelTest { assertEquals(InterestsUiState.Loading, awaitItem()) userDataRepository.setFollowedAuthorIds(emptySet()) userDataRepository.setFollowedTopicIds(setOf("1")) - cancel() } } @@ -106,7 +103,6 @@ class InterestsViewModelTest { InterestsUiState.Interests(topics = testOutputTopics, authors = emptyList()), awaitItem() ) - cancel() } } @@ -130,7 +126,6 @@ class InterestsViewModelTest { InterestsUiState.Interests(topics = emptyList(), authors = testOutputAuthors), awaitItem() ) - cancel() } } @@ -162,7 +157,6 @@ class InterestsViewModelTest { InterestsUiState.Interests(topics = testInputTopics, authors = emptyList()), awaitItem() ) - cancel() } } @@ -188,7 +182,6 @@ class InterestsViewModelTest { InterestsUiState.Interests(topics = emptyList(), authors = testInputAuthors), awaitItem() ) - cancel() } } } diff --git a/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt b/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt index f76cd649b..3cb99d67e 100644 --- a/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt +++ b/feature-topic/src/main/java/com/google/samples/apps/nowinandroid/feature/topic/TopicScreen.kt @@ -49,9 +49,13 @@ import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import coil.compose.AsyncImage import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic +import com.google.samples.apps.nowinandroid.core.model.data.previewNewsResources +import com.google.samples.apps.nowinandroid.core.model.data.previewTopics import com.google.samples.apps.nowinandroid.core.ui.LoadingWheel +import com.google.samples.apps.nowinandroid.core.ui.component.NiaBackground import com.google.samples.apps.nowinandroid.core.ui.component.NiaFilterChip import com.google.samples.apps.nowinandroid.core.ui.newsResourceCardItems +import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme import com.google.samples.apps.nowinandroid.feature.topic.R.string import com.google.samples.apps.nowinandroid.feature.topic.TopicUiState.Loading @@ -188,19 +192,6 @@ private fun LazyListScope.TopicCards(news: NewsUiState) { } } -@Preview -@Composable -private fun TopicBodyPreview() { - MaterialTheme { - LazyColumn { - TopicBody( - "Jetpack Compose", "Lorem ipsum maximum", - NewsUiState.Success(emptyList()), "" - ) - } - } -} - @Composable private fun TopicToolbar( uiState: FollowableTopic, @@ -235,3 +226,39 @@ private fun TopicToolbar( } } } + +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Composable +fun TopicScreenPopulated() { + NiaTheme { + NiaBackground { + TopicScreen( + topicState = TopicUiState.Success(FollowableTopic(previewTopics[0], false)), + newsState = NewsUiState.Success(previewNewsResources), + onBackClick = {}, + onFollowClick = {} + ) + } + } +} + +@Preview(name = "phone", device = "spec:shape=Normal,width=360,height=640,unit=dp,dpi=480") +@Preview(name = "landscape", device = "spec:shape=Normal,width=640,height=360,unit=dp,dpi=480") +@Preview(name = "foldable", device = "spec:shape=Normal,width=673,height=841,unit=dp,dpi=480") +@Preview(name = "tablet", device = "spec:shape=Normal,width=1280,height=800,unit=dp,dpi=480") +@Composable +fun TopicScreenLoading() { + NiaTheme { + NiaBackground { + TopicScreen( + topicState = TopicUiState.Loading, + newsState = NewsUiState.Loading, + onBackClick = {}, + onFollowClick = {} + ) + } + } +} diff --git a/feature-topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt b/feature-topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt index a5e37a4ae..bbc183003 100644 --- a/feature-topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt +++ b/feature-topic/src/test/java/com/google/samples/apps/nowinandroid/feature/topic/TopicViewModelTest.kt @@ -72,7 +72,6 @@ class TopicViewModelTest { ).first() assertEquals(topicFromRepository, successTopicState.followableTopic.topic) - cancel() } } @@ -80,7 +79,6 @@ class TopicViewModelTest { fun uiStateNews_whenInitialized_thenShowLoading() = runTest { viewModel.uiState.test { assertEquals(NewsUiState.Loading, awaitItem().newsState) - cancel() } } @@ -88,7 +86,6 @@ class TopicViewModelTest { fun uiStateTopic_whenInitialized_thenShowLoading() = runTest { viewModel.uiState.test { assertEquals(TopicUiState.Loading, awaitItem().topicState) - cancel() } } @@ -97,7 +94,6 @@ class TopicViewModelTest { viewModel.uiState.test { userDataRepository.setFollowedTopicIds(setOf(testInputTopics[1].topic.id)) assertEquals(TopicUiState.Loading, awaitItem().topicState) - cancel() } } @@ -111,7 +107,6 @@ class TopicViewModelTest { val item = awaitItem() assertTrue(item.topicState is TopicUiState.Success) assertTrue(item.newsState is NewsUiState.Loading) - cancel() } } @@ -126,7 +121,6 @@ class TopicViewModelTest { val item = awaitItem() assertTrue(item.topicState is TopicUiState.Success) assertTrue(item.newsState is NewsUiState.Success) - cancel() } } @@ -145,7 +139,6 @@ class TopicViewModelTest { TopicUiState.Success(followableTopic = testOutputTopics[0]), awaitItem().topicState ) - cancel() } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e68ee834c..78724ff06 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,10 +3,10 @@ accompanist = "0.24.8-beta" androidDesugarJdkLibs = "1.1.5" androidGradlePlugin = "7.2.1" androidxActivity = "1.4.0" -androidxAppCompat = "1.3.0" +androidxAppCompat = "1.4.2" androidxCompose = "1.2.0-beta03" androidxComposeMaterial3 = "1.0.0-alpha13" -androidxCore = "1.7.0" +androidxCore = "1.8.0" androidxCustomView = "1.0.0-beta02" androidxDataStore = "1.0.0" androidxEspresso = "3.4.0" @@ -28,14 +28,14 @@ hiltExt = "1.0.0" jacoco = "0.8.7" junit4 = "4.13.2" kotlin = "1.6.21" -kotlinxCoroutines = "1.6.0" +kotlinxCoroutines = "1.6.2" kotlinxDatetime = "0.3.3" kotlinxSerializationJson = "1.3.3" ksp = "1.6.21-1.0.5" ktlint = "0.43.0" material3 = "1.6.1" okhttp = "4.9.3" -protobuf = "3.20.0" +protobuf = "3.21.1" protobufPlugin = "0.8.18" retrofit = "2.9.0" retrofitKotlinxSerializationJson = "0.8.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2..41d9927a4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 66c521b8d..aa991fcea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Thu Feb 24 14:19:14 GMT 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionPath=wrapper/dists -zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists