Merge branch 'refs/heads/main' into exchange-rate-implementation

# Conflicts:
#	CHANGELOG.md
#	docs/whatsNew/WHATS_NEW_EN.md
This commit is contained in:
Milan Cerovsky 2024-08-12 17:29:01 +02:00
commit 77f1c163ad
11 changed files with 95 additions and 49 deletions

View File

@ -85,7 +85,7 @@ jobs:
ref: main
fetch-depth: 0 # To fetch all commits
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -112,7 +112,7 @@ jobs:
# Note that this step is not currently used due to #1033
if: false
id: auth_google_play
uses: google-github-actions/auth@71fee32a0bb7e97b4d33d548e7d957010649d8fa
uses: google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2
with:
create_credentials_file: true
project_id: ${{ secrets.GOOGLE_PLAY_CLOUD_PROJECT }}
@ -167,7 +167,7 @@ jobs:
zip -r ${BINARIES_ZIP_PATH} . -i app/build/outputs/apk/\*/\*.apk app/build/outputs/apk_from_bundle/\*/\*.apk app/build/outputs/bundle/\*/\*.aab
zip -r ${MAPPINGS_ZIP_PATH} . -i app/build/outputs/mapping/\*/mapping.txt
- name: Upload Artifacts
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 5
with:
name: Binaries

View File

@ -73,7 +73,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -96,7 +96,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -120,7 +120,7 @@ jobs:
zip -r ${REPORTS_ZIP_PATH} . -i build/reports/detekt/*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Detekt static analysis results
@ -136,7 +136,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -160,7 +160,7 @@ jobs:
zip -r ${REPORTS_ZIP_PATH} . -i build/reports/ktlint/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Ktlint static analysis results
@ -176,7 +176,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -203,7 +203,7 @@ jobs:
zip -r ${LINT_ZIP_PATH} . -i \*build/reports/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Android Lint static analysis results
@ -219,7 +219,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -244,7 +244,7 @@ jobs:
zip -r ${RESULTS_ZIP_PATH} . -i \*build/reports/\* \*/build/kover/html/\* \*/build/kover/xml/report.xml
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Test Kotlin modules results
@ -263,7 +263,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -277,7 +277,7 @@ jobs:
./gradlew assembleDebug assembleAndroidTest assembleZcashmainnetDebug assembleZcashtestnetDebug
- name: Authenticate to Google Cloud for Firebase Test Lab
id: auth_test_lab
uses: google-github-actions/auth@71fee32a0bb7e97b4d33d548e7d957010649d8fa
uses: google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2
with:
create_credentials_file: true
project_id: ${{ vars.FIREBASE_TEST_LAB_PROJECT }}
@ -309,7 +309,7 @@ jobs:
zip -r ${TEST_RESULTS_ZIP_PATH} . -i build/fladle/\* \*/build/outputs/androidTest-results/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Test Android modules with FTL results
@ -326,7 +326,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -356,7 +356,7 @@ jobs:
zip -r ${TEST_RESULTS_ZIP_PATH} . -i \*/build/test-results/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Test Android libs with WTF results
@ -373,7 +373,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -403,7 +403,7 @@ jobs:
zip -r ${TEST_RESULTS_ZIP_PATH} . -i \*/build/test-results/\*
- name: Upload Artifacts
if: ${{ always() }}
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 1
with:
name: Test Android app with WTF results
@ -423,7 +423,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -451,7 +451,7 @@ jobs:
./gradlew :app:assembleDebug
- name: Authenticate to Google Cloud for Firebase Test Lab
id: auth_test_lab
uses: google-github-actions/auth@71fee32a0bb7e97b4d33d548e7d957010649d8fa
uses: google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2
with:
create_credentials_file: true
project_id: ${{ vars.FIREBASE_TEST_LAB_PROJECT }}
@ -477,7 +477,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -530,7 +530,7 @@ jobs:
zip -r ${MAPPINGS_ZIP_PATH} . -i *app/build/outputs/mapping/*/mapping.txt
zip -r ${COMPOSE_METRICS_ZIP_PATH} . -i \*/build/compose-metrics/\* \*/build/compose-reports/\*
- name: Upload Artifacts
uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a
timeout-minutes: 2
with:
name: Binaries
@ -550,7 +550,7 @@ jobs:
timeout-minutes: 1
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Set up Java
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9
uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018
timeout-minutes: 1
with:
distribution: 'temurin'
@ -560,7 +560,7 @@ jobs:
timeout-minutes: 5
- name: Authenticate to Google Cloud for Firebase Test Lab
id: auth_test_lab
uses: google-github-actions/auth@71fee32a0bb7e97b4d33d548e7d957010649d8fa
uses: google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2
with:
create_credentials_file: true
project_id: ${{ vars.FIREBASE_TEST_LAB_PROJECT }}

View File

@ -10,6 +10,18 @@ and this application adheres to [Semantic Versioning](https://semver.org/spec/v2
- Balance now also displays USD value
- An option to enter USD amount in Send Transaction screen
## Changed
- Android NDK version has been bumped to 26.1.10909125
## Fixed
- The app screenshot testing has been re-enabled after we moved away from AppCompat components
## [1.1.5 (706)] - 2024-08-09
### Changed
- Adopted the latest Zcash SDK version 2.1.3, which brings a significant block synchronization speed-up and improved
UTXOs fetching logic
## [1.1.4 (700)] - 2024-07-23
### Added

View File

@ -134,6 +134,9 @@ object ChangelogParser {
}
}
return subList(startIndex, endIndex)
.onEach { log("Parser: before formatting item: $it") }
// To remove hard line wrap from AS
.map { it.replace("\n ", "") }
.joinToString(prefix = "\n", separator = "\n")
.takeIf { it.isNotBlank() }?.let {
ChangelogEntrySection(title = title, content = it)

View File

@ -13,6 +13,12 @@ directly impact users rather than highlighting other key architectural updates.*
- Balance now also displays USD value
- An option to enter USD amount in Send Transaction screen
## [1.1.5 (706)] - 2024-08-09
### Changed
- We adopted the latest Zcash SDK version 2.1.3, which significantly improves block synchronization speed.
- We also improved the logic for fetching transparent transactions.
## [1.1.4 (700)] - 2024-07-23
### Added

View File

@ -61,7 +61,7 @@ NDK_DEBUG_SYMBOL_LEVEL=symbol_table
# VERSION_CODE is effectively ignored. VERSION_NAME is suffixed with the version code.
# If not using automated Google Play deployment, then these serve as the actual version numbers.
ZCASH_VERSION_CODE=1
ZCASH_VERSION_NAME=1.1.4
ZCASH_VERSION_NAME=1.1.5
# Set these fields, as you need them (e.g. with values "Zcash X" and "co.electriccoin.zcash.x")
# to distinguish a different release build that can be installed alongside the official version
@ -142,7 +142,7 @@ ANDROID_MIN_SDK_VERSION=27
ANDROID_TARGET_SDK_VERSION=34
ANDROID_COMPILE_SDK_VERSION=34
ANDROID_NDK_VERSION=23.0.7599858
ANDROID_NDK_VERSION=26.1.10909125
ANDROID_GRADLE_PLUGIN_VERSION=8.5.0
DETEKT_VERSION=1.23.6
@ -204,7 +204,7 @@ LOTTIE_VERSION=6.5.0
ZCASH_BIP39_VERSION=1.0.8
# WARNING: Ensure a non-snapshot version is used before releasing to production
ZCASH_SDK_VERSION=2.1.2
ZCASH_SDK_VERSION=2.1.3
# Toolchain is the Java version used to build the application, which is separate from the
# Java version used to run the application.

View File

@ -27,10 +27,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.painterResource
import co.electriccoin.zcash.ui.design.R
import co.electriccoin.zcash.ui.design.component.AnimationConstants.ANIMATION_DURATION
import co.electriccoin.zcash.ui.design.component.AnimationConstants.INITIAL_DELAY
import co.electriccoin.zcash.ui.design.component.AnimationConstants.WELCOME_ANIM_TEST_TAG
import co.electriccoin.zcash.ui.design.theme.ZcashTheme
import co.electriccoin.zcash.ui.design.util.screenHeight
import kotlinx.coroutines.delay
@ -40,6 +42,7 @@ import kotlin.time.Duration.Companion.milliseconds
object AnimationConstants {
const val ANIMATION_DURATION = 700
const val INITIAL_DELAY = 1000
const val WELCOME_ANIM_TEST_TAG = "WELCOME_ANIM_TEST_TAG"
fun together() = (ANIMATION_DURATION + INITIAL_DELAY).toLong()
}
@ -56,7 +59,7 @@ fun WelcomeAnimationAutostart(
WelcomeAnimation(
animationState = currentAnimationState,
modifier = modifier
modifier = modifier.testTag(WELCOME_ANIM_TEST_TAG)
)
// Let's start the animation automatically in case e.g. authentication is not involved

View File

@ -596,6 +596,11 @@ sealed class SecretState {
class Ready(val persistableWallet: PersistableWallet) : SecretState()
}
/**
* This constant sets the default limitation on the length of the stack trace in the [SynchronizerError]
*/
const val STACKTRACE_LIMIT = 250
// TODO [#529]: Localize Synchronizer Errors
// TODO [#529]: https://github.com/Electric-Coin-Company/zashi-android/issues/529
@ -605,24 +610,36 @@ sealed class SecretState {
sealed class SynchronizerError {
abstract fun getCauseMessage(): String?
abstract fun getStackTrace(limit: Int = STACKTRACE_LIMIT): String?
class Critical(val error: Throwable?) : SynchronizerError() {
override fun getCauseMessage(): String? = error?.message
override fun getStackTrace(limit: Int): String? = error?.stackTraceToString()?.substring(0..limit)
}
class Processor(val error: Throwable?) : SynchronizerError() {
override fun getCauseMessage(): String? = error?.message
override fun getStackTrace(limit: Int): String? = error?.stackTraceToString()?.substring(0..limit)
}
class Submission(val error: Throwable?) : SynchronizerError() {
override fun getCauseMessage(): String? = error?.message
override fun getStackTrace(limit: Int): String? = error?.stackTraceToString()?.substring(0..limit)
}
class Setup(val error: Throwable?) : SynchronizerError() {
override fun getCauseMessage(): String? = error?.message
override fun getStackTrace(limit: Int): String? = error?.stackTraceToString()?.substring(0..limit)
}
class Chain(val x: BlockHeight, val y: BlockHeight) : SynchronizerError() {
override fun getCauseMessage(): String = "$x, $y"
override fun getStackTrace(limit: Int): String? = null
}
}

View File

@ -13,6 +13,7 @@ import co.electriccoin.zcash.ui.common.extension.toKotlinLocale
import co.electriccoin.zcash.ui.common.model.WalletSnapshot
import co.electriccoin.zcash.ui.common.model.spendableBalance
import co.electriccoin.zcash.ui.common.model.totalBalance
import co.electriccoin.zcash.ui.common.viewmodel.STACKTRACE_LIMIT
data class WalletDisplayValues(
val progress: PercentDecimal,
@ -102,7 +103,9 @@ data class WalletDisplayValues(
context.getString(
R.string.balances_status_error_dialog_cause,
walletSnapshot.synchronizerError.getCauseMessage()
?: context.getString(R.string.balances_status_error_dialog_unknown)
?: context.getString(R.string.balances_status_error_dialog_cause_unknown),
walletSnapshot.synchronizerError.getStackTrace(limit = STACKTRACE_LIMIT)
?: context.getString(R.string.balances_status_error_dialog_stacktrace_unknown)
)
)
}

View File

@ -30,12 +30,17 @@
<string name="balances_status_error_dialog_connection">
Disconnected. Please check your internet connection.
</string>
<string name="balances_status_error_dialog_cause" formatted="true">
Error: <xliff:g id="error_cause" example="Block scanning problem">%1$s</xliff:g>
<string name="balances_status_error_dialog_cause" formatted="true">Error:
<xliff:g id="error_cause" example="Block scanning problem">%1$s</xliff:g>\n\nStacktrace:
<xliff:g id="error_stacktrace"
example="java.lang.IllegalStateException: Unsupported wallet state
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
Caused by: java.lang.RuntimeException: Failure from Rust backend">%2$s</xliff:g>
</string>
<string name="balances_status_error_dialog_unknown">
<string name="balances_status_error_dialog_cause_unknown">
Unknown cause. Please contact our support team if the problem persists.
</string>
<string name="balances_status_error_dialog_stacktrace_unknown">Unknown stacktrace.</string>
<string name="balances_status_dialog_stopped">Synchronization is stopped. It will resume soon.</string>
<string name="balances_status_dialog_button">OK</string>

View File

@ -2,26 +2,14 @@
package co.electroniccoin.zcash.ui.screenshot
import org.junit.Test
// NOTE: this is just a placeholder test to satisfy this module test settings and will be removed once the below
// issue is resolved
class ScreenshotTest {
@Test
fun placeholderTest() {
assert(true)
}
}
/*
TODO [#1448]: Re-enable or rework screenshot testing
TODO [#1448]: https://github.com/Electric-Coin-Company/zashi-android/issues/1448
import android.content.Context
import android.os.Build
import android.os.LocaleList
import androidx.activity.viewModels
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.hasContentDescription
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.ComposeContentTestRule
@ -54,6 +42,7 @@ import co.electriccoin.zcash.ui.MainActivity
import co.electriccoin.zcash.ui.NavigationTargets
import co.electriccoin.zcash.ui.R
import co.electriccoin.zcash.ui.common.viewmodel.SecretState
import co.electriccoin.zcash.ui.design.component.AnimationConstants.WELCOME_ANIM_TEST_TAG
import co.electriccoin.zcash.ui.design.component.ConfigurationOverride
import co.electriccoin.zcash.ui.design.component.UiMode
import co.electriccoin.zcash.ui.screen.account.AccountTag
@ -168,6 +157,7 @@ class ScreenshotTest : UiTestPrerequisites() {
}
}
@OptIn(ExperimentalTestApi::class)
@Suppress("LongMethod", "CyclomaticComplexMethod")
private fun takeScreenshotsForRestoreWallet(
resContext: Context,
@ -183,6 +173,8 @@ class ScreenshotTest : UiTestPrerequisites() {
composeTestRule.activity.walletViewModel.secretState.value is SecretState.None
}
composeTestRule.waitUntilDoesNotExist(hasTestTag(WELCOME_ANIM_TEST_TAG), DEFAULT_TIMEOUT_MILLISECONDS)
composeTestRule.onNodeWithText(
text =
resContext.getString(
@ -324,6 +316,7 @@ class ScreenshotTest : UiTestPrerequisites() {
}
}
@OptIn(ExperimentalTestApi::class)
private fun onboardingScreenshots(
resContext: Context,
tag: String,
@ -339,6 +332,8 @@ private fun onboardingScreenshots(
ScreenshotTest.takeScreenshot(tag, "Onboarding 1")
}
composeTestRule.waitUntilDoesNotExist(hasTestTag(WELCOME_ANIM_TEST_TAG), DEFAULT_TIMEOUT_MILLISECONDS)
composeTestRule.onNodeWithText(
text = resContext.getString(R.string.onboarding_create_new_wallet),
ignoreCase = true
@ -347,7 +342,10 @@ private fun onboardingScreenshots(
}
// Security Warning screen
composeTestRule.onNodeWithText(text = resContext.getString(R.string.security_warning_acknowledge)).also {
composeTestRule.onNodeWithText(
text = resContext.getString(R.string.security_warning_acknowledge),
ignoreCase = true
).also {
it.assertExists()
it.performClick()
ScreenshotTest.takeScreenshot(tag, "Security Warning")
@ -551,4 +549,3 @@ private fun seedScreenshots(
ScreenshotTest.takeScreenshot(tag, "Seed 1")
}
*/