Updated on 2026-08-14
This commit is contained in:
commit
4b6c4381d4
9 changed files with 65 additions and 22 deletions
|
|
@ -277,6 +277,7 @@ internal class BiometricUserWalletsListManager(
|
|||
|
||||
prevState.copy(
|
||||
userWallets = newUserWallets,
|
||||
encryptionKeys = encryptionKeys,
|
||||
isLocked = newUserWallets.any(UserWallet::isLocked),
|
||||
)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -11,20 +11,20 @@ internal sealed interface SaveWalletAction : Action {
|
|||
val backupCardsIds: Set<String>?,
|
||||
) : SaveWalletAction
|
||||
|
||||
object Save : SaveWalletAction {
|
||||
object Success : SaveWalletAction
|
||||
data object Save : SaveWalletAction {
|
||||
data object Success : SaveWalletAction
|
||||
data class Error(val error: TangemError) : SaveWalletAction
|
||||
}
|
||||
|
||||
object AllowToUseBiometrics : SaveWalletAction
|
||||
data object AllowToUseBiometrics : SaveWalletAction
|
||||
|
||||
object Dismiss : SaveWalletAction
|
||||
data object Dismiss : SaveWalletAction
|
||||
|
||||
object CloseError : SaveWalletAction
|
||||
object EnrollBiometrics : SaveWalletAction {
|
||||
object Enroll : SaveWalletAction
|
||||
object Cancel : SaveWalletAction
|
||||
data object CloseError : SaveWalletAction
|
||||
data object EnrollBiometrics : SaveWalletAction {
|
||||
data object Enroll : SaveWalletAction
|
||||
data object Cancel : SaveWalletAction
|
||||
}
|
||||
|
||||
object SaveWalletWasShown : SaveWalletAction
|
||||
data object SaveWalletWasShown : SaveWalletAction
|
||||
}
|
||||
|
|
@ -147,6 +147,11 @@ internal class SaveWalletMiddleware {
|
|||
}
|
||||
|
||||
private fun allowToUseBiometrics(state: SaveWalletState) {
|
||||
if (tangemSdkManager.needEnrollBiometrics) {
|
||||
store.dispatchOnMain(SaveWalletAction.EnrollBiometrics)
|
||||
return
|
||||
}
|
||||
|
||||
val scanResponse = state.backupInfo?.scanResponse
|
||||
?: store.state.globalState.scanResponse
|
||||
?: return
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ import com.google.mlkit.vision.common.InputImage
|
|||
import com.tangem.core.ui.res.TangemTheme
|
||||
import com.tangem.core.ui.screen.ComposeFragment
|
||||
import com.tangem.core.ui.theme.AppThemeModeHolder
|
||||
import com.tangem.feature.qrscanning.presentation.QrScanningContent
|
||||
import com.tangem.feature.qrscanning.viewmodel.QrScanningViewModel
|
||||
import com.tangem.feature.qrscanning.inner.MLKitBarcodeAnalyzer
|
||||
import com.tangem.feature.qrscanning.navigation.QrScanningInnerRouter
|
||||
import com.tangem.feature.qrscanning.presentation.QrScanningContent
|
||||
import com.tangem.feature.qrscanning.viewmodel.QrScanningViewModel
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
|
@ -47,6 +47,11 @@ internal class QrScanningFragment : ComposeFragment() {
|
|||
private val viewModel by viewModels<QrScanningViewModel>()
|
||||
|
||||
private var cameraExecutor: ExecutorService by Delegates.notNull()
|
||||
// Camera requires its own analyzer instance due to flow of frames needed to be analyzed.
|
||||
// Each new frame can cancel previous analysis e.i. image from the gallery can be skipped.
|
||||
private val cameraAnalyzer: MLKitBarcodeAnalyzer by lazy(LazyThreadSafetyMode.NONE) {
|
||||
MLKitBarcodeAnalyzer(viewModel::onQrScanned)
|
||||
}
|
||||
private val analyzer: MLKitBarcodeAnalyzer by lazy(LazyThreadSafetyMode.NONE) {
|
||||
MLKitBarcodeAnalyzer(viewModel::onQrScanned)
|
||||
}
|
||||
|
|
@ -69,6 +74,11 @@ internal class QrScanningFragment : ComposeFragment() {
|
|||
requestCameraPermission()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
checkPermissionGranted()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraPermissionLauncher.unregister()
|
||||
|
|
@ -80,11 +90,14 @@ internal class QrScanningFragment : ComposeFragment() {
|
|||
StatusBarTransparencyDisposable()
|
||||
QrScanningContent(
|
||||
executor = { cameraExecutor },
|
||||
analyzer = { analyzer },
|
||||
analyzer = { cameraAnalyzer },
|
||||
uiState = viewModel.uiState.collectAsStateWithLifecycle().value,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for requesting permission if there isn't one.
|
||||
*/
|
||||
private fun requestCameraPermission() {
|
||||
if (
|
||||
ContextCompat.checkSelfPermission(
|
||||
|
|
@ -96,6 +109,20 @@ internal class QrScanningFragment : ComposeFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for checking if permission was granted after user opened Settings screen.
|
||||
* If permission was granted dismiss bottom sheet.
|
||||
*/
|
||||
private fun checkPermissionGranted() {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
Manifest.permission.CAMERA,
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
viewModel.onDismissBottomSheetState()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun create() = QrScanningFragment()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ private fun CameraDeniedBottomSheet(content: CameraDeniedBottomSheetConfig) {
|
|||
val intent: Intent = Intent(
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
|
||||
Uri.fromParts("package", context.packageName, null),
|
||||
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
ContextCompat.startActivity(context, intent, null)
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ import com.tangem.feature.qrscanning.SourceType
|
|||
import com.tangem.feature.qrscanning.navigation.QrScanningInnerRouter
|
||||
import com.tangem.feature.qrscanning.presentation.QrScanningState
|
||||
import com.tangem.feature.qrscanning.presentation.QrScanningStateController
|
||||
import com.tangem.feature.qrscanning.presentation.transformers.ShowCameraDeniedBottomSheetTransformer
|
||||
import com.tangem.feature.qrscanning.presentation.transformers.DismissBottomSheetTransformer
|
||||
import com.tangem.feature.qrscanning.presentation.transformers.InitializeQrScanningStateTransformer
|
||||
import com.tangem.feature.qrscanning.presentation.transformers.ShowCameraDeniedBottomSheetTransformer
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
|
|
@ -43,4 +44,8 @@ internal class QrScanningViewModel @Inject constructor(
|
|||
fun onCameraDeniedState() {
|
||||
stateHolder.update(ShowCameraDeniedBottomSheetTransformer(clickIntents))
|
||||
}
|
||||
|
||||
fun onDismissBottomSheetState() {
|
||||
stateHolder.update(DismissBottomSheetTransformer())
|
||||
}
|
||||
}
|
||||
|
|
@ -703,6 +703,7 @@ internal class StateBuilder(
|
|||
return uiState.copy(
|
||||
sendCardData = uiState.sendCardData.copy(
|
||||
balance = cryptoCurrencyStatus.getFormattedAmount(isNeedSymbol = false),
|
||||
token = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -716,6 +717,7 @@ internal class StateBuilder(
|
|||
return uiState.copy(
|
||||
receiveCardData = uiState.receiveCardData.copy(
|
||||
balance = cryptoCurrencyStatus.getFormattedAmount(isNeedSymbol = false),
|
||||
token = cryptoCurrencyStatus,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -745,6 +745,8 @@ internal class SwapViewModel @Inject constructor(
|
|||
dataState = dataState.copy(toCryptoCurrency = it)
|
||||
stateBuilder.updateReceiveCurrencyBalance(uiState, it)
|
||||
}
|
||||
|
||||
startLoadingQuotesFromLastState(isSilent = true)
|
||||
}
|
||||
.flowOn(dispatchers.main)
|
||||
.launchIn(viewModelScope)
|
||||
|
|
|
|||
|
|
@ -177,14 +177,8 @@ internal class WalletViewModel @Inject constructor(
|
|||
is WalletsUpdateActionResolver.Action.UpdateWalletName -> {
|
||||
stateHolder.update(transformer = RenameWalletTransformer(action.selectedWalletId, action.name))
|
||||
}
|
||||
is WalletsUpdateActionResolver.Action.NoAccessibleWallets -> {
|
||||
stateHolder.clear()
|
||||
router.popBackStack(screen = AppScreen.Welcome)
|
||||
}
|
||||
is WalletsUpdateActionResolver.Action.NoWallets -> {
|
||||
stateHolder.clear()
|
||||
router.popBackStack(screen = AppScreen.Home)
|
||||
}
|
||||
is WalletsUpdateActionResolver.Action.NoAccessibleWallets -> closeScreen(screen = AppScreen.Welcome)
|
||||
is WalletsUpdateActionResolver.Action.NoWallets -> closeScreen(screen = AppScreen.Home)
|
||||
is WalletsUpdateActionResolver.Action.Unknown -> Unit
|
||||
}
|
||||
}
|
||||
|
|
@ -295,6 +289,13 @@ internal class WalletViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
private fun closeScreen(screen: AppScreen) {
|
||||
if (!screenLifecycleProvider.isBackground) {
|
||||
stateHolder.clear()
|
||||
router.popBackStack(screen = screen)
|
||||
}
|
||||
}
|
||||
|
||||
private fun scrollToWallet(index: Int, onConsume: () -> Unit = {}) {
|
||||
stateHolder.update(
|
||||
ScrollToWalletTransformer(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue