[#1096] Change brightness adjusting feature
* [#1096] Change brightness adjusting feature - Closes #1096 - As reported by testers, the automatic brightness adjustment could be too invasive - Switched to the on-demand feature after a new button click - Tests aligned * Align Screenshot tests * Changelog update
This commit is contained in:
parent
201cdbbd07
commit
06ca665fca
|
@ -12,6 +12,10 @@ directly impact users rather than highlighting other key architectural updates.*
|
|||
### Added
|
||||
- Unfinished features show a "Not implemented yet" message after accessing in the app UI
|
||||
|
||||
### Changed
|
||||
- Home and Receive screens have their Top app bar UI changed
|
||||
- Automatic brightness adjustment switched to an on-demand feature after a new button is clicked on the Receive screen
|
||||
|
||||
### Removed
|
||||
- Home screen side menu navigation was removed in favor of the Settings screen
|
||||
|
||||
|
|
|
@ -1,55 +1,40 @@
|
|||
package co.electriccoin.zcash.ui.screen.receive.view
|
||||
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.test.filters.MediumTest
|
||||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||
import co.electriccoin.zcash.ui.common.LocalScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.ScreenBrightness
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class ReceiveViewScreenBrightnessTest : UiTestPrerequisites() {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testFullBrightness() = runTest {
|
||||
fun testBrightnessDefaultState() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
assertEquals(1, testSetup.getSecureBrightnessCount())
|
||||
assertEquals(0, testSetup.getScreenBrightnessCount())
|
||||
}
|
||||
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = TestSetup(composeTestRule, walletAddress)
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testBrightnessOnState() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
private class TestSetup(private val composeTestRule: ComposeContentTestRule, walletAddress: WalletAddress) {
|
||||
private val screenBrightness = ScreenBrightness()
|
||||
assertEquals(false, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(0, testSetup.getScreenBrightnessCount())
|
||||
|
||||
fun getSecureBrightnessCount() = screenBrightness.referenceCount.value
|
||||
composeTestRule.clickAdjustBrightness()
|
||||
|
||||
init {
|
||||
composeTestRule.setContent {
|
||||
CompositionLocalProvider(LocalScreenBrightness provides screenBrightness) {
|
||||
ZcashTheme {
|
||||
ZcashTheme {
|
||||
Receive(
|
||||
walletAddress,
|
||||
onBack = { },
|
||||
onAddressDetails = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assertEquals(true, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(1, testSetup.getScreenBrightnessCount())
|
||||
}
|
||||
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = ReceiveViewTestSetup(composeTestRule, walletAddress)
|
||||
}
|
||||
|
|
|
@ -1,56 +1,40 @@
|
|||
package co.electriccoin.zcash.ui.screen.receive.view
|
||||
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.test.filters.MediumTest
|
||||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
||||
import co.electriccoin.zcash.test.UiTestPrerequisites
|
||||
import co.electriccoin.zcash.ui.common.LocalScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.ScreenTimeout
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
class ReceiveViewScreenTimeoutTest : UiTestPrerequisites() {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testFullBrightness() = runTest {
|
||||
fun testTimeoutDefaultState() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
assertEquals(0, testSetup.getScreenTimeoutCount())
|
||||
}
|
||||
|
||||
@Test
|
||||
@MediumTest
|
||||
fun testTimeoutOnState() = runTest {
|
||||
val testSetup = newTestSetup(WalletAddressFixture.unified())
|
||||
|
||||
assertEquals(false, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(0, testSetup.getScreenTimeoutCount())
|
||||
|
||||
composeTestRule.clickAdjustBrightness()
|
||||
|
||||
assertEquals(true, testSetup.getOnAdjustBrightness())
|
||||
assertEquals(1, testSetup.getScreenTimeoutCount())
|
||||
}
|
||||
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = TestSetup(composeTestRule, walletAddress)
|
||||
|
||||
private class TestSetup(private val composeTestRule: ComposeContentTestRule, walletAddress: WalletAddress) {
|
||||
|
||||
private val screenTimeout = ScreenTimeout()
|
||||
|
||||
fun getScreenTimeoutCount() = screenTimeout.referenceCount.value
|
||||
|
||||
init {
|
||||
composeTestRule.setContent {
|
||||
CompositionLocalProvider(LocalScreenTimeout provides screenTimeout) {
|
||||
ZcashTheme {
|
||||
ZcashTheme {
|
||||
Receive(
|
||||
walletAddress,
|
||||
onBack = { },
|
||||
onAddressDetails = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = ReceiveViewTestSetup(composeTestRule, walletAddress)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package co.electriccoin.zcash.ui.screen.receive.view
|
||||
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
|
@ -9,13 +8,11 @@ import androidx.test.filters.MediumTest
|
|||
import cash.z.ecc.android.sdk.fixture.WalletAddressFixture
|
||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.test.getStringResource
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
/*
|
||||
* Note: It is difficult to test the QR code from automated tests. There is a manual test case
|
||||
|
@ -71,37 +68,5 @@ class ReceiveViewTest {
|
|||
assertEquals(1, testSetup.getOnAddressDetailsCount())
|
||||
}
|
||||
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = TestSetup(composeTestRule, walletAddress)
|
||||
|
||||
private class TestSetup(private val composeTestRule: ComposeContentTestRule, walletAddress: WalletAddress) {
|
||||
|
||||
private val onBackCount = AtomicInteger(0)
|
||||
private val onAddressDetailsCount = AtomicInteger(0)
|
||||
|
||||
fun getOnBackCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onBackCount.get()
|
||||
}
|
||||
|
||||
fun getOnAddressDetailsCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onAddressDetailsCount.get()
|
||||
}
|
||||
|
||||
init {
|
||||
composeTestRule.setContent {
|
||||
ZcashTheme {
|
||||
Receive(
|
||||
walletAddress,
|
||||
onBack = {
|
||||
onBackCount.getAndIncrement()
|
||||
},
|
||||
onAddressDetails = {
|
||||
onAddressDetailsCount.getAndIncrement()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun newTestSetup(walletAddress: WalletAddress) = ReceiveViewTestSetup(composeTestRule, walletAddress)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package co.electriccoin.zcash.ui.screen.receive.view
|
||||
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.test.junit4.ComposeContentTestRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.performClick
|
||||
import cash.z.ecc.android.sdk.model.WalletAddress
|
||||
import co.electriccoin.zcash.ui.R
|
||||
import co.electriccoin.zcash.ui.common.LocalScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.LocalScreenTimeout
|
||||
import co.electriccoin.zcash.ui.common.ScreenBrightness
|
||||
import co.electriccoin.zcash.ui.common.ScreenTimeout
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.test.getStringResource
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class ReceiveViewTestSetup(
|
||||
private val composeTestRule: ComposeContentTestRule,
|
||||
walletAddress: WalletAddress
|
||||
) {
|
||||
private val onBackCount = AtomicInteger(0)
|
||||
private val onAddressDetailsCount = AtomicInteger(0)
|
||||
private val screenBrightness = ScreenBrightness()
|
||||
private val screenTimeout = ScreenTimeout()
|
||||
private val onAdjustBrightness = AtomicBoolean(false)
|
||||
|
||||
fun getScreenBrightnessCount() = screenBrightness.referenceCount.value
|
||||
|
||||
fun getScreenTimeoutCount() = screenTimeout.referenceCount.value
|
||||
|
||||
fun getOnAdjustBrightness(): Boolean {
|
||||
composeTestRule.waitForIdle()
|
||||
return onAdjustBrightness.get()
|
||||
}
|
||||
|
||||
fun getOnBackCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onBackCount.get()
|
||||
}
|
||||
|
||||
fun getOnAddressDetailsCount(): Int {
|
||||
composeTestRule.waitForIdle()
|
||||
return onAddressDetailsCount.get()
|
||||
}
|
||||
|
||||
init {
|
||||
composeTestRule.setContent {
|
||||
CompositionLocalProvider(
|
||||
LocalScreenBrightness provides screenBrightness,
|
||||
LocalScreenTimeout provides screenTimeout
|
||||
) {
|
||||
ZcashTheme {
|
||||
ZcashTheme {
|
||||
Receive(
|
||||
walletAddress,
|
||||
onBack = {
|
||||
onBackCount.getAndIncrement()
|
||||
},
|
||||
onAddressDetails = {
|
||||
onAddressDetailsCount.getAndIncrement()
|
||||
},
|
||||
onAdjustBrightness = {
|
||||
onAdjustBrightness.getAndSet(it)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ComposeContentTestRule.clickAdjustBrightness() {
|
||||
onNodeWithContentDescription(getStringResource(R.string.receive_brightness_content_description)).also {
|
||||
it.performClick()
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ class ScreenBrightness {
|
|||
mutableReferenceCount.update { it + 1 }
|
||||
}
|
||||
|
||||
fun restore() {
|
||||
fun restoreBrightness() {
|
||||
val after = mutableReferenceCount.updateAndGet { it - 1 }
|
||||
|
||||
if (after < 0) {
|
||||
|
@ -34,6 +34,6 @@ fun BrightenScreen() {
|
|||
val screenBrightness = LocalScreenBrightness.current
|
||||
DisposableEffect(screenBrightness) {
|
||||
screenBrightness.fullBrightness()
|
||||
onDispose { screenBrightness.restore() }
|
||||
onDispose { screenBrightness.restoreBrightness() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ internal fun WrapReceive(
|
|||
walletAddresses.unified,
|
||||
onBack = onBack,
|
||||
onAddressDetails = onAddressDetails,
|
||||
onAdjustBrightness = { /* Just for testing */ }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,15 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material.icons.filled.BrightnessHigh
|
||||
import androidx.compose.material.icons.filled.BrightnessLow
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
|
@ -35,6 +36,7 @@ import co.electriccoin.zcash.ui.design.MINIMAL_WEIGHT
|
|||
import co.electriccoin.zcash.ui.design.component.Body
|
||||
import co.electriccoin.zcash.ui.design.component.GradientSurface
|
||||
import co.electriccoin.zcash.ui.design.component.PrimaryButton
|
||||
import co.electriccoin.zcash.ui.design.component.SmallTopAppBar
|
||||
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
|
||||
import co.electriccoin.zcash.ui.screen.receive.util.AndroidQrCodeImageGenerator
|
||||
import co.electriccoin.zcash.ui.screen.receive.util.JvmQrCodeGenerator
|
||||
|
@ -50,24 +52,35 @@ private fun ComposablePreview() {
|
|||
walletAddress = runBlocking { WalletAddressFixture.unified() },
|
||||
onBack = {},
|
||||
onAddressDetails = {},
|
||||
onAdjustBrightness = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
fun Receive(
|
||||
walletAddress: WalletAddress,
|
||||
onBack: () -> Unit,
|
||||
onAddressDetails: () -> Unit,
|
||||
onAdjustBrightness: (Boolean) -> Unit,
|
||||
) {
|
||||
val (brightness, setBrightness) = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
// Rework this into Scaffold
|
||||
Column {
|
||||
ReceiveTopAppBar(onBack = onBack)
|
||||
ReceiveTopAppBar(
|
||||
adjustBrightness = brightness,
|
||||
onBack = onBack,
|
||||
onBrightness = {
|
||||
onAdjustBrightness(!brightness)
|
||||
setBrightness(!brightness)
|
||||
}
|
||||
)
|
||||
ReceiveContents(
|
||||
walletAddress = walletAddress,
|
||||
onAddressDetails = onAddressDetails,
|
||||
adjustBrightness = brightness,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.verticalScroll(rememberScrollState())
|
||||
|
@ -81,17 +94,27 @@ fun Receive(
|
|||
}
|
||||
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
private fun ReceiveTopAppBar(onBack: () -> Unit) {
|
||||
TopAppBar(
|
||||
title = { Text(text = stringResource(id = R.string.receive_title)) },
|
||||
navigationIcon = {
|
||||
private fun ReceiveTopAppBar(
|
||||
adjustBrightness: Boolean,
|
||||
onBack: () -> Unit,
|
||||
onBrightness: () -> Unit
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
titleText = stringResource(id = R.string.receive_title),
|
||||
backText = stringResource(id = R.string.receive_back),
|
||||
backContentDescriptionText = stringResource(id = R.string.receive_back_content_description),
|
||||
onBack = onBack,
|
||||
regularActions = {
|
||||
IconButton(
|
||||
onClick = onBack
|
||||
onClick = onBrightness
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.ArrowBack,
|
||||
contentDescription = stringResource(R.string.receive_back_content_description)
|
||||
imageVector = if (adjustBrightness) {
|
||||
Icons.Default.BrightnessLow
|
||||
} else {
|
||||
Icons.Default.BrightnessHigh
|
||||
},
|
||||
contentDescription = stringResource(R.string.receive_brightness_content_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -101,17 +124,22 @@ private fun ReceiveTopAppBar(onBack: () -> Unit) {
|
|||
private val DEFAULT_QR_CODE_SIZE = 320.dp
|
||||
|
||||
@Composable
|
||||
@Suppress("LongParameterList")
|
||||
private fun ReceiveContents(
|
||||
walletAddress: WalletAddress,
|
||||
onAddressDetails: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
adjustBrightness: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
QrCode(data = walletAddress.address, DEFAULT_QR_CODE_SIZE, Modifier.align(Alignment.CenterHorizontally))
|
||||
QrCode(
|
||||
data = walletAddress.address,
|
||||
size = DEFAULT_QR_CODE_SIZE,
|
||||
adjustBrightness = adjustBrightness,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(ZcashTheme.dimens.spacingLarge))
|
||||
|
||||
|
@ -151,10 +179,18 @@ private fun ReceiveContents(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun QrCode(data: String, size: Dp, modifier: Modifier = Modifier) {
|
||||
private fun QrCode(
|
||||
data: String,
|
||||
size: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
adjustBrightness: Boolean = false,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
BrightenScreen()
|
||||
DisableScreenTimeout()
|
||||
if (adjustBrightness) {
|
||||
BrightenScreen()
|
||||
DisableScreenTimeout()
|
||||
}
|
||||
|
||||
val sizePixels = with(LocalDensity.current) { size.toPx() }.roundToInt()
|
||||
|
||||
// In the future, use actual/expect to switch QR code generator implementations for multiplatform
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="receive_title">Receive</string>
|
||||
<string name="receive_back">Back</string>
|
||||
<string name="receive_back_content_description">Back</string>
|
||||
<string name="receive_brightness_content_description">Adjust brightness</string>
|
||||
<string name="receive_qr_code_content_description">QR code for address</string>
|
||||
<string name="receive_caption">Your Address</string>
|
||||
<string name="receive_see_address_details">See Address Details</string>
|
||||
|
|
|
@ -155,6 +155,7 @@ class ScreenshotTest : UiTestPrerequisites() {
|
|||
),
|
||||
ignoreCase = true
|
||||
).also {
|
||||
it.performScrollTo()
|
||||
it.assertExists()
|
||||
it.performClick()
|
||||
}
|
||||
|
@ -408,7 +409,7 @@ private fun receiveZecScreenshots(
|
|||
composeTestRule.activity.walletViewModel.addresses.value != null
|
||||
}
|
||||
|
||||
composeTestRule.onNode(hasText(resContext.getString(R.string.receive_title))).also {
|
||||
composeTestRule.onNode(hasText(resContext.getString(R.string.receive_title), ignoreCase = true)).also {
|
||||
it.assertExists()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue