Updated on 2026-08-14
This commit is contained in:
parent
2806489bd8
commit
c2a6235483
10 changed files with 293 additions and 75 deletions
|
|
@ -105,6 +105,7 @@ dependencies {
|
|||
implementation(deps.androidx.activity.compose)
|
||||
implementation(deps.androidx.browser)
|
||||
implementation(deps.androidx.paging.runtime)
|
||||
implementation(deps.androidx.swipeRefreshLayout)
|
||||
implementation(deps.lifecycle.runtime.ktx)
|
||||
implementation(deps.lifecycle.common.java8)
|
||||
implementation(deps.lifecycle.viewModel.ktx)
|
||||
|
|
@ -153,7 +154,6 @@ dependencies {
|
|||
implementation(deps.timber)
|
||||
implementation(deps.reKotlin)
|
||||
implementation(deps.zxing.qrCore)
|
||||
implementation(deps.zxing.qrBarcodeScanner)
|
||||
implementation(deps.otaliastudiosCameraView)
|
||||
implementation(deps.coil)
|
||||
implementation(deps.appsflyer)
|
||||
|
|
@ -192,4 +192,19 @@ dependencies {
|
|||
externalImplementation(deps.chuckerStub)
|
||||
internalImplementation(deps.chuckerStub)
|
||||
releaseImplementation(deps.chuckerStub)
|
||||
|
||||
/** Camera */
|
||||
implementation(deps.camera.camera2)
|
||||
implementation(deps.camera.lifecycle)
|
||||
implementation(deps.camera.view)
|
||||
|
||||
implementation(deps.listenableFuture)
|
||||
implementation(deps.mlKit.barcodeScanning)
|
||||
|
||||
/** Excluded dependencies */
|
||||
implementation("com.google.guava:guava:30.0-android") {
|
||||
// excludes version 9999.0-empty-to-avoid-conflict-with-guava
|
||||
exclude(group="com.google.guava", module = "listenablefuture")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.tangem.tap.common.qrCodeScan
|
||||
|
||||
import androidx.camera.core.ExperimentalGetImage
|
||||
import androidx.camera.core.ImageAnalysis
|
||||
import androidx.camera.core.ImageProxy
|
||||
import com.google.mlkit.vision.barcode.BarcodeScanning
|
||||
import com.google.mlkit.vision.common.InputImage
|
||||
|
||||
class MLKitBarcodeAnalyzer(private val onScanned: (String) -> Unit) : ImageAnalysis.Analyzer {
|
||||
|
||||
private var isScanning: Boolean = false
|
||||
|
||||
@ExperimentalGetImage
|
||||
override fun analyze(imageProxy: ImageProxy) {
|
||||
val mediaImage = imageProxy.image
|
||||
if (mediaImage != null && !isScanning) {
|
||||
val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
|
||||
val scanner = BarcodeScanning.getClient()
|
||||
|
||||
isScanning = true
|
||||
scanner.process(image)
|
||||
.addOnSuccessListener { codes ->
|
||||
codes.firstOrNull().let { barcode ->
|
||||
val rawValue = barcode?.rawValue
|
||||
rawValue?.let {
|
||||
onScanned.invoke(it)
|
||||
}
|
||||
}
|
||||
|
||||
isScanning = false
|
||||
imageProxy.close()
|
||||
}
|
||||
.addOnFailureListener {
|
||||
isScanning = false
|
||||
imageProxy.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,48 +3,63 @@ package com.tangem.tap.common.qrCodeScan
|
|||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.Result
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.otaliastudios.cameraview.CameraView.PERMISSION_REQUEST_CODE
|
||||
import me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||
import com.tangem.tap.features.details.ui.walletconnect.dialogs.PreviewBinder
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.LayoutQrScanningBinding
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
|
||||
class ScanQrCodeActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var mScannerView: ZXingScannerView
|
||||
private val binding: LayoutQrScanningBinding by viewBinding(LayoutQrScanningBinding::bind)
|
||||
|
||||
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
|
||||
private var cameraExecutor: ExecutorService? = null
|
||||
|
||||
private val binder = PreviewBinder()
|
||||
|
||||
override fun onCreate(state: Bundle?) {
|
||||
super.onCreate(state)
|
||||
|
||||
mScannerView = ZXingScannerView(this).apply {
|
||||
setFormats(listOf(BarcodeFormat.QR_CODE))
|
||||
}
|
||||
setContentView(mScannerView)
|
||||
|
||||
if (!permissionIsGranted()) requestPermission()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
mScannerView.setResultHandler(this)
|
||||
mScannerView.startCamera()
|
||||
}
|
||||
setContentView(R.layout.layout_qr_scanning)
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
mScannerView.stopCamera()
|
||||
}
|
||||
cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
override fun handleResult(result: Result) {
|
||||
setResult(SCAN_QR_REQUEST_CODE, Intent().apply { putExtra(SCAN_RESULT, result.text) })
|
||||
finish()
|
||||
cameraProviderFuture?.addListener(
|
||||
{
|
||||
val cameraProvider = cameraProviderFuture?.get()
|
||||
binder.bindPreview(
|
||||
context = this,
|
||||
binding = binding,
|
||||
lifecycleOwner = this,
|
||||
cameraProvider = requireNotNull(cameraProvider),
|
||||
cameraExecutor = requireNotNull(cameraExecutor),
|
||||
onScanned = { result ->
|
||||
setResult(SCAN_QR_REQUEST_CODE, Intent().apply { putExtra(SCAN_RESULT, result) })
|
||||
finish()
|
||||
},
|
||||
)
|
||||
},
|
||||
ContextCompat.getMainExecutor(this),
|
||||
)
|
||||
|
||||
binding.overlay.post {
|
||||
binding.overlay.setViewFinder()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
|
|
@ -56,12 +71,8 @@ class ScanQrCodeActivity : AppCompatActivity(), ZXingScannerView.ResultHandler {
|
|||
}
|
||||
|
||||
private fun permissionIsGranted(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||
cameraPermission == PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||
return cameraPermission == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private fun requestPermission() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.tap.common.qrCodeScan
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.*
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.tangem.wallet.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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,26 +2,33 @@ package com.tangem.tap.features.details.ui.walletconnect
|
|||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.*
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.camera.lifecycle.ProcessCameraProvider
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.Result
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.otaliastudios.cameraview.CameraView
|
||||
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 me.dm7.barcodescanner.zxing.ZXingScannerView
|
||||
import com.tangem.wallet.R
|
||||
import com.tangem.wallet.databinding.LayoutQrScanningBinding
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
||||
internal class QrScanFragment : Fragment(R.layout.layout_qr_scanning) {
|
||||
|
||||
private var scannerView: ZXingScannerView? = null
|
||||
private val binding: LayoutQrScanningBinding by viewBinding(LayoutQrScanningBinding::bind)
|
||||
|
||||
private val binder = PreviewBinder()
|
||||
|
||||
private var cameraProviderFuture: ListenableFuture<ProcessCameraProvider>? = null
|
||||
private var cameraExecutor: ExecutorService? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -36,25 +43,38 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
if (!permissionIsGranted()) requestPermission()
|
||||
|
||||
scannerView = ZXingScannerView(activity).apply {
|
||||
setFormats(listOf(BarcodeFormat.QR_CODE))
|
||||
cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
|
||||
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 ->
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
setFitSystemWindows(fit = false)
|
||||
if (result.isNotBlank()) {
|
||||
store.dispatch(WalletConnectAction.OpenSession(result))
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
ContextCompat.getMainExecutor(requireContext()),
|
||||
)
|
||||
|
||||
binding.overlay.post {
|
||||
binding.overlay.setViewFinder()
|
||||
}
|
||||
|
||||
return scannerView
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
scannerView?.setResultHandler(this)
|
||||
scannerView?.startCamera()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
scannerView?.stopCamera()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
|
@ -62,14 +82,6 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
setFitSystemWindows(fit = false)
|
||||
}
|
||||
|
||||
override fun handleResult(result: Result) {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
setFitSystemWindows(fit = false)
|
||||
if (!result.text.isNullOrBlank()) {
|
||||
store.dispatch(WalletConnectAction.OpenSession(result.text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
if (requestCode != CameraView.PERMISSION_REQUEST_CODE) return
|
||||
|
||||
|
|
@ -80,13 +92,8 @@ class QrScanFragment : Fragment(0), ZXingScannerView.ResultHandler {
|
|||
}
|
||||
|
||||
private fun permissionIsGranted(): Boolean {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val cameraPermission =
|
||||
ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
|
||||
cameraPermission == PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
val cameraPermission = ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
|
||||
return cameraPermission == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private fun requestPermission() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect.dialogs
|
||||
|
||||
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.tap.common.qrCodeScan.MLKitBarcodeAnalyzer
|
||||
import com.tangem.wallet.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)
|
||||
}
|
||||
}
|
||||
20
app/src/main/res/layout/layout_qr_scanning.xml
Normal file
20
app/src/main/res/layout/layout_qr_scanning.xml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<?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.tap.common.qrCodeScan.ViewFinderOverlay
|
||||
android:id="@+id/overlay"
|
||||
android:layerType="software"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
|
@ -42,4 +42,7 @@
|
|||
|
||||
<dimen name="layout_address_info_margin">16dp</dimen>
|
||||
|
||||
<dimen name="qr_border_stroke_width">4dp</dimen>
|
||||
<dimen name="qr_border_corner_radius">8dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,8 @@ spongycastleCryptoCore = "1.58.0.0"
|
|||
timber = "4.7.1"
|
||||
viewBindingDelegate = "1.5.9"
|
||||
xmlShimmer = "1.1.3"
|
||||
zxingQrBarcodeScanner = "1.9.8"
|
||||
zendeskChat = "3.3.5"
|
||||
zendeskMessaging = "5.2.4"
|
||||
zxingQrCode = "3.5.1"
|
||||
mviCore = "1.3.1"
|
||||
kotlinSerialization = "1.4.1"
|
||||
|
|
@ -79,6 +80,10 @@ walletConnectWeb3 = "1.11.0"
|
|||
prettyLogger = "2.2.0"
|
||||
okHttp-prettyLogging = "3.1.0"
|
||||
chucker = "4.0.0"
|
||||
mlKit-barcodeScanning = "17.2.0"
|
||||
androidXCamera = "1.3.0"
|
||||
listenableFuture = "1.0"
|
||||
swipeRefreshLayout = "1.1.0"
|
||||
spr-client = "3.6.2"
|
||||
# endregion Other libraries
|
||||
|
||||
|
|
@ -132,11 +137,12 @@ androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx
|
|||
androidx-core-splashScreen = { module = "androidx.core:core-splashscreen", version.ref = "androidxSplashScreen" }
|
||||
androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "androidxFragment" }
|
||||
androidx-paging-runtime = { module = "androidx.paging:paging-runtime", version.ref = "androidx-paging" }
|
||||
androidx-swipeRefreshLayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swipeRefreshLayout" }
|
||||
androidx-palette = { module = "androidx.palette:palette", version.ref = "androidx-palette" }
|
||||
lifecycle-common-java8 = { module = "androidx.lifecycle:lifecycle-common-java8", version.ref = "androidxLifecycle" }
|
||||
lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidxLifecycle" }
|
||||
lifecycle-viewModel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidxLifecycle" }
|
||||
lifecycle-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "compoese-lifecycle-runtime" }
|
||||
androidx-palette = { module = "androidx.palette:palette", version.ref = "androidx-palette" }
|
||||
androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" }
|
||||
# region AndroidX
|
||||
|
||||
|
|
@ -220,7 +226,8 @@ retrofit-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.re
|
|||
timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
|
||||
viewBindingDelegate = { module = "com.github.kirich1409:viewbindingpropertydelegate-noreflection", version.ref = "viewBindingDelegate" }
|
||||
xmlShimmer = { module = "com.github.skydoves:androidveil", version.ref = "xmlShimmer" }
|
||||
zxing-qrBarcodeScanner = { module = "me.dm7.barcodescanner:zxing", version.ref = "zxingQrBarcodeScanner" }
|
||||
zendesk-chat = { module = "com.zendesk:chat", version.ref = "zendeskChat" }
|
||||
zendesk-messaging = { module = "com.zendesk:messaging", version.ref = "zendeskMessaging" }
|
||||
zxing-qrCore = { module = "com.google.zxing:core", version.ref = "zxingQrCode" }
|
||||
mviCore-watcher = { module = "com.github.badoo.mvicore:mvicore-diff", version.ref = "mviCore" }
|
||||
kotlin-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinSerialization" }
|
||||
|
|
@ -233,4 +240,10 @@ prettyLogger = { module = "com.orhanobut:logger", version.ref = "prettyLogger" }
|
|||
sprClient = { module = "com.spr:messengerclient", version.ref = "spr-client" }
|
||||
chucker = { module = "com.github.chuckerteam.chucker:library", version.ref = "chucker" }
|
||||
chuckerStub = { module = "com.github.chuckerteam.chucker:library-no-op", version.ref = "chucker" }
|
||||
mlKit-barcodeScanning = { module = "com.google.mlkit:barcode-scanning", version.ref = "mlKit-barcodeScanning" }
|
||||
listenableFuture = { module = "com.google.guava:listenablefuture", version.ref = "listenableFuture" }
|
||||
camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "androidXCamera" }
|
||||
camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidXCamera" }
|
||||
camera-view = { module = "androidx.camera:camera-view", version.ref = "androidXCamera" }
|
||||
|
||||
# endregion Other
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import java.math.BigDecimal
|
|||
|
||||
interface TransactionManager {
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
@Throws(IllegalStateException::class)
|
||||
suspend fun sendApproveTransaction(
|
||||
txData: ApproveTxData,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue