Updated on 2026-08-14

This commit is contained in:
Tangem 2024-01-10 15:03:48 +03:00
parent 2a689bbbe4
commit ee04820594
24 changed files with 384 additions and 268 deletions

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M8.5,13.5L11,16.5L14.5,12L19,18H5M21,19V5C21,3.89 20.1,3 19,3H5C4.47,3 3.961,3.211 3.586,3.586C3.211,3.961 3,4.47 3,5V19C3,19.53 3.211,20.039 3.586,20.414C3.961,20.789 4.47,21 5,21H19C19.53,21 20.039,20.789 20.414,20.414C20.789,20.039 21,19.53 21,19Z"
android:fillColor="#ffffff"/>
</vector>

View file

@ -8,5 +8,6 @@ interface QrScanningRouter {
companion object {
const val SOURCE_KEY = "source"
const val NETWORK_KEY = "network"
}
}

View file

@ -8,17 +8,17 @@ plugins {
android {
namespace = "com.tangem.feature.qrscanning.impl"
viewBinding {
enable = true
}
}
dependencies {
/** Core */
implementation(projects.core.ui)
implementation(projects.core.utils)
implementation(projects.core.navigation)
implementation(deps.androidx.fragment.ktx)
implementation(deps.viewBindingDelegate)
/** Camera */
implementation(deps.camera.camera2)
@ -42,6 +42,12 @@ dependencies {
/** Compose */
implementation(deps.compose.foundation)
implementation(deps.compose.ui)
implementation(deps.compose.ui.tooling)
implementation(deps.compose.material3)
implementation(deps.compose.accompanist.systemUiController)
/** Other dependencies */
implementation(deps.arrow.core)
implementation(deps.timber)
}

View file

@ -1,5 +0,0 @@
package com.tangem.feature.qrscanning
const val SCAN_QR_REQUEST_CODE = 1001
const val SCAN_RESULT = "scanResult"
const val PERMISSION_REQUEST_CODE = 16

View file

@ -1,8 +0,0 @@
package com.tangem.feature.qrscanning
import androidx.fragment.app.Fragment
internal class DefaultQrScanningRouter : QrScanningRouter {
override fun getEntryFragment(): Fragment = QrScanningFragment.create()
}

View file

@ -3,98 +3,86 @@ package com.tangem.feature.qrscanning
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.common.util.concurrent.ListenableFuture
import com.tangem.feature.qrscanning.impl.R
import com.tangem.feature.qrscanning.impl.databinding.LayoutQrScanningBinding
import com.tangem.feature.qrscanning.inner.PreviewBinder
import com.tangem.core.ui.components.SystemBarsEffect
import com.tangem.core.ui.screen.ComposeFragment
import com.tangem.core.ui.theme.AppThemeModeHolder
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 com.tangem.core.navigation.NavigationAction
// import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
// import com.tangem.tap.features.details.ui.walletconnect.dialogs.PreviewBinder
// import com.tangem.tap.store
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import javax.inject.Inject
import kotlin.properties.Delegates
@AndroidEntryPoint
internal class QrScanningFragment : Fragment(R.layout.layout_qr_scanning) {
internal class QrScanningFragment : ComposeFragment() {
private val binding: LayoutQrScanningBinding by viewBinding(LayoutQrScanningBinding::bind)
@Inject
override lateinit var appThemeModeHolder: AppThemeModeHolder
private val binder = PreviewBinder()
@Inject
lateinit var router: QrScanningRouter
private val innerRouter: QrScanningInnerRouter
get() = requireNotNull(router as? QrScanningInnerRouter) {
"innerRouter should be instance of QrScanningInnerRouter"
}
private val viewModel by viewModels<QrScanningViewModel>()
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
private var cameraExecutor: ExecutorService? = null
private var cameraExecutor: ExecutorService by Delegates.notNull()
private val cameraPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
if (!it) parentFragmentManager.popBackStack()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setFitSystemWindows(fit = true)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (!permissionIsGranted()) requestPermission()
cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
viewModel.router = innerRouter
cameraExecutor = Executors.newSingleThreadExecutor()
cameraProviderFuture?.addListener(
{
val cameraProvider = cameraProviderFuture?.get()
binder.bindPreview(
context = requireContext(),
binding = binding,
lifecycleOwner = this,
cameraProvider = requireNotNull(cameraProvider),
cameraExecutor = requireNotNull(cameraExecutor),
onScanned = { result ->
parentFragmentManager.popBackStack()
setFitSystemWindows(fit = false)
if (result.isNotBlank()) {
viewModel.onQrScanned(result)
}
},
)
},
ContextCompat.getMainExecutor(requireContext()),
)
binding.overlay.post {
binding.overlay.setViewFinder()
}
requestCameraPermission()
}
override fun onDestroy() {
super.onDestroy()
setFitSystemWindows(fit = true)
cameraPermissionLauncher.unregister()
cameraExecutor.shutdown()
}
@Composable
override fun ScreenContent(modifier: Modifier) {
SystemBarsEffect {
setSystemBarsColor(Color.Transparent, darkIcons = false)
}
QrScanningContent(
executor = { cameraExecutor },
analyzer = { MLKitBarcodeAnalyzer(viewModel::onQrScanned) },
uiState = viewModel.uiState,
)
setFitSystemWindows(fit = false)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode != PERMISSION_REQUEST_CODE) return
if (grantResults.isEmpty() || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
parentFragmentManager.popBackStack()
private fun requestCameraPermission() {
if (
ContextCompat.checkSelfPermission(
requireContext(),
Manifest.permission.CAMERA,
) == PackageManager.PERMISSION_DENIED
) {
cameraPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
private fun permissionIsGranted(): Boolean {
val cameraPermission = ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
return cameraPermission == PackageManager.PERMISSION_GRANTED
}
private fun requestPermission() {
requestPermissions(arrayOf(Manifest.permission.CAMERA), PERMISSION_REQUEST_CODE)
}
private fun setFitSystemWindows(fit: Boolean) {
activity?.window?.let {
WindowCompat.setDecorFitsSystemWindows(it, fit)

View file

@ -1,18 +0,0 @@
package com.tangem.feature.qrscanning
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityScoped
@Module
@InstallIn(ActivityComponent::class)
internal object QrScanningRouterModule {
@Provides
@ActivityScoped
fun provideQrScanRouter(): QrScanningRouter {
return DefaultQrScanningRouter()
}
}

View file

@ -1,25 +0,0 @@
package com.tangem.feature.qrscanning
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.feature.qrscanning.QrScanningRouter.Companion.SOURCE_KEY
import com.tangem.feature.qrscanning.usecase.EmitQrScannedEventUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
internal class QrScanningViewModel @Inject constructor(
private val emitQrScannedEventUseCase: EmitQrScannedEventUseCase,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val source: SourceType = savedStateHandle[SOURCE_KEY] ?: error("Source is mandatory")
fun onQrScanned(qrCode: String) {
viewModelScope.launch {
emitQrScannedEventUseCase.invoke(source, qrCode)
}
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.feature.qrscanning
package com.tangem.feature.qrscanning.di
import com.tangem.feature.qrscanning.repo.DefaultQrScanningEventsRepository
import com.tangem.feature.qrscanning.repo.QrScanningEventsRepository

View file

@ -0,0 +1,21 @@
package com.tangem.feature.qrscanning.di
import com.tangem.core.navigation.ReduxNavController
import com.tangem.feature.qrscanning.QrScanningRouter
import com.tangem.feature.qrscanning.navigation.DefaultQrScanningRouter
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.scopes.ActivityScoped
@Module
@InstallIn(ActivityComponent::class)
internal object QrScanningRouterModule {
@Provides
@ActivityScoped
fun provideQrScanRouter(reduxNavController: ReduxNavController): QrScanningRouter {
return DefaultQrScanningRouter(reduxNavController)
}
}

View file

@ -5,7 +5,9 @@ import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.common.InputImage
import javax.annotation.concurrent.Immutable
@Immutable
class MLKitBarcodeAnalyzer(private val onScanned: (String) -> Unit) : ImageAnalysis.Analyzer {
private var isScanning: Boolean = false

View file

@ -1,68 +0,0 @@
package com.tangem.feature.qrscanning.inner
import android.content.Context
import android.util.Size
import android.view.OrientationEventListener
import android.view.Surface
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.lifecycle.LifecycleOwner
import com.tangem.feature.qrscanning.impl.databinding.LayoutQrScanningBinding
import java.util.concurrent.ExecutorService
internal class PreviewBinder {
@Suppress("LongParameterList")
fun bindPreview(
context: Context,
binding: LayoutQrScanningBinding,
lifecycleOwner: LifecycleOwner,
cameraProvider: ProcessCameraProvider,
cameraExecutor: ExecutorService,
onScanned: (String) -> Unit,
) {
cameraProvider.unbindAll()
val preview: Preview = Preview.Builder()
.build()
val imageAnalysis = ImageAnalysis.Builder()
.setTargetResolution(Size(binding.cameraPreview.width, binding.cameraPreview.height))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
val orientationEventListener = object : OrientationEventListener(context) {
@Suppress("MagicNumber")
override fun onOrientationChanged(orientation: Int) {
val rotation: Int = when (orientation) {
in 45..134 -> Surface.ROTATION_270
in 135..224 -> Surface.ROTATION_180
in 225..314 -> Surface.ROTATION_90
else -> Surface.ROTATION_0
}
imageAnalysis.targetRotation = rotation
}
}
orientationEventListener.enable()
val analyzer: ImageAnalysis.Analyzer = MLKitBarcodeAnalyzer {
imageAnalysis.clearAnalyzer()
onScanned.invoke(it)
}
cameraExecutor.let {
imageAnalysis.setAnalyzer(it, analyzer)
}
preview.setSurfaceProvider(binding.cameraPreview.surfaceProvider)
val cameraSelector: CameraSelector = CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build()
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageAnalysis, preview)
}
}

View file

@ -1,42 +0,0 @@
package com.tangem.feature.qrscanning.inner
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
import com.tangem.feature.qrscanning.impl.R
class ViewFinderOverlay(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val boxPaint: Paint = Paint().apply {
color = ContextCompat.getColor(context, R.color.white)
style = Paint.Style.STROKE
strokeWidth = context.resources.getDimensionPixelOffset(R.dimen.qr_border_stroke_width).toFloat()
}
private val boxWidthRatio = 0.8F
private val boxCornerRadius: Float =
context.resources.getDimensionPixelOffset(R.dimen.qr_border_corner_radius).toFloat()
private var boxRect: RectF? = null
@Suppress("MagicNumber")
fun setViewFinder() {
val overlayWidth = width.toFloat()
val overlayHeight = height.toFloat()
val boxSize = overlayWidth * boxWidthRatio
val cx = overlayWidth / 2
val cy = overlayHeight / 2
boxRect = RectF(cx - boxSize / 2, cy - boxSize / 2, cx + boxSize / 2, cy + boxSize / 2)
invalidate()
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
boxRect?.let {
canvas.drawRoundRect(it, boxCornerRadius, boxCornerRadius, boxPaint)
}
}
}

View file

@ -0,0 +1,15 @@
package com.tangem.feature.qrscanning.navigation
import androidx.fragment.app.Fragment
import com.tangem.core.navigation.ReduxNavController
import com.tangem.feature.qrscanning.QrScanningFragment
class DefaultQrScanningRouter(
private val reduxNavController: ReduxNavController,
) : QrScanningInnerRouter {
override fun getEntryFragment(): Fragment = QrScanningFragment.create()
override fun popBackStack() {
reduxNavController.popBackStack()
}
}

View file

@ -0,0 +1,8 @@
package com.tangem.feature.qrscanning.navigation
import com.tangem.feature.qrscanning.QrScanningRouter
interface QrScanningInnerRouter : QrScanningRouter {
fun popBackStack()
}

View file

@ -0,0 +1,35 @@
package com.tangem.feature.qrscanning.presentation
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.view.LifecycleCameraController
import androidx.camera.view.PreviewView
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.viewinterop.AndroidView
import com.tangem.feature.qrscanning.inner.MLKitBarcodeAnalyzer
import java.util.concurrent.ExecutorService
@Composable
internal fun CameraView(executor: () -> ExecutorService, analyzer: () -> MLKitBarcodeAnalyzer) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val previewView = remember { PreviewView(context) }
val cameraController = remember { LifecycleCameraController(context) }
cameraController.apply {
bindToLifecycle(lifecycleOwner)
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
setImageAnalysisAnalyzer(executor(), analyzer())
imageAnalysisBackpressureStrategy = ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST
}
previewView.controller = cameraController
AndroidView({ previewView }, modifier = Modifier.fillMaxSize())
}

View file

@ -0,0 +1,125 @@
package com.tangem.feature.qrscanning.presentation
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Constraints
import com.tangem.core.ui.components.appbar.AppBarWithBackButtonAndIcon
import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resolveReference
import com.tangem.core.ui.res.TangemColorPalette
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.qrscanning.impl.R
import com.tangem.feature.qrscanning.inner.MLKitBarcodeAnalyzer
import java.util.concurrent.ExecutorService
import kotlin.math.roundToInt
private const val QR_CODE_SIZE = 0.8f
@Composable
internal fun QrScanningContent(
executor: () -> ExecutorService,
analyzer: () -> MLKitBarcodeAnalyzer,
uiState: QrScanningState,
) {
Box(
modifier = Modifier
.fillMaxSize(),
) {
CameraView(
executor = executor,
analyzer = analyzer,
)
Overlay(
message = uiState.message,
)
AppBarWithBackButtonAndIcon(
onBackClick = uiState.onBackClick,
iconRes = R.drawable.ic_gallery_24,
onIconClick = uiState.onGalleryClicked,
backgroundColor = Color.Transparent,
modifier = Modifier.statusBarsPadding(),
)
}
}
@Composable
private fun Overlay(message: TextReference?, overlayColor: Color = TangemColorPalette.Black.copy(alpha = 0.7f)) {
val whiteColor = TangemTheme.colors.text.constantWhite
val borderWidth = with(LocalDensity.current) { TangemTheme.dimens.spacing4.toPx() }
val borderLength = with(LocalDensity.current) { TangemTheme.dimens.size20.toPx() }
val textMeasurer = rememberTextMeasurer()
val textPadding = with(LocalDensity.current) { TangemTheme.dimens.spacing24.toPx() }
val style = TangemTheme.typography.caption2.copy(textAlign = TextAlign.Center)
val text = message?.resolveReference()
Canvas(modifier = Modifier.fillMaxSize()) {
val squareSize = size.minDimension * QR_CODE_SIZE
val verticalOffset = (size.height - squareSize) / 2f
val horizontalOffset = (size.width - squareSize) / 2f
drawRect(
color = overlayColor,
topLeft = Offset.Zero,
size = Size(size.width, verticalOffset),
)
drawRect(
color = overlayColor,
topLeft = Offset(0f, verticalOffset),
size = Size(horizontalOffset, squareSize),
)
drawRect(
color = overlayColor,
topLeft = Offset(horizontalOffset + squareSize, verticalOffset),
size = Size(horizontalOffset, squareSize),
)
drawRect(
color = overlayColor,
topLeft = Offset(0f, verticalOffset + squareSize),
size = Size(size.width, verticalOffset),
)
drawRect(
color = whiteColor,
topLeft = Offset(horizontalOffset, verticalOffset),
size = Size(squareSize, squareSize),
style = Stroke(
width = borderWidth,
join = StrokeJoin.Round,
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(2 * borderLength, squareSize - 2 * borderLength),
phase = borderLength,
),
),
)
text?.let {
val textLayoutResult = text.let {
textMeasurer.measure(
text = it,
style = style,
constraints = Constraints.fixedWidth(squareSize.roundToInt()),
)
}
drawText(
textLayoutResult = textLayoutResult,
color = whiteColor,
topLeft = Offset(
x = horizontalOffset,
y = verticalOffset + squareSize + textPadding,
),
)
}
}
}

View file

@ -0,0 +1,12 @@
package com.tangem.feature.qrscanning.presentation
import androidx.compose.runtime.Immutable
import com.tangem.core.ui.extensions.TextReference
@Immutable
data class QrScanningState(
val message: TextReference?,
val onQrScanned: (String) -> Unit,
val onBackClick: () -> Unit,
val onGalleryClicked: () -> Unit,
)

View file

@ -0,0 +1,26 @@
package com.tangem.feature.qrscanning.presentation
import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.feature.qrscanning.viewmodel.QrScanningClickIntents
import com.tangem.feature.qrscanning.SourceType
import com.tangem.feature.qrscanning.impl.R
internal class QrScanningStateFactory(
val clickIntents: QrScanningClickIntents,
) {
fun getInitialState(source: SourceType, network: String?): QrScanningState {
val message = when (source) {
SourceType.SEND -> network?.let { resourceReference(R.string.send_qrcode_scan_info, wrappedList(it)) }
else -> null
}
return QrScanningState(
message = message,
onBackClick = clickIntents::onBackClick,
onQrScanned = clickIntents::onQrScanned,
onGalleryClicked = clickIntents::onGalleryClicked,
)
}
}

View file

@ -0,0 +1,10 @@
package com.tangem.feature.qrscanning.viewmodel
interface QrScanningClickIntents {
fun onBackClick()
fun onQrScanned(qrCode: String)
fun onGalleryClicked()
}

View file

@ -0,0 +1,55 @@
package com.tangem.feature.qrscanning.viewmodel
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.feature.qrscanning.QrScanningRouter.Companion.NETWORK_KEY
import com.tangem.feature.qrscanning.QrScanningRouter.Companion.SOURCE_KEY
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.QrScanningStateFactory
import com.tangem.feature.qrscanning.usecase.EmitQrScannedEventUseCase
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.properties.Delegates
@HiltViewModel
internal class QrScanningViewModel @Inject constructor(
private val emitQrScannedEventUseCase: EmitQrScannedEventUseCase,
private val dispatcher: CoroutineDispatcherProvider,
savedStateHandle: SavedStateHandle,
) : ViewModel(), QrScanningClickIntents {
private val source: SourceType = savedStateHandle[SOURCE_KEY] ?: error("Source is mandatory")
private val network: String? = savedStateHandle[NETWORK_KEY]
private val factory = QrScanningStateFactory(
clickIntents = this,
)
var router: QrScanningInnerRouter by Delegates.notNull()
var uiState: QrScanningState by mutableStateOf(factory.getInitialState(source, network))
private set
override fun onBackClick() = router.popBackStack()
override fun onQrScanned(qrCode: String) {
if (qrCode.isNotBlank()) {
router.popBackStack()
viewModelScope.launch(dispatcher.main) {
emitQrScannedEventUseCase.invoke(source, qrCode)
}
}
}
override fun onGalleryClicked() {
// [REDACTED_JIRA]
}
}

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false"
tools:background="@android:color/white">
<androidx.camera.view.PreviewView
android:id="@+id/cameraPreview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.tangem.feature.qrscanning.inner.ViewFinderOverlay
android:id="@+id/overlay"
android:layerType="software"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="white">#FFFFFFFF</color>
</resources>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="qr_border_stroke_width">4dp</dimen>
<dimen name="qr_border_corner_radius">8dp</dimen>
</resources>