-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updated STAR demo to support navigating to standard Android #275
Conversation
03e912b
to
7bf5ca5
Compare
7bf5ca5
to
1e1cd50
Compare
Added legacy navigator to support navigating outside of Circuit. Reworked PetDetails "View full bio" external link to use new legacy navigator pattern.
3061d48
to
9978fe2
Compare
@@ -32,7 +32,7 @@ android { | |||
defaultConfig { | |||
minSdk = 28 | |||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | |||
testApplicationId = "com.slack.circuit.star.androidTest" | |||
testApplicationId = "com.slack.circuit.star.apk.androidTest" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this, the test suite can't find the test application at runtime
@@ -115,7 +115,7 @@ dependencies { | |||
testImplementation(libs.androidx.compose.ui.testing.manifest) | |||
testImplementation(libs.leakcanary.android.instrumentation) | |||
|
|||
debugImplementation(libs.androidx.compose.ui.testing.manifest) | |||
androidTestImplementation(libs.androidx.compose.ui.testing.manifest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this, ComposeActivity
isn't merged with the manifest meaning it can't be found at runtime. Before introduction of the apk module, we used to support debug builds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it needs to be present in both?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By both do you mean unit tests? We were already merging correctly for unit tests
@Composable | ||
private fun TopBar(state: PetDetailScreen.State) { | ||
if (state !is PetDetailScreen.State.Success) return | ||
|
||
CenterAlignedTopAppBar(title = { Text(state.name) }, navigationIcon = { BackPressNavIcon() }) | ||
} | ||
|
||
@Composable | ||
private fun Loading(paddingValues: PaddingValues) { | ||
Box( | ||
modifier = Modifier.padding(paddingValues).fillMaxSize(), | ||
contentAlignment = Alignment.Center | ||
) { | ||
CircularProgressIndicator(modifier = Modifier.testTag(PROGRESS_TAG)) | ||
} | ||
} | ||
|
||
@Composable | ||
private fun UnknownAnimal(paddingValues: PaddingValues) { | ||
Box( | ||
modifier = Modifier.padding(paddingValues).fillMaxSize(), | ||
contentAlignment = Alignment.Center | ||
) { | ||
Text( | ||
modifier = Modifier.testTag(UNKNOWN_ANIMAL_TAG), | ||
text = stringResource(id = R.string.unknown_animals) | ||
) | ||
} | ||
} | ||
|
||
@Composable | ||
private fun ShowAnimal( | ||
state: PetDetailScreen.State.Success, | ||
padding: PaddingValues, | ||
) = | ||
when (LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE) { | ||
true -> ShowAnimalLandscape(state, padding) | ||
false -> ShowAnimalPortrait(state, padding) | ||
} | ||
|
||
@Composable | ||
private fun ShowAnimalLandscape(state: PetDetailScreen.State.Success, padding: PaddingValues) { | ||
Row( | ||
modifier = Modifier.padding(padding), | ||
horizontalArrangement = Arrangement.SpaceEvenly, | ||
) { | ||
CircuitContent( | ||
PetPhotoCarouselScreen( | ||
name = state.name, | ||
photoUrls = state.photoUrls, | ||
photoUrlMemoryCacheKey = state.photoUrlMemoryCacheKey, | ||
) | ||
) | ||
LazyColumn { petDetailDescriptions(state) } | ||
} | ||
} | ||
|
||
@Composable | ||
private fun ShowAnimalPortrait(state: PetDetailScreen.State.Success, padding: PaddingValues) { | ||
LazyColumn( | ||
modifier = Modifier.padding(padding).testTag(ANIMAL_CONTAINER_TAG), | ||
contentPadding = PaddingValues(16.dp), | ||
verticalArrangement = Arrangement.spacedBy(16.dp), | ||
) { | ||
item { | ||
CircuitContent( | ||
PetPhotoCarouselScreen( | ||
name = state.name, | ||
photoUrls = state.photoUrls, | ||
photoUrlMemoryCacheKey = state.photoUrlMemoryCacheKey, | ||
) | ||
) | ||
} | ||
petDetailDescriptions(state) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No change here. I just extracted it from PetDetail
name = "Baxter", | ||
description = "Grumpy looking Australian Terrier", | ||
tags = listOf("dog", "terrier", "male"), | ||
eventSink = channel::trySend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: why the name trySend
for this callback? Should we just do send
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't use send
here because it's suspend
-able, trySend
isn't
@@ -115,7 +115,7 @@ dependencies { | |||
testImplementation(libs.androidx.compose.ui.testing.manifest) | |||
testImplementation(libs.leakcanary.android.instrumentation) | |||
|
|||
debugImplementation(libs.androidx.compose.ui.testing.manifest) | |||
androidTestImplementation(libs.androidx.compose.ui.testing.manifest) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it needs to be present in both?
composeTestRule.run { | ||
setContent { CircuitCompositionLocals(circuitConfig) { PetDetail(success) } } | ||
|
||
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() } | ||
onNodeWithTag(FULL_BIO_TAG, true).assertIsDisplayed().performClick() | ||
|
||
val event = channel.receive() | ||
assertThat(event).isEqualTo(PetDetailScreen.Event.ViewFullBio(success.url)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity why do we do these run blocks?
composeTestRule.run { | |
setContent { CircuitCompositionLocals(circuitConfig) { PetDetail(success) } } | |
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() } | |
onNodeWithTag(FULL_BIO_TAG, true).assertIsDisplayed().performClick() | |
val event = channel.receive() | |
assertThat(event).isEqualTo(PetDetailScreen.Event.ViewFullBio(success.url)) | |
} | |
composeTestRule.setContent { | |
setContent { CircuitCompositionLocals(circuitConfig) { PetDetail(success) } } | |
} | |
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() } | |
onNodeWithTag(FULL_BIO_TAG, true).assertIsDisplayed().performClick() | |
val event = channel.receive() | |
assertThat(event).isEqualTo(PetDetailScreen.Event.ViewFullBio(success.url)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the onNodeWithX
methods are extensions on SemanticsNodeInteractionsProvider
which is implemented by the AndroidComposeTestRule
(ie. composeTestRule
). Without the run
(or something similar) we'd need to prefix ever onNodeWithX
with composeTestRule
composeTestRule.run { | ||
setContent { CircuitCompositionLocals(circuitConfig) { PetDetail(success) } } | ||
|
||
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() } | ||
onNodeWithTag(FULL_BIO_TAG, true).assertIsDisplayed().performClick() | ||
|
||
val event = channel.receive() | ||
assertThat(event).isEqualTo(PetDetailScreen.Event.ViewFullBio(success.url)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity why do we do these run blocks?
composeTestRule.run { | |
setContent { CircuitCompositionLocals(circuitConfig) { PetDetail(success) } } | |
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() } | |
onNodeWithTag(FULL_BIO_TAG, true).assertIsDisplayed().performClick() | |
val event = channel.receive() | |
assertThat(event).isEqualTo(PetDetailScreen.Event.ViewFullBio(success.url)) | |
} | |
composeTestRule.setContent { | |
setContent { CircuitCompositionLocals(circuitConfig) { PetDetail(success) } } | |
} | |
onNodeWithTag(CAROUSEL_TAG).assertIsDisplayed().performTouchInput { swipeUp() } | |
onNodeWithTag(FULL_BIO_TAG, true).assertIsDisplayed().performClick() | |
val event = channel.receive() | |
assertThat(event).isEqualTo(PetDetailScreen.Event.ViewFullBio(success.url)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here
Let's update the name to mention this is just a demo for navigating to standard android. "Legacy views" is referring to slack internal stuff, same with the jira slug 😅 |
Yes, good call. Done! |
This PR introduces
LegacyNavigator
as a solution for navigating out of a circuit environment. It also updates PetDetails to use this new approach when the user clicks on the "View full bio" button.Note: instrumentation tests are not currently being run by CI. This will be addressed in a follow-up PR