Polish picker switching and Home playback handoff
This commit is contained in:
parent
74b737fb52
commit
612ae79f0c
20 changed files with 974 additions and 83 deletions
|
|
@ -0,0 +1,63 @@
|
|||
package org.justinvisser.wolfskin.design
|
||||
|
||||
import android.app.Application
|
||||
import android.graphics.BitmapFactory
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.test.*
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import com.github.takahirom.roborazzi.captureRoboImage
|
||||
import java.io.File
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.GraphicsMode
|
||||
|
||||
/** Loading profiles share one pulse without fading the recovery action. */
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34], application = Application::class, qualifiers = "w960dp-h540dp-xhdpi")
|
||||
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
||||
class PickerPolishTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test fun loadingAvatarsBreatheButtonStays() = capture(false)
|
||||
@Test fun reducedMotionKeepsAvatarsAndButtonStill() = capture(true)
|
||||
|
||||
private fun capture(reduced: Boolean) {
|
||||
rule.mainClock.autoAdvance = false
|
||||
val state = ShellState(fixturePeople(), "justin").apply { peopleStatus = PeopleStatus.Loading }
|
||||
rule.setContent { CompositionLocalProvider(LocalReducedMotion provides reduced) { WolfskinTheme {
|
||||
ShellSurface(state, Modifier.requiredSize(WolfskinTokens.Shell.stageWidth, WolfskinTokens.Shell.stageHeight))
|
||||
} } }
|
||||
rule.mainClock.advanceTimeBy(32)
|
||||
val directory = File(System.getProperty("wolfskin.captureDirectory"), "ui-polish/P07/${if (reduced) "reduced" else "normal"}").apply { mkdirs() }
|
||||
val samples = (0..14).map { index ->
|
||||
val file = File(directory, "picker-loading-${index.toString().padStart(2, '0')}.png")
|
||||
rule.onRoot().captureRoboImage(file.absolutePath)
|
||||
val image = BitmapFactory.decodeFile(file.absolutePath)
|
||||
val pixels = try { image.getPixel(650, 540) to image.getPixel(950, 820) } finally { image.recycle() }
|
||||
rule.mainClock.advanceTimeBy(100, ignoreFrameDuration = true)
|
||||
"${index * 100},${pixels.first},${pixels.second}"
|
||||
}
|
||||
File(directory, "samples.csv").writeText("timeMs,avatar,button\n" + samples.joinToString("\n"))
|
||||
val avatars = samples.map { it.split(',')[1].toInt() }
|
||||
val buttons = samples.map { it.split(',')[2].toInt() }
|
||||
assertEquals("The recovery button never pulses", 1, buttons.distinct().size)
|
||||
if (reduced) assertEquals("Reduced motion stops the shared pulse", 1, avatars.distinct().size)
|
||||
else {
|
||||
assertNotEquals("The avatar must breathe by the middle of the cycle", avatars.first(), avatars[7])
|
||||
assertNotEquals("The avatar must also pass through an intermediate alpha", avatars.first(), avatars[3])
|
||||
}
|
||||
rule.runOnIdle { state.peopleStatus = PeopleStatus.Ready; androidx.compose.runtime.snapshots.Snapshot.sendApplyNotifications() }
|
||||
rule.mainClock.advanceTimeBy(1000)
|
||||
rule.onNodeWithTag("picker-person:justin").assertIsDisplayed()
|
||||
rule.onNodeWithText("Continue as Justin").assertDoesNotExist()
|
||||
assertTrue("Removing the last subscriber stops its infinite transition",
|
||||
androidx.compose.runtime.Recomposer.runningRecomposers.value.all { !it.hasPendingWork })
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue