mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-07-01 19:46:08 +01:00
Migrate VerifyScanFragment to compose.
This commit is contained in:
@@ -1,56 +1,35 @@
|
||||
package org.thoughtcrime.securesms.verify
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.OneShotPreDrawListener
|
||||
import androidx.fragment.app.Fragment
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.signal.qr.QrScannerView
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import org.signal.camera.CameraScreenViewModel
|
||||
import org.signal.core.ui.compose.ComposeFragment
|
||||
import org.signal.qr.kitkat.ScanListener
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ShapeScrim
|
||||
import org.thoughtcrime.securesms.mediasend.camerax.CameraXRemoteConfig
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.fragments.findListener
|
||||
|
||||
/**
|
||||
* QR Scanner for identity verification
|
||||
*/
|
||||
class VerifyScanFragment : Fragment() {
|
||||
private val lifecycleDisposable = LifecycleDisposable()
|
||||
|
||||
private lateinit var cameraView: QrScannerView
|
||||
private lateinit var cameraScrim: ShapeScrim
|
||||
private lateinit var cameraMarks: ImageView
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, viewGroup: ViewGroup?, bundle: Bundle?): View? {
|
||||
return ViewUtil.inflate(inflater, viewGroup!!, R.layout.verify_scan_fragment)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
cameraView = view.findViewById(R.id.scanner)
|
||||
cameraScrim = view.findViewById(R.id.camera_scrim)
|
||||
cameraMarks = view.findViewById(R.id.camera_marks)
|
||||
OneShotPreDrawListener.add(cameraScrim) {
|
||||
val width = cameraScrim.scrimWidth
|
||||
val height = cameraScrim.scrimHeight
|
||||
ViewUtil.updateLayoutParams(cameraMarks, width, height)
|
||||
class VerifyScanFragment : ComposeFragment() {
|
||||
@Composable
|
||||
override fun FragmentContent() {
|
||||
val viewModel = viewModel {
|
||||
CameraScreenViewModel()
|
||||
}
|
||||
|
||||
cameraView.start(viewLifecycleOwner, CameraXRemoteConfig.isBlocklisted())
|
||||
val state by viewModel.state
|
||||
|
||||
lifecycleDisposable.bindTo(viewLifecycleOwner)
|
||||
|
||||
lifecycleDisposable += cameraView
|
||||
.qrData
|
||||
.distinctUntilChanged()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { qrData: String ->
|
||||
findListener<ScanListener>()?.onQrDataFound(qrData)
|
||||
LaunchedEffect(viewModel) {
|
||||
viewModel.qrCodeDetected.collect {
|
||||
findListener<ScanListener>()?.onQrDataFound(it)
|
||||
}
|
||||
}
|
||||
|
||||
VerifyScanScreen(
|
||||
state = state,
|
||||
emitter = viewModel::onEvent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.verify
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.signal.camera.CameraCaptureMode
|
||||
import org.signal.camera.CameraScreen
|
||||
import org.signal.camera.CameraScreenEvents
|
||||
import org.signal.camera.CameraScreenState
|
||||
import org.signal.camera.CameraScreenViewModel
|
||||
import org.signal.core.ui.compose.Cutout
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* Scanner screen for verifying user identities. This is meant to be utilized with an instance of
|
||||
* [CameraScreenViewModel], which the parent component owns. There is a field on the ViewModel through
|
||||
* which you can recieve via [qrCodeDetected]
|
||||
*/
|
||||
@Composable
|
||||
fun VerifyScanScreen(
|
||||
state: CameraScreenState,
|
||||
emitter: (CameraScreenEvents) -> Unit
|
||||
) {
|
||||
Column {
|
||||
CameraScreen(
|
||||
state = state,
|
||||
emitter = emitter,
|
||||
roundCorners = false,
|
||||
enableQrScanning = true,
|
||||
captureMode = CameraCaptureMode.ImageOnly,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
) {
|
||||
Cutout(
|
||||
cutoutShape = RoundedCornerShape(18.dp),
|
||||
cutoutPadding = PaddingValues(64.dp),
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ic_camera_outline),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.heightIn(min = 60.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.verify_scan_fragment__scan_the_qr_code_on_your_contact),
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
private fun VerifyScanScreenPreview() {
|
||||
Previews.Preview {
|
||||
VerifyScanScreen(
|
||||
state = CameraScreenState(),
|
||||
emitter = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user