Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cf792cd

Browse files
committedSep 16, 2020
Update JetNews to alpha03.
Update snackbar in [HomeScreen] to not restart when posts changes but the error remains false (previously it would flicker due to a restart) Change workaround in SwipeToRefresh to not crash in alpha03. This was caused by the behavior change of [onCommit]. Various renames from alpha01-alpha03
1 parent 4d40369 commit cf792cd

File tree

15 files changed

+161
-116
lines changed

15 files changed

+161
-116
lines changed
 

Diff for: ‎JetNews/.gitignore

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
*.iml
22
.gradle
33
/local.properties
4-
/.idea
4+
/.idea/caches
5+
/.idea/libraries
6+
/.idea/modules.xml
7+
/.idea/workspace.xml
8+
/.idea/navEditor.xml
9+
/.idea/assetWizardSettings.xml
510
.DS_Store
611
/build
712
/captures
813
.externalNativeBuild
14+
.cxx
15+
local.properties

Diff for: ‎JetNews/app/build.gradle

+8-8
Original file line numberDiff line numberDiff line change
@@ -67,18 +67,18 @@ dependencies {
6767
implementation "androidx.compose.foundation:foundation:$compose_version"
6868
implementation "androidx.compose.animation:animation:$compose_version"
6969
implementation "androidx.ui:ui-tooling:$compose_version"
70-
implementation 'androidx.appcompat:appcompat:1.3.0-alpha01'
71-
implementation 'androidx.activity:activity-ktx:1.1.0'
72-
implementation 'androidx.core:core-ktx:1.5.0-alpha01'
73-
7470
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
7571

76-
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.0-alpha06"
77-
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-alpha06"
72+
implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
73+
implementation 'androidx.activity:activity-ktx:1.1.0'
74+
implementation 'androidx.core:core-ktx:1.5.0-alpha02'
75+
76+
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.0-alpha07"
77+
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0-alpha07"
7878

7979
androidTestImplementation 'junit:junit:4.13'
80-
androidTestImplementation 'androidx.test:rules:1.2.0'
81-
androidTestImplementation 'androidx.test:runner:1.2.0'
80+
androidTestImplementation 'androidx.test:rules:1.3.0'
81+
androidTestImplementation 'androidx.test:runner:1.3.0'
8282
androidTestImplementation "androidx.ui:ui-test:$compose_version"
8383
}
8484

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright 2020 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.jetnews
18+
19+
import androidx.compose.material.ExperimentalMaterialApi
20+
import androidx.compose.material.SnackbarHostState
21+
import androidx.compose.material.rememberScaffoldState
22+
import androidx.compose.runtime.ExperimentalComposeApi
23+
import androidx.compose.runtime.snapshots.snapshotFlow
24+
import androidx.test.platform.app.InstrumentationRegistry
25+
import androidx.ui.test.assertIsDisplayed
26+
import androidx.ui.test.createComposeRule
27+
import androidx.ui.test.onNodeWithText
28+
import com.example.jetnews.ui.home.HomeScreen
29+
import com.example.jetnews.ui.state.UiState
30+
import kotlinx.coroutines.flow.filterNotNull
31+
import kotlinx.coroutines.flow.first
32+
import kotlinx.coroutines.runBlocking
33+
import org.junit.Rule
34+
import org.junit.Test
35+
36+
/**
37+
* Checks that the Snackbar is shown when the HomeScreen data contains an error.
38+
*/
39+
class HomeScreenSnackbarTest {
40+
41+
@get:Rule
42+
val composeTestRule = createComposeRule(disableTransitions = true)
43+
44+
@OptIn(
45+
ExperimentalMaterialApi::class,
46+
ExperimentalComposeApi::class
47+
)
48+
@Test
49+
fun postsContainError_snackbarShown() {
50+
val snackbarHostState = SnackbarHostState()
51+
composeTestRule.setContent {
52+
val scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState)
53+
54+
// When the Home screen receives data with an error
55+
HomeScreen(
56+
posts = UiState(exception = IllegalStateException()),
57+
favorites = emptySet(),
58+
onToggleFavorite = {},
59+
onRefreshPosts = {},
60+
onErrorDismiss = {},
61+
navigateTo = {},
62+
scaffoldState = scaffoldState
63+
)
64+
}
65+
66+
// Then the first message received in the Snackbar is an error message
67+
val snackbarText = InstrumentationRegistry.getInstrumentation()
68+
.targetContext.resources.getString(R.string.load_error)
69+
runBlocking {
70+
// snapshotFlow converts a State to a Kotlin Flow so we can observe it
71+
// wait for the first a non-null `currentSnackbarData`
72+
snapshotFlow { snackbarHostState.currentSnackbarData }.filterNotNull().first()
73+
composeTestRule.onNodeWithText(snackbarText, false, false).assertIsDisplayed()
74+
}
75+
}
76+
}

Diff for: ‎JetNews/app/src/androidTest/java/com/example/jetnews/JetnewsUiTest.kt

+5-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import androidx.test.platform.app.InstrumentationRegistry
2121
import androidx.ui.test.assertIsDisplayed
2222
import androidx.ui.test.createComposeRule
2323
import androidx.ui.test.hasSubstring
24-
import androidx.ui.test.onAllNodes
2524
import androidx.ui.test.onNodeWithText
2625
import androidx.ui.test.performClick
2726
import org.junit.Before
@@ -41,16 +40,16 @@ class JetnewsUiTest {
4140
composeTestRule.launchJetNewsApp(InstrumentationRegistry.getInstrumentation().targetContext)
4241
}
4342

44-
@Ignore // TODO Investigate why this passes locally but fail on CI
43+
@Ignore("TODO Investigate why this passes locally but fail on CI")
4544
@Test
4645
fun app_launches() {
47-
onNodeWithText("Jetnews").assertIsDisplayed()
46+
composeTestRule.onNodeWithText("Jetnews").assertIsDisplayed()
4847
}
4948

50-
@Ignore // TODO Investigate why this passes locally but fail on CI
49+
@Ignore("TODO Investigate why this passes locally but fail on CI")
5150
@Test
5251
fun app_opensArticle() {
53-
onAllNodes(hasSubstring("Manuel Vivo"))[0].performClick()
54-
onAllNodes(hasSubstring("3 min read"))[0].assertIsDisplayed()
52+
composeTestRule.onAllNodes(hasSubstring("Manuel Vivo"))[0].performClick()
53+
composeTestRule.onAllNodes(hasSubstring("3 min read"))[0].assertIsDisplayed()
5554
}
5655
}

Diff for: ‎JetNews/app/src/androidTest/java/com/example/jetnews/TestHelper.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@ package com.example.jetnews
1919
import android.content.Context
2020
import androidx.compose.runtime.remember
2121
import androidx.lifecycle.SavedStateHandle
22-
import androidx.ui.test.ComposeTestRule
22+
import androidx.ui.test.ComposeTestRuleJUnit
2323
import com.example.jetnews.ui.JetnewsApp
2424
import com.example.jetnews.ui.NavigationViewModel
2525

2626
/**
2727
* Launches the app from a test context
2828
*/
29-
fun ComposeTestRule.launchJetNewsApp(context: Context) {
29+
fun ComposeTestRuleJUnit.launchJetNewsApp(context: Context) {
3030
setContent {
3131
JetnewsApp(
3232
TestAppContainer(context),

Diff for: ‎JetNews/app/src/main/java/com/example/jetnews/ui/JetnewsApp.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ private fun DrawerButton(
180180
) {
181181
Row(
182182
horizontalArrangement = Arrangement.Start,
183-
verticalGravity = Alignment.CenterVertically,
183+
verticalAlignment = Alignment.CenterVertically,
184184
modifier = Modifier.fillMaxWidth()
185185
) {
186186
Image(

Diff for: ‎JetNews/app/src/main/java/com/example/jetnews/ui/SwipeToRefresh.kt

+12-16
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,15 @@ fun SwipeToRefreshLayout(
4242
content: @Composable () -> Unit
4343
) {
4444
val refreshDistance = with(DensityAmbient.current) { RefreshDistance.toPx() }
45-
val state = rememberSwipeableState(refreshingState)
46-
// TODO (https://issuetracker.google.com/issues/164113834): This state->event trampoline is a
47-
// workaround for a bug in the SwipableState API. It should be replaced with a correct solution
48-
// when that bug closes.
49-
onCommit(refreshingState) {
50-
state.animateTo(refreshingState)
51-
}
52-
// TODO (https://issuetracker.google.com/issues/164113834): Hoist state changes when bug is
53-
// fixed and do this logic in the ViewModel. Currently, state.value is a duplicated source of
54-
// truth of refreshingState
55-
onCommit(state.value) {
56-
if (state.value) {
57-
onRefresh()
58-
}
45+
val state = rememberSwipeableState(refreshingState) { newValue ->
46+
// compare both copies of the swipe state before calling onRefresh(). This is a workaround.
47+
if (newValue && !refreshingState) onRefresh()
48+
true
5949
}
6050

6151
Stack(
6252
modifier = Modifier.swipeable(
6353
state = state,
64-
enabled = !state.value,
6554
anchors = mapOf(
6655
-refreshDistance to false,
6756
refreshDistance to true
@@ -71,10 +60,17 @@ fun SwipeToRefreshLayout(
7160
)
7261
) {
7362
content()
74-
Box(Modifier.gravity(Alignment.TopCenter).offsetPx(y = state.offset)) {
63+
Box(Modifier.align(Alignment.TopCenter).offsetPx(y = state.offset)) {
7564
if (state.offset.value != -refreshDistance) {
7665
refreshIndicator()
7766
}
7867
}
68+
69+
// TODO (https://issuetracker.google.com/issues/164113834): This state->event trampoline is a
70+
// workaround for a bug in the SwipableState API. Currently, state.value is a duplicated
71+
// source of truth of refreshingState.
72+
onCommit(refreshingState) {
73+
state.animateTo(refreshingState)
74+
}
7975
}
8076
}

Diff for: ‎JetNews/app/src/main/java/com/example/jetnews/ui/article/ArticleScreen.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private fun BottomBar(
171171
) {
172172
Surface(elevation = 2.dp) {
173173
Row(
174-
verticalGravity = Alignment.CenterVertically,
174+
verticalAlignment = Alignment.CenterVertically,
175175
modifier = Modifier
176176
.preferredHeight(56.dp)
177177
.fillMaxWidth()

Diff for: ‎JetNews/app/src/main/java/com/example/jetnews/ui/article/PostContent.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ import androidx.compose.foundation.layout.Column
2525
import androidx.compose.foundation.layout.Row
2626
import androidx.compose.foundation.layout.Spacer
2727
import androidx.compose.foundation.layout.fillMaxWidth
28+
import androidx.compose.foundation.layout.heightIn
2829
import androidx.compose.foundation.layout.padding
2930
import androidx.compose.foundation.layout.preferredHeight
30-
import androidx.compose.foundation.layout.preferredHeightIn
3131
import androidx.compose.foundation.layout.preferredSize
3232
import androidx.compose.foundation.layout.preferredWidth
3333
import androidx.compose.foundation.shape.CircleShape
@@ -101,7 +101,7 @@ fun PostContent(post: Post, modifier: Modifier = Modifier) {
101101
private fun PostHeaderImage(post: Post) {
102102
post.image?.let { image ->
103103
val imageModifier = Modifier
104-
.preferredHeightIn(minHeight = 180.dp)
104+
.heightIn(min = 180.dp)
105105
.fillMaxWidth()
106106
.clip(shape = MaterialTheme.shapes.medium)
107107
Image(image, imageModifier, contentScale = ContentScale.Crop)
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.