Skip to content

Commit

Permalink
Merge pull request #8361 from cketti/qr_code_scanner_update
Browse files Browse the repository at this point in the history
Update QR code scanner screen
  • Loading branch information
cketti authored Oct 18, 2024
2 parents 00dd8f1 + e7b7f7a commit 0cad619
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithTheme
import app.k9mail.core.ui.compose.designsystem.atom.Surface
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.DisplayText

@Preview
@Composable
Expand All @@ -12,8 +13,7 @@ fun QrCodeScannerViewPreview_initial() {
Surface {
QrCodeScannerView(
cameraUseCasesProvider = { emptyList() },
scannedCount = 0,
totalCount = 0,
displayText = DisplayText.HelpText,
onDoneClick = {},
)
}
Expand All @@ -27,8 +27,7 @@ fun QrCodeScannerViewPreview_one_qr_code_scanned() {
Surface {
QrCodeScannerView(
cameraUseCasesProvider = { emptyList() },
scannedCount = 1,
totalCount = 2,
DisplayText.ProgressText(scannedCount = 1, totalCount = 2),
onDoneClick = {},
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleLarge
import app.k9mail.feature.migration.qrcode.domain.QrCodeDomainContract.UseCase.CameraUseCasesProvider
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import android.graphics.Color as AndroidColor

/**
* Displays a camera preview and includes the provided CameraX [UseCase]s.
Expand All @@ -47,6 +48,7 @@ internal fun CameraPreviewView(

val previewView = remember {
PreviewView(context).apply {
setBackgroundColor(AndroidColor.TRANSPARENT)
scaleType = PreviewView.ScaleType.FIT_CENTER
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app.k9mail.feature.migration.qrcode.ui

import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
Expand All @@ -16,26 +15,21 @@ import app.k9mail.feature.migration.qrcode.R

@Composable
internal fun QrCodeScannerBottomContent(
scannedCount: Int,
totalCount: Int,
text: String,
onDoneClick: () -> Unit,
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
if (totalCount > 0) {
TextBodyLarge(
text = stringResource(R.string.migration_qrcode_scanning_progress, scannedCount, totalCount),
modifier = Modifier
.testTag("ScannedStatus")
.padding(vertical = MainTheme.spacings.double)
.padding(start = MainTheme.spacings.double)
.weight(1f),
)
} else {
Spacer(modifier = Modifier.weight(1f))
}
TextBodyLarge(
text = text,
modifier = Modifier
.testTag("ScannedStatus")
.padding(vertical = MainTheme.spacings.double)
.padding(start = MainTheme.spacings.double)
.weight(1f),
)

ButtonOutlined(
text = stringResource(R.string.migration_qrcode_done_button_text),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ internal fun QrCodeScannerContent(
UiPermissionState.Granted -> {
QrCodeScannerView(
cameraUseCasesProvider = cameraUseCasesProvider,
scannedCount = state.scannedCount,
totalCount = state.totalCount,
displayText = state.displayText,
onDoneClick = { onEvent(Event.DoneClicked) },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ internal interface QrCodeScannerContract {

data class State(
val cameraPermissionState: UiPermissionState = UiPermissionState.Unknown,
val scannedCount: Int = 0,
val totalCount: Int = 0,
val displayText: DisplayText = DisplayText.HelpText,
)

sealed interface Event {
Expand All @@ -36,4 +35,9 @@ internal interface QrCodeScannerContract {
Denied,
Waiting,
}

sealed interface DisplayText {
data object HelpText : DisplayText
data class ProgressText(val scannedCount: Int, val totalCount: Int) : DisplayText
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,53 @@ package app.k9mail.feature.migration.qrcode.ui

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.feature.migration.qrcode.R
import app.k9mail.feature.migration.qrcode.domain.QrCodeDomainContract.UseCase
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.DisplayText

@Composable
internal fun QrCodeScannerView(
cameraUseCasesProvider: UseCase.CameraUseCasesProvider,
scannedCount: Int,
totalCount: Int,
displayText: DisplayText,
onDoneClick: () -> Unit,
) {
Column(modifier = Modifier.testTag("QrCodeScannerView")) {
CameraPreviewView(
cameraUseCasesProvider = cameraUseCasesProvider,
modifier = Modifier
.fillMaxWidth()
.padding(
top = MainTheme.spacings.double,
start = MainTheme.spacings.double,
end = MainTheme.spacings.double,
)
.weight(1f),
)

QrCodeScannerBottomContent(
scannedCount = scannedCount,
totalCount = totalCount,
text = buildString(displayText),
onDoneClick = onDoneClick,
)
}
}

@Composable
@ReadOnlyComposable
private fun buildString(text: DisplayText): String {
return when (text) {
DisplayText.HelpText -> {
stringResource(R.string.migration_qrcode_scanning_instructions)
}

is DisplayText.ProgressText -> {
stringResource(R.string.migration_qrcode_scanning_progress, text.scannedCount, text.totalCount)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import app.k9mail.feature.migration.qrcode.domain.QrCodeDomainContract.UseCase
import app.k9mail.feature.migration.qrcode.domain.entity.AccountData
import app.k9mail.feature.migration.qrcode.domain.entity.AccountData.Account
import app.k9mail.feature.migration.qrcode.domain.usecase.QrCodeImageAnalysisProvider
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.DisplayText
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.Effect
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.Event
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.State
Expand Down Expand Up @@ -33,6 +34,9 @@ internal class QrCodeScannerViewModel(
private val unsupportedPayloadHashes = ArrayDeque<ByteString>()
private val accountDataList = mutableListOf<AccountData>()

private var scannedCount = 0
private var totalCount = 0

override val cameraUseCasesProvider: UseCase.CameraUseCasesProvider =
createCameraUseCaseProvider(::handleQrCodeScanned)

Expand Down Expand Up @@ -103,23 +107,22 @@ internal class QrCodeScannerViewModel(
}

private fun handleSupportedPayload(accountData: AccountData) {
val currentState = state.value
if (accountData.sequenceEnd == currentState.totalCount) {
if (accountData.sequenceEnd == totalCount) {
accountDataList.add(accountData)

updateState {
it.copy(scannedCount = accountDataList.size)
}
scannedCount = accountDataList.size
} else {
// Total QR code count doesn't match previous value. The user has probably started over.

supportedPayloadHashes.clear()
accountDataList.clear()
accountDataList.add(accountData)

updateState {
it.copy(scannedCount = 1, totalCount = accountData.sequenceEnd)
}
scannedCount = 1
totalCount = accountData.sequenceEnd
}

updateState {
it.copy(displayText = DisplayText.ProgressText(scannedCount, totalCount))
}

if (accountDataList.size == accountData.sequenceEnd) {
Expand Down
1 change: 1 addition & 0 deletions feature/migration/qrcode/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
<string name="migration_qrcode_permission_denied_message">Go to Android settings, tap permissions, and allow access to the camera.</string>
<string name="migration_qrcode_go_to_settings_button_text">Go to settings</string>
<string name="migration_qrcode_scanning_progress">Scanned %1$s of %2$s</string>
<string name="migration_qrcode_scanning_instructions">Align the QR code provided from Thunderbird Desktop</string>
<string name="migration_qrcode_done_button_text">Done</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,10 @@ import org.robolectric.annotation.Config
class QrCodeScannerBottomContentKtTest : ComposeTest() {

@Test
fun `not having a total count should not show ScannedStatus`() = runComposeTest {
fun `text should be displayed`() = runComposeTest {
setContentWithTheme {
QrCodeScannerBottomContent(
scannedCount = 0,
totalCount = 0,
onDoneClick = {},
)
}

composeTestRule.onNodeWithTag("ScannedStatus").assertDoesNotExist()
composeTestRule.onNodeWithTag("DoneButton").assertExists()
}

@Test
fun `having a total count should show ScannedStatus`() = runComposeTest {
setContentWithTheme {
QrCodeScannerBottomContent(
scannedCount = 1,
totalCount = 2,
text = "Scanned 1 of 2",
onDoneClick = {},
)
}
Expand All @@ -48,8 +33,7 @@ class QrCodeScannerBottomContentKtTest : ComposeTest() {

setContentWithTheme {
QrCodeScannerBottomContent(
scannedCount = 0,
totalCount = 0,
text = "irrelevant",
onDoneClick = { doneClickCount++ },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import app.k9mail.core.ui.compose.testing.mvi.runMviTest
import app.k9mail.core.ui.compose.testing.mvi.turbinesWithInitialStateCheck
import app.k9mail.feature.migration.qrcode.domain.QrCodeDomainContract.UseCase
import app.k9mail.feature.migration.qrcode.domain.usecase.QrCodePayloadReader
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.DisplayText
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.Effect
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.Event
import app.k9mail.feature.migration.qrcode.ui.QrCodeScannerContract.State
Expand Down Expand Up @@ -214,8 +215,10 @@ private class QrCodeScannerScreenRobot(
assertThat(turbines.awaitStateItem()).isEqualTo(
State(
cameraPermissionState = UiPermissionState.Granted,
scannedCount = expectedScannedCount,
totalCount = expectedScannedTotal,
displayText = DisplayText.ProgressText(
scannedCount = expectedScannedCount,
totalCount = expectedScannedTotal,
),
),
)
}
Expand Down

0 comments on commit 0cad619

Please sign in to comment.