[#552] Compose dependencies update (#589)

* [#552] Compose 1.2.1
* [#553] Accompanist 0.25.0
* Material3 dependency update
* Compose Compiler dependency update
* Compose Navigation dependency update
* Fix camera permission multiple displaying
* Added missing TODO description comments
* Improved Scan screen manual test guide
* Bump dependencies again
Co-authored-by: Carter Jernigan <git@carterjernigan.com>
This commit is contained in:
Honza Rychnovsky 2022-09-22 15:55:34 +02:00 committed by GitHub
parent 569e518615
commit 1b75ab4fd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 178 additions and 83 deletions

View File

@ -0,0 +1,55 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ui-integration-test:connectedCheck" type="AndroidTestRunConfigurationType" factoryName="Android Instrumented Tests">
<module name="zcash-android-app.ui-integration-test-lib" />
<option name="TESTING_TYPE" value="0" />
<option name="METHOD_NAME" value="" />
<option name="CLASS_NAME" value="" />
<option name="PACKAGE_NAME" value="" />
<option name="INSTRUMENTATION_RUNNER_CLASS" value="" />
<option name="EXTRA_OPTIONS" value="" />
<option name="INCLUDE_GRADLE_EXTRA_OPTIONS" value="true" />
<option name="RETENTION_ENABLED" value="No" />
<option name="RETENTION_MAX_SNAPSHOTS" value="2" />
<option name="RETENTION_COMPRESS_SNAPSHOTS" value="false" />
<option name="CLEAR_LOGCAT" value="false" />
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
<option name="DEBUGGER_TYPE" value="Auto" />
<Auto>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Auto>
<Hybrid>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Hybrid>
<Java />
<Native>
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
<option name="SHOW_STATIC_VARS" value="true" />
<option name="WORKING_DIR" value="" />
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
</Native>
<Profilers>
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
<option name="STARTUP_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_ENABLED" value="false" />
<option name="STARTUP_CPU_PROFILING_CONFIGURATION_NAME" value="Java/Kotlin Method Sample (legacy)" />
<option name="STARTUP_NATIVE_MEMORY_PROFILING_ENABLED" value="false" />
<option name="NATIVE_MEMORY_SAMPLE_RATE_BYTES" value="2048" />
</Profilers>
<method v="2">
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
</method>
</configuration>
</component>

View File

@ -1,48 +1,61 @@
Note: To be able to fully test the QR Scan screen and its logic, we recommend you to test it on real Android devices, which have hardware camera accessories. Although there is a way on how to test the scanning functionalities on an Android emulator too. See the next section on how to set up a QR code for the emulated camera scene.
# Test Prerequisites
- Prepare at least two Zcash wallet addresses - one valid and one invalid. A valid address for Testnet can be `tmEjY6KfCryQhJ1hKSGiA7p8EeVggpvN78r`. The invalid one can be its modification.
- Check you have a wallet configured in the Zcash wallet app
- Open Zcash wallet app in the system Settings app. Visit the permissions screen, then select Camera and make sure that you have the Camera permission denied.
- Prepare at least two Zcash wallet addresses - one valid and one invalid. A valid address for Testnet can be `tmEjY6KfCryQhJ1hKSGiA7p8EeVggpvN78r`. The invalid one can be its modification.
- The previous step of resetting the Camera permission needs to be repeated before each following subtests by one of these ways:
- Reset the wallet app data from system Settings app to reset the Camera permission
- Reinstall the wallet app
- Change the Camera permission settings by switching between available options (the options may differ on different Android SDK versions).
# Android emulator setup (optional)
This section is optional and is required only if you'd like to test on an Android emulator device.
1. Follow these [steps](https://developer.android.com/studio/install) to download and install Android studio
2. And these [steps](https://developer.android.com/studio/run/managing-avds#createavd) help you set up an Android emulator
3. Then you'll need to create a valid Zcash address QR code image. It can be done, for example, with the [QR Code Generator](https://www.qr-code-generator.com/) tool.
4. Download the image
5. Start the emulator
6. Click on More in the emulator panel to open the Extended controls window
7. Click on Camera
8. Click Add Image in the Wall section
9. Select your QR code image and close the window
10. Once you're in the QR Scan screen with the virtual camera opened, see these [instructions](https://developers.google.com/ar/develop/java/emulator#control_the_virtual_scene) on how to move in virtual scene.
11. The last step is to let the scanner read your QR code to be able to move to the smaller room (behind the dog), which will have the code displayed on the room wall.
1. And these [steps](https://developer.android.com/studio/run/managing-avds#createavd) help you set up an Android emulator
1. Then you'll need to create a valid Zcash address QR code image. It can be done, for example, with the [QR Code Generator](https://www.qr-code-generator.com/) tool.
1. Download the image
1. Start the emulator
1. Click on More in the emulator panel to open the Extended controls window
1. Click on Camera
1. Click Add Image in the Wall section
1. Select your QR code image and close the window
1. Once you're in the QR Scan screen with the virtual camera opened, see these [instructions](https://developers.google.com/ar/develop/java/emulator#control_the_virtual_scene) on how to move in virtual scene.
1. The last step is to let the scanner read your QR code to be able to move to the smaller room (behind the dog), which will have the code displayed on the room wall.
# Check Camera permission allow functionality
1. Open QR Scan screen by QR code icon from the Home screen
2. Camera permission dialog should be prompt
3. Grant camera permission with Allow button (or its modifications)
4. Camera view and its square frame should appear
1. Camera permission dialog should be prompt
1. Grant camera permission with Allow button (or its modifications)
1. Camera view and its square frame should appear
# Check Camera permission deny functionality
1. Open QR Scan screen by QR code icon from the Home screen
2. Camera permission dialog should be prompt
3. Deny camera permission with Deny button (or its modifications)
4. Camera view and its square frame shouldn't be visible. The screen should be black. Also, Open system Settings app button on the bottom side of the screen should be visible now.
5. Hit the button.
6. System Settings app should open on the Zcash wallet app screen.
1. Camera permission dialog should be prompt
1. Deny camera permission with Deny button (or its modifications)
1. Camera view and its square frame shouldn't be visible. The screen should be black. Also, Open system Settings app button on the bottom side of the screen should be visible now.
1. Hit the button.
1. System Settings app should open on the Zcash wallet app screen.
# Check Camera permission dismiss functionality
1. Open QR Scan screen by QR code icon from the Home screen
1. Camera permission dialog should be prompt
1. Dismiss the Camera permission by back navigation or by touching outside the Camera permission popup
1. Rotate the device to trigger a configuration change (make sure the screen rotation is enabled on the device)
1. Ensure that the Camera permission is shown again
1. Leave the QR Scan screen by back navigation; you're on Home screen now
1. Ensure that Camera permission is not shown above the Home screen
# Scan valid QR code
1. Grant the Camera permission with one of the previous procedures
2. Create QR code from the valid Zcash wallet address. You can use, for example, the [QR Code Generator](https://www.qr-code-generator.com/) tool.
3. Scan the created QR code
4. The code should be scanned and validated
5. App should then close the QR Scan screen and navigate to another screen to proceed with the scanned result
1. Create QR code from the valid Zcash wallet address. You can use, for example, the [QR Code Generator](https://www.qr-code-generator.com/) tool.
1. Scan the created QR code
1. The code should be scanned and validated
1. App should then close the QR Scan screen and navigate to another screen to proceed with the scanned result
# Scan invalid QR code
1. Grant the Camera permission with one of the previous procedures
2. Create QR code from the valid Zcash wallet address. You can use, for example, the [QR Code Generator](https://www.qr-code-generator.com/) tool.
3. Scan the created QR code
4. The code should be scanned but not validated
5. The app UI should not be changed and the Camera view should be still available for scanning another codes
1. Create QR code from the valid Zcash wallet address. You can use, for example, the [QR Code Generator](https://www.qr-code-generator.com/) tool.
1. Scan the created QR code
1. The code should be scanned but not validated
1. The app UI should not be changed and the Camera view should be still available for scanning another codes

View File

@ -104,24 +104,24 @@ JGIT_VERSION=6.1.0.202203080745-r
KTLINT_VERSION=0.46.1
PLAY_PUBLISHER_PLUGIN_VERSION=3.7.0
ACCOMPANIST_PERMISSIONS_VERSION=0.23.1
ANDROIDX_ACTIVITY_VERSION=1.5.0
ANDROIDX_ANNOTATION_VERSION=1.4.0
ANDROIDX_APPCOMPAT_VERSION=1.5.0
ACCOMPANIST_PERMISSIONS_VERSION=0.25.1
ANDROIDX_ACTIVITY_VERSION=1.6.0
ANDROIDX_ANNOTATION_VERSION=1.5.0
ANDROIDX_APPCOMPAT_VERSION=1.5.1
ANDROIDX_CAMERA_VERSION=1.1.0
ANDROIDX_COMPOSE_COMPILER_VERSION=1.3.0-beta01
ANDROIDX_COMPOSE_MATERIAL3_VERSION=1.0.0-alpha14
ANDROIDX_COMPOSE_VERSION=1.2.0-rc03
ANDROIDX_COMPOSE_COMPILER_VERSION=1.3.1
ANDROIDX_COMPOSE_MATERIAL3_VERSION=1.0.0-beta03
ANDROIDX_COMPOSE_VERSION=1.2.1
ANDROIDX_CONSTRAINTLAYOUT_VERSION=1.0.1
ANDROIDX_CORE_VERSION=1.8.0
ANDROIDX_CORE_VERSION=1.9.0
ANDROIDX_ESPRESSO_VERSION=3.5.0-alpha07
ANDROIDX_LIFECYCLE_VERSION=2.5.0
ANDROIDX_NAVIGATION_COMPOSE_VERSION=2.5.0
ANDROIDX_LIFECYCLE_VERSION=2.5.1
ANDROIDX_NAVIGATION_COMPOSE_VERSION=2.5.2
ANDROIDX_SECURITY_CRYPTO_VERSION=1.1.0-alpha03
ANDROIDX_SPLASH_SCREEN_VERSION=1.0.0
ANDROIDX_TEST_JUNIT_VERSION=1.1.4-alpha07
ANDROIDX_TEST_ORCHESTRATOR_VERSION=1.4.2-alpha04
ANDROIDX_TEST_CORE_VERSION=1.5.0-alpha01
ANDROIDX_TEST_CORE_VERSION=1.5.0-alpha02
ANDROIDX_TEST_RUNNER_VERSION=1.5.0-alpha04
ANDROIDX_UI_AUTOMATOR_VERSION=2.2.0-alpha1
ANDROIDX_WORK_MANAGER_VERSION=2.7.1

View File

@ -118,7 +118,7 @@ dependencyResolutionManagement {
val androidxComposeCompilerVersion = extra["ANDROIDX_COMPOSE_COMPILER_VERSION"].toString()
val androidxComposeMaterial3Version = extra["ANDROIDX_COMPOSE_MATERIAL3_VERSION"].toString()
val androidxComposeVersion = extra["ANDROIDX_COMPOSE_VERSION"].toString()
val androidxConstraintlayoutVersion = extra["ANDROIDX_CONSTRAINTLAYOUT_VERSION"].toString()
val androidxConstraintLayoutVersion = extra["ANDROIDX_CONSTRAINTLAYOUT_VERSION"].toString()
val androidxCoreVersion = extra["ANDROIDX_CORE_VERSION"].toString()
val androidxEspressoVersion = extra["ANDROIDX_ESPRESSO_VERSION"].toString()
val androidxLifecycleVersion = extra["ANDROIDX_LIFECYCLE_VERSION"].toString()
@ -167,7 +167,7 @@ dependencyResolutionManagement {
library("androidx-compose-ui-fonts", "androidx.compose.ui:ui-text-google-fonts:$androidxComposeVersion")
library("androidx-compose-compiler", "androidx.compose.compiler:compiler:$androidxComposeCompilerVersion")
library("androidx-core", "androidx.core:core-ktx:$androidxCoreVersion")
library("androidx-constraintlayout", "androidx.constraintlayout:constraintlayout-compose:$androidxConstraintlayoutVersion")
library("androidx-constraintlayout", "androidx.constraintlayout:constraintlayout-compose:$androidxConstraintLayoutVersion")
library("androidx-lifecycle-livedata", "androidx.lifecycle:lifecycle-livedata-ktx:$androidxLifecycleVersion")
library("androidx-navigation-compose", "androidx.navigation:navigation-compose:$androidxNavigationComposeVersion")
library("androidx-security-crypto", "androidx.security:security-crypto-ktx:$androidxSecurityCryptoVersion")

View File

@ -1,4 +1,4 @@
package co.electriccoin.zcash.ui.integration.test
package co.electriccoin.zcash.ui.integration.test.common
import android.content.Context
import android.os.Build
@ -50,10 +50,10 @@ fun getPermissionPositiveButtonUiObject(): UiObject? {
)
}
fun waitForDeviceIdle(timeoutMillis: Duration = 1000.milliseconds) {
fun waitForDeviceIdle(timeout: Duration = 1000.milliseconds) {
val instrumentation = InstrumentationRegistry.getInstrumentation()
UiDevice.getInstance(instrumentation).waitForWindowUpdate(
ApplicationProvider.getApplicationContext<Context>().packageName,
timeoutMillis.inWholeMilliseconds
timeout.inWholeMilliseconds
)
}

View File

@ -7,7 +7,7 @@ import androidx.compose.ui.test.onNodeWithTag
import androidx.test.filters.LargeTest
import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.integration.test.common.IntegrationTestingActivity
import co.electriccoin.zcash.ui.integration.test.getPermissionPositiveButtonUiObject
import co.electriccoin.zcash.ui.integration.test.common.getPermissionPositiveButtonUiObject
import co.electriccoin.zcash.ui.screen.scan.ScanTag
import co.electriccoin.zcash.ui.screen.scan.model.ScanState
import org.junit.Assert

View File

@ -12,9 +12,9 @@ import androidx.test.filters.LargeTest
import co.electriccoin.zcash.test.UiTestPrerequisites
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.integration.test.common.IntegrationTestingActivity
import co.electriccoin.zcash.ui.integration.test.getPermissionPositiveButtonUiObject
import co.electriccoin.zcash.ui.integration.test.getStringResource
import co.electriccoin.zcash.ui.integration.test.waitForDeviceIdle
import co.electriccoin.zcash.ui.integration.test.common.getPermissionPositiveButtonUiObject
import co.electriccoin.zcash.ui.integration.test.common.getStringResource
import co.electriccoin.zcash.ui.integration.test.common.waitForDeviceIdle
import co.electriccoin.zcash.ui.screen.scan.ScanTag
import co.electriccoin.zcash.ui.screen.scan.model.ScanState
import org.junit.Assert.assertEquals
@ -93,7 +93,7 @@ class ScanViewTest : UiTestPrerequisites() {
assertEquals(ScanState.Scanning, testSetup.getScanState())
// we need to actively wait for the camera preview initialization
waitForDeviceIdle(timeoutMillis = 5000.milliseconds)
waitForDeviceIdle(timeout = 5000.milliseconds)
composeTestRule.onNodeWithTag(ScanTag.CAMERA_VIEW).also {
it.assertIsDisplayed()

View File

@ -4,8 +4,8 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.integration.test.getPermissionNegativeButtonUiObject
import co.electriccoin.zcash.ui.integration.test.getPermissionPositiveButtonUiObject
import co.electriccoin.zcash.ui.integration.test.common.getPermissionNegativeButtonUiObject
import co.electriccoin.zcash.ui.integration.test.common.getPermissionPositiveButtonUiObject
import co.electriccoin.zcash.ui.screen.scan.model.ScanState
import co.electriccoin.zcash.ui.screen.scan.view.Scan
import org.junit.Assert.assertNotNull

View File

@ -13,8 +13,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
@ -57,8 +57,9 @@ fun About(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun AboutTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.about_title)) },
navigationIcon = {
IconButton(

View File

@ -19,11 +19,12 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDownCircle
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -70,8 +71,9 @@ fun WalletAddresses(walletAddresses: WalletAddresses, onBack: () -> Unit) {
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun WalletDetailTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = {
Text(
text = stringResource(id = R.string.wallet_address_title)

View File

@ -26,8 +26,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -113,12 +113,13 @@ fun Home(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun HomeTopAppBar(
isDebugMenuEnabled: Boolean,
resetSdk: () -> Unit,
wipeEntireWallet: () -> Unit
) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.app_name)) },
actions = {
if (isDebugMenuEnabled) {

View File

@ -23,8 +23,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -100,6 +100,7 @@ fun Onboarding(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun OnboardingTopAppBar(
onboardingState: OnboardingState,
isDebugMenuEnabled: Boolean,
@ -107,7 +108,7 @@ private fun OnboardingTopAppBar(
) {
val currentStage = onboardingState.current.collectAsState().value
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.app_name)) },
navigationIcon =
if (IS_NAVIGATION_IN_APP_BAR && currentStage.hasPrevious()) {

View File

@ -7,11 +7,12 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -83,8 +84,9 @@ fun Profile(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun ProfileTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.profile_title)) },
navigationIcon = {
IconButton(

View File

@ -13,9 +13,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -77,8 +77,9 @@ fun Request(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun RequestTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.request_title)) },
navigationIcon = {
IconButton(
@ -97,6 +98,7 @@ private fun RequestTopAppBar(onBack: () -> Unit) {
// TODO [#217]: Need to handle changing of Locale after user input, but before submitting the button.
// TODO [#288]: TextField component can't do long-press backspace.
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun RequestMainContent(
paddingValues: PaddingValues,
myAddress: WalletAddress.Unified,

View File

@ -25,9 +25,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
@ -137,8 +137,9 @@ fun RestoreWallet(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun RestoreTopAppBar(onBack: () -> Unit, onClear: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.restore_header)) },
navigationIcon = {
IconButton(
@ -269,6 +270,7 @@ private fun ChipGridWithText(
// TODO [#288]: TextField component can't do long-press backspace.
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun NextWordTextField(modifier: Modifier = Modifier, text: String, setText: (String) -> Unit) {
/*
* Treat the user input as a password, but disable the transformation to obscure input.

View File

@ -25,11 +25,11 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
@ -65,16 +65,18 @@ import co.electriccoin.zcash.ui.screen.scan.model.ScanState
import co.electriccoin.zcash.ui.screen.scan.util.QrCodeAnalyzer
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.google.accompanist.permissions.shouldShowRationale
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.guava.await
import java.util.UUID
import kotlin.math.roundToInt
// TODO [#423]: https://github.com/zcash/secant-android-wallet/issues/423
// TODO QR scan screen elements transparency
@Preview("Scan")
@Composable
fun PreviewScan() {
@ -159,8 +161,9 @@ fun ScanBottomItems(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun ScanTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.scan_header)) },
navigationIcon = {
IconButton(
@ -194,7 +197,7 @@ private fun ScanMainContent(
val (scanState, setScanState) = rememberSaveable {
mutableStateOf(
if (permissionState.hasPermission) {
if (permissionState.status.isGranted) {
ScanState.Scanning
} else {
ScanState.Permission
@ -202,14 +205,19 @@ private fun ScanMainContent(
)
}
if (!permissionState.hasPermission) {
if (!permissionState.status.isGranted) {
setScanState(ScanState.Permission)
LaunchedEffect(key1 = UUID.randomUUID()) {
permissionState.launchPermissionRequest()
if (permissionState.status.shouldShowRationale) {
// keep blank screen with a link to the app settings
// user denied the permission previously
} else {
LaunchedEffect(key1 = true) {
permissionState.launchPermissionRequest()
}
}
} else if (scanState == ScanState.Failed) {
// keep current state
} else if (permissionState.hasPermission) {
} else if (permissionState.status.isGranted) {
if (scanState != ScanState.Scanning) {
setScanState(ScanState.Scanning)
}
@ -240,6 +248,7 @@ private fun ScanMainContent(
}
ScanState.Scanning -> {
// TODO [#437]: https://github.com/zcash/secant-android-wallet/issues/437
// TODO Scan QR Screen Frame Analysing
onScanStateChanged(ScanState.Scanning)
ScanCameraView(
onScanned = onScanned,
@ -312,7 +321,7 @@ fun ScanCameraView(
// we check the permission first, as the ProcessCameraProvider's emit won't be called again after
// recomposition with the permission granted
val cameraProviderFlow = if (permissionState.hasPermission) {
val cameraProviderFlow = if (permissionState.status.isGranted) {
remember {
flow<ProcessCameraProvider> { emit(ProcessCameraProvider.getInstance(context).await()) }
}

View File

@ -11,8 +11,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -64,8 +64,9 @@ fun Seed(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SeedTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.seed_title)) },
navigationIcon = {
IconButton(

View File

@ -16,9 +16,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -96,8 +96,9 @@ fun Send(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SendTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.send_title)) },
navigationIcon = {
IconButton(
@ -146,6 +147,7 @@ private fun SendMainContent(
// TODO [#294]: DetektAll failed LongMethod
@Suppress("LongMethod")
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SendForm(
paddingValues: PaddingValues,
myBalance: Zatoshi,

View File

@ -9,8 +9,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -57,8 +57,9 @@ fun Settings(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SettingsTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.settings_header)) },
navigationIcon = {
IconButton(

View File

@ -14,11 +14,11 @@ import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
@ -83,8 +83,9 @@ fun Support(
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SupportTopAppBar(onBack: () -> Unit) {
SmallTopAppBar(
TopAppBar(
title = { Text(text = stringResource(id = R.string.support_header)) },
navigationIcon = {
IconButton(
@ -100,6 +101,7 @@ private fun SupportTopAppBar(onBack: () -> Unit) {
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SupportMainContent(
paddingValues: PaddingValues,
message: String,

View File

@ -14,10 +14,10 @@ import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -111,8 +111,9 @@ fun UpdateOverlayRunning(updateInfo: UpdateInfo) {
}
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun UpdateTopAppBar(updateInfo: UpdateInfo) {
SmallTopAppBar(
TopAppBar(
title = {
Text(
text = stringResource(