From 79cfde1924229e18958a913a263a6f8a6782328c Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 29 Feb 2024 19:33:45 +1030 Subject: [PATCH] Add QR camera permissions --- app/build.gradle | 6 ++ .../onboarding/LinkDeviceActivity.kt | 101 ++++++++++++++++-- 2 files changed, 97 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 855d37df41..80a7067c1f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -365,10 +365,16 @@ dependencies { implementation "com.google.accompanist:accompanist-themeadapter-appcompat:0.33.1-alpha" implementation "com.google.accompanist:accompanist-pager:0.33.1-alpha" implementation "com.google.accompanist:accompanist-pager-indicators:0.33.1-alpha" + implementation "com.google.accompanist:accompanist-permissions:0.33.1-alpha" implementation "androidx.compose.runtime:runtime-livedata:1.6.2" implementation 'androidx.compose.foundation:foundation-layout:1.6.2' implementation 'androidx.compose.material:material:1.6.2' + +// implementation "androidx.camera:camera-camera2:1.3.1" +// implementation "androidx.camera:camera-lifecycle:1.3.1" +// implementation "androidx.camera:camera-view:1.3.1" +// implementation "com.google.mlkit:barcode-scanning:17.2.0" } static def getLastCommitTimestamp() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/LinkDeviceActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/LinkDeviceActivity.kt index b3ea96f65e..789559349a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/LinkDeviceActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/LinkDeviceActivity.kt @@ -2,13 +2,16 @@ package org.thoughtcrime.securesms.onboarding import android.content.Context import android.content.Intent +import android.net.Uri import android.os.Bundle +import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS import androidx.activity.viewModels import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -30,14 +33,22 @@ import androidx.compose.material.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner 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 androidx.lifecycle.lifecycleScope +import com.google.accompanist.permissions.ExperimentalPermissionsApi +import com.google.accompanist.permissions.isGranted +import com.google.accompanist.permissions.rememberPermissionState +import com.google.accompanist.permissions.shouldShowRationale import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import network.loki.messenger.R @@ -49,6 +60,7 @@ import org.thoughtcrime.securesms.ui.baseBold import org.thoughtcrime.securesms.ui.colorDestructive import javax.inject.Inject + @AndroidEntryPoint class LinkDeviceActivity : BaseActionBarActivity() { @@ -71,7 +83,6 @@ class LinkDeviceActivity : BaseActionBarActivity() { } } - ComposeView(this).apply { setContent { val state by viewModel.stateFlow.collectAsState() @@ -93,8 +104,9 @@ class LinkDeviceActivity : BaseActionBarActivity() { selectedTabIndex = pagerState.currentPage, modifier = Modifier.height(48.dp) ) { + val animationScope = rememberCoroutineScope() tabs.forEachIndexed { i, it -> - Tab(i == pagerState.currentPage, onClick = { pagerState.targetPage }) { + Tab(i == pagerState.currentPage, onClick = { animationScope.launch { pagerState.animateScrollToPage(i) } }) { Text(stringResource(id = it)) } } @@ -105,11 +117,82 @@ class LinkDeviceActivity : BaseActionBarActivity() { ) { i -> when(tabs[i]) { R.string.activity_recovery_password -> RecoveryPassword(state, onChange, onContinue) - R.string.activity_link_device_scan_qr_code -> ScanQrCode() + R.string.activity_link_device_scan_qr_code -> MaybeScanQrCode() } } } } + + + @OptIn(ExperimentalPermissionsApi::class) + @Composable + fun MaybeScanQrCode() { + Box(modifier = Modifier.fillMaxSize()) { + val cameraPermissionState = rememberPermissionState(android.Manifest.permission.CAMERA) + + if (cameraPermissionState.status.isGranted) { + ScanQrCode() + } else if (cameraPermissionState.status.shouldShowRationale) { + Column( + modifier = Modifier.align(Alignment.Center) + .padding(horizontal = 60.dp) + ) { + Text( + "Camera Permission permanently denied. Configure in settings.", + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.size(20.dp)) + OutlineButton( + text = "Settings", + modifier = Modifier.align(Alignment.CenterHorizontally) + ) { + Intent(ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = Uri.fromParts("package", packageName, null) + }.let(::startActivity) + } + } + } else { + OutlineButton( + text = "Grant Camera Permission", + modifier = Modifier.align(Alignment.Center) + ) { + cameraPermissionState.run { launchPermissionRequest() } + } + } + } + } +} + +@Composable +fun ScanQrCode() { + val localContext = LocalContext.current + val lifecycleOwner = LocalLifecycleOwner.current +// val cameraProviderFuture = remember { +// ProcessCameraProvider.getInstance(localContext) +// } +// AndroidView( +// modifier = Modifier.fillMaxSize(), +// factory = { context -> +// val previewView = PreviewView(context) +// val preview = Preview.Builder().build() +// val selector = CameraSelector.Builder() +// .requireLensFacing(CameraSelector.LENS_FACING_BACK) +// .build() +// +// preview.setSurfaceProvider(previewView.surfaceProvider) +// +// runCatching { +// cameraProviderFuture.get().bindToLifecycle( +// lifecycleOwner, +// selector, +// preview +// ) +// }.onFailure { +// Log.e("CAMERA", "Camera bind error", it) +// } +// previewView +// } +// ) } @Composable @@ -157,16 +240,14 @@ fun RecoveryPassword(state: LinkDeviceState, onChange: (String) -> Unit = {}, on Spacer(Modifier.weight(2f)) OutlineButton( text = stringResource(id = R.string.continue_2), - modifier = Modifier.align(Alignment.CenterHorizontally).padding(horizontal = 64.dp, vertical = 20.dp).width(200.dp) + modifier = Modifier + .align(Alignment.CenterHorizontally) + .padding(horizontal = 64.dp, vertical = 20.dp) + .width(200.dp) ) { onContinue() } } } -@Composable -fun ScanQrCode() { - -} - fun Context.startLinkDeviceActivity() { Intent(this, LinkDeviceActivity::class.java).let(::startActivity) }