Update camera permission UI for usernames.
This commit is contained in:
parent
2744dec43a
commit
a99db2b16e
4 changed files with 79 additions and 17 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
|
@ -77,6 +78,7 @@ import org.thoughtcrime.securesms.components.settings.app.usernamelinks.Username
|
|||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.permissions.PermissionCompat
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
@ -140,6 +142,7 @@ class UsernameLinkSettingsFragment : ComposeFragment() {
|
|||
onShareBadge = { shareQrBadge(requireActivity(), viewModel.generateQrCodeImage(helpText)) },
|
||||
onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) },
|
||||
onQrResultHandled = { viewModel.onQrResultHandled() },
|
||||
onOpenCameraClicked = { askCameraPermissions() },
|
||||
onOpenGalleryClicked = {
|
||||
if (galleryPermissionState.allPermissionsGranted) {
|
||||
galleryLauncher.launch(Unit)
|
||||
|
@ -153,6 +156,10 @@ class UsernameLinkSettingsFragment : ComposeFragment() {
|
|||
)
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
disposables.bindTo(viewLifecycleOwner)
|
||||
}
|
||||
|
@ -161,6 +168,15 @@ class UsernameLinkSettingsFragment : ComposeFragment() {
|
|||
super.onResume()
|
||||
viewModel.onResume()
|
||||
}
|
||||
|
||||
private fun askCameraPermissions() {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_scan_qr_codes, parentFragmentManager)
|
||||
.onAnyDenied { Toast.makeText(requireContext(), R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code, Toast.LENGTH_LONG).show() }
|
||||
.execute()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
|
@ -177,6 +193,7 @@ private fun MainScreen(
|
|||
onShareBadge: () -> Unit = {},
|
||||
onQrCodeScanned: (String) -> Unit = {},
|
||||
onQrResultHandled: () -> Unit = {},
|
||||
onOpenCameraClicked: () -> Unit = {},
|
||||
onOpenGalleryClicked: () -> Unit = {},
|
||||
onLinkReset: () -> Unit = {},
|
||||
onBackNavigationPressed: () -> Unit = {},
|
||||
|
@ -244,7 +261,9 @@ private fun MainScreen(
|
|||
qrScanResult = state.qrScanResult,
|
||||
onQrCodeScanned = onQrCodeScanned,
|
||||
onQrResultHandled = onQrResultHandled,
|
||||
onOpenCameraClicked = onOpenCameraClicked,
|
||||
onOpenGalleryClicked = onOpenGalleryClicked,
|
||||
hasCameraPermission = cameraPermissionState.status.isGranted,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
onRecipientFound = { recipient ->
|
||||
val taskStack = TaskStackBuilder
|
||||
|
@ -296,13 +315,7 @@ private fun TopAppBarContent(
|
|||
TabButton(
|
||||
label = stringResource(R.string.UsernameLinkSettings_scan_tab_name),
|
||||
active = activeTab == ActiveTab.Scan,
|
||||
onClick = {
|
||||
if (cameraPermissionState.status.isGranted) {
|
||||
onScanTabSelected()
|
||||
} else {
|
||||
cameraPermissionState.launchPermissionRequest()
|
||||
}
|
||||
},
|
||||
onClick = { onScanTabSelected() },
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -26,11 +27,13 @@ import androidx.compose.ui.graphics.drawscope.DrawScope
|
|||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
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.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import org.signal.core.ui.Buttons
|
||||
import org.signal.core.ui.Dialogs
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
import org.signal.qr.QrScannerView
|
||||
|
@ -49,8 +52,10 @@ fun UsernameQrScanScreen(
|
|||
qrScanResult: QrScanResult?,
|
||||
onQrCodeScanned: (String) -> Unit,
|
||||
onQrResultHandled: () -> Unit,
|
||||
onOpenCameraClicked: () -> Unit,
|
||||
onOpenGalleryClicked: () -> Unit,
|
||||
onRecipientFound: (Recipient) -> Unit,
|
||||
hasCameraPermission: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val path = remember { Path() }
|
||||
|
@ -113,9 +118,34 @@ fun UsernameQrScanScreen(
|
|||
.fillMaxHeight()
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
drawQrCrosshair(path)
|
||||
if (hasCameraPermission) {
|
||||
drawQrCrosshair(path)
|
||||
}
|
||||
}
|
||||
)
|
||||
if (!hasCameraPermission) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.padding(50.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.CameraXFragment_to_scan_qr_code_allow_camera),
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = Color.White,
|
||||
modifier = Modifier.padding(10.dp)
|
||||
)
|
||||
Buttons.MediumTonal(
|
||||
colors = ButtonDefaults.filledTonalButtonColors(),
|
||||
onClick = onOpenCameraClicked
|
||||
) {
|
||||
Text(stringResource(R.string.CameraXFragment_allow_access))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FloatingActionButton(
|
||||
shape = CircleShape,
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
|
@ -30,7 +32,10 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.lifecycle.LifecycleOwner
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.MultiplePermissionsState
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import org.signal.core.ui.Dialogs
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
|
@ -38,6 +43,7 @@ import org.signal.core.util.concurrent.LifecycleDisposable
|
|||
import org.signal.core.util.getParcelableExtraCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.permissions.PermissionCompat
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme
|
||||
|
@ -55,6 +61,11 @@ class UsernameQrScannerActivity : AppCompatActivity() {
|
|||
private val viewModel: UsernameQrScannerViewModel by viewModels()
|
||||
private val disposables = LifecycleDisposable()
|
||||
|
||||
@SuppressLint("MissingSuperCall")
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
disposables.bindTo(this)
|
||||
|
@ -74,6 +85,7 @@ class UsernameQrScannerActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
val cameraPermissionState: PermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
|
||||
val state by viewModel.state
|
||||
|
||||
SignalTheme(isDarkMode = DynamicTheme.isDarkTheme(LocalContext.current)) {
|
||||
|
@ -82,10 +94,12 @@ class UsernameQrScannerActivity : AppCompatActivity() {
|
|||
diposables = disposables.disposables,
|
||||
state = state,
|
||||
galleryPermissionsState = galleryPermissionState,
|
||||
cameraPermissionState = cameraPermissionState,
|
||||
onQrScanned = { url -> viewModel.onQrScanned(url) },
|
||||
onQrResultHandled = {
|
||||
finish()
|
||||
},
|
||||
onOpenCameraClicked = { askCameraPermissions() },
|
||||
onOpenGalleryClicked = {
|
||||
if (galleryPermissionState.allPermissionsGranted) {
|
||||
galleryLauncher.launch(Unit)
|
||||
|
@ -108,6 +122,15 @@ class UsernameQrScannerActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun askCameraPermissions() {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.CAMERA)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(getString(R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code), null, R.string.CameraXFragment_allow_access_camera, R.string.CameraXFragment_to_scan_qr_codes, supportFragmentManager)
|
||||
.onAnyDenied { Toast.makeText(this, R.string.CameraXFragment_signal_needs_camera_access_scan_qr_code, Toast.LENGTH_LONG).show() }
|
||||
.execute()
|
||||
}
|
||||
|
||||
class Contract : ActivityResultContract<Unit, RecipientId?>() {
|
||||
override fun createIntent(context: Context, input: Unit): Intent {
|
||||
return Intent(context, UsernameQrScannerActivity::class.java)
|
||||
|
@ -126,8 +149,10 @@ fun Content(
|
|||
diposables: CompositeDisposable,
|
||||
state: UsernameQrScannerViewModel.ScannerState,
|
||||
galleryPermissionsState: MultiplePermissionsState,
|
||||
cameraPermissionState: PermissionState,
|
||||
onQrScanned: (String) -> Unit,
|
||||
onQrResultHandled: () -> Unit,
|
||||
onOpenCameraClicked: () -> Unit,
|
||||
onOpenGalleryClicked: () -> Unit,
|
||||
onRecipientFound: (Recipient) -> Unit,
|
||||
onBackNavigationPressed: () -> Unit
|
||||
|
@ -155,8 +180,10 @@ fun Content(
|
|||
qrScanResult = state.qrScanResult,
|
||||
onQrCodeScanned = onQrScanned,
|
||||
onQrResultHandled = onQrResultHandled,
|
||||
onOpenCameraClicked = onOpenCameraClicked,
|
||||
onOpenGalleryClicked = onOpenGalleryClicked,
|
||||
onRecipientFound = onRecipientFound,
|
||||
hasCameraPermission = cameraPermissionState.status.isGranted,
|
||||
modifier = Modifier.padding(contentPadding)
|
||||
)
|
||||
|
||||
|
|
|
@ -81,7 +81,6 @@ import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
|||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameQrScannerActivity
|
||||
import org.thoughtcrime.securesms.invites.InviteActions
|
||||
import org.thoughtcrime.securesms.permissions.compose.Permissions
|
||||
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberVisualTransformation
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.registration.util.CountryPrefix
|
||||
|
@ -142,13 +141,6 @@ class FindByActivity : PassphraseRequiredActivity() {
|
|||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val cameraPermissionController = Permissions.cameraPermissionHandler(
|
||||
rationale = stringResource(id = R.string.PaymentsTransferFragment__to_scan_a_qr_code_signal_needs_access_to_the_camera),
|
||||
onPermissionGranted = {
|
||||
qrScanLauncher.launch(Unit)
|
||||
}
|
||||
)
|
||||
|
||||
Content(
|
||||
paddingValues = it,
|
||||
state = state,
|
||||
|
@ -171,7 +163,7 @@ class FindByActivity : PassphraseRequiredActivity() {
|
|||
navController.navigate("select-country-prefix")
|
||||
},
|
||||
onQrCodeScanClicked = {
|
||||
cameraPermissionController.request()
|
||||
qrScanLauncher.launch(Unit)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue