Refactor username link share screen to enable previews.
This commit is contained in:
parent
252aa3714e
commit
7530d44d28
2 changed files with 277 additions and 214 deletions
|
@ -1,7 +1,8 @@
|
|||
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
|
||||
|
||||
package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Bitmap
|
||||
|
@ -11,6 +12,7 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -45,6 +47,8 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.core.app.ShareCompat
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
|
@ -52,6 +56,7 @@ import com.google.accompanist.permissions.PermissionState
|
|||
import com.google.accompanist.permissions.PermissionStatus
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.signal.core.ui.Buttons
|
||||
import org.signal.core.ui.Dialogs
|
||||
|
@ -59,6 +64,9 @@ import org.signal.core.ui.Snackbars
|
|||
import org.signal.core.ui.theme.SignalTheme
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeData
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.QrCodeState
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.UsernameQrCodeColorScheme
|
||||
import org.thoughtcrime.securesms.components.settings.app.usernamelinks.main.UsernameLinkSettingsState.ActiveTab
|
||||
import org.thoughtcrime.securesms.compose.ComposeFragment
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider
|
||||
|
@ -80,91 +88,33 @@ class UsernameLinkSettingsFragment : ComposeFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun FragmentContent() {
|
||||
val state by viewModel.state
|
||||
val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
|
||||
val scope: CoroutineScope = rememberCoroutineScope()
|
||||
val navController: NavController by remember { mutableStateOf(findNavController()) }
|
||||
var showResetDialog: Boolean by remember { mutableStateOf(false) }
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val linkCopiedEvent: UUID? by viewModel.linkCopiedEvent
|
||||
val helpText = stringResource(id = R.string.UsernameLinkSettings_scan_this_qr_code)
|
||||
|
||||
val cameraPermissionState: PermissionState = rememberPermissionState(permission = android.Manifest.permission.CAMERA) {
|
||||
viewModel.onTabSelected(ActiveTab.Scan)
|
||||
}
|
||||
val linkCopiedEvent: UUID? by viewModel.linkCopiedEvent
|
||||
|
||||
val linkCopiedString = stringResource(R.string.UsernameLinkSettings_link_copied_toast)
|
||||
|
||||
LaunchedEffect(linkCopiedEvent) {
|
||||
if (linkCopiedEvent != null) {
|
||||
snackbarHostState.showSnackbar(linkCopiedString)
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
snackbarHost = { Snackbars.Host(snackbarHostState) },
|
||||
topBar = {
|
||||
TopAppBarContent(
|
||||
activeTab = state.activeTab,
|
||||
scrollBehavior = scrollBehavior,
|
||||
onCodeTabSelected = { viewModel.onTabSelected(ActiveTab.Code) },
|
||||
onScanTabSelected = { viewModel.onTabSelected(ActiveTab.Scan) },
|
||||
cameraPermissionState = cameraPermissionState
|
||||
)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
) { contentPadding ->
|
||||
|
||||
if (state.indeterminateProgress) {
|
||||
Dialogs.IndeterminateProgressDialog()
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = state.activeTab == ActiveTab.Code,
|
||||
enter = slideInHorizontally(initialOffsetX = { fullWidth -> -fullWidth }),
|
||||
exit = slideOutHorizontally(targetOffsetX = { fullWidth -> -fullWidth })
|
||||
) {
|
||||
val helpText = stringResource(id = R.string.UsernameLinkSettings_scan_this_qr_code)
|
||||
UsernameLinkShareScreen(
|
||||
state = state,
|
||||
snackbarHostState = snackbarHostState,
|
||||
scope = scope,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
navController = navController,
|
||||
onShareBadge = {
|
||||
shareQrBadge(viewModel.generateQrCodeImage(helpText))
|
||||
},
|
||||
onResetClicked = { showResetDialog = true },
|
||||
onLinkResultHandled = { viewModel.onUsernameLinkResetResultHandled() }
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = state.activeTab == ActiveTab.Scan,
|
||||
enter = slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }),
|
||||
exit = slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth })
|
||||
) {
|
||||
UsernameQrScanScreen(
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
disposables = disposables.disposables,
|
||||
qrScanResult = state.qrScanResult,
|
||||
onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) },
|
||||
onQrResultHandled = { viewModel.onQrResultHandled() },
|
||||
modifier = Modifier.padding(contentPadding)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (showResetDialog) {
|
||||
ResetDialog(
|
||||
onConfirm = {
|
||||
viewModel.onUsernameLinkReset()
|
||||
showResetDialog = false
|
||||
},
|
||||
onDismiss = { showResetDialog = false }
|
||||
)
|
||||
}
|
||||
MainScreen(
|
||||
state = state,
|
||||
navController = navController,
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
disposables = disposables.disposables,
|
||||
cameraPermissionState = cameraPermissionState,
|
||||
onCodeTabSelected = { viewModel.onTabSelected(ActiveTab.Code) },
|
||||
onScanTabSelected = { viewModel.onTabSelected(ActiveTab.Scan) },
|
||||
onUsernameLinkResetResultHandled = { viewModel.onUsernameLinkResetResultHandled() },
|
||||
onShareBadge = { shareQrBadge(requireActivity(), viewModel.generateQrCodeImage(helpText)) },
|
||||
onQrCodeScanned = { data -> viewModel.onQrCodeScanned(data) },
|
||||
onQrResultHandled = { viewModel.onQrResultHandled() },
|
||||
onLinkReset = { viewModel.onUsernameLinkReset() },
|
||||
onBackNavigationPressed = { requireActivity().onBackPressed() },
|
||||
linkCopiedEvent = linkCopiedEvent
|
||||
)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
|
@ -175,153 +125,266 @@ class UsernameLinkSettingsFragment : ComposeFragment() {
|
|||
super.onResume()
|
||||
viewModel.onResume()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun TopAppBarContent(
|
||||
activeTab: ActiveTab,
|
||||
scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
onCodeTabSelected: () -> Unit = {},
|
||||
onScanTabSelected: () -> Unit = {},
|
||||
cameraPermissionState: PermissionState = previewPermissionState()
|
||||
) {
|
||||
CenterAlignedTopAppBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
title = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
TabButton(
|
||||
label = stringResource(R.string.UsernameLinkSettings_code_tab_name),
|
||||
active = activeTab == ActiveTab.Code,
|
||||
onClick = onCodeTabSelected,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
TabButton(
|
||||
label = stringResource(R.string.UsernameLinkSettings_scan_tab_name),
|
||||
active = activeTab == ActiveTab.Scan,
|
||||
onClick = {
|
||||
if (cameraPermissionState.status.isGranted) {
|
||||
onScanTabSelected()
|
||||
} else {
|
||||
cameraPermissionState.launchPermissionRequest()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = { requireActivity().onBackPressed() }
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.symbol_x_24),
|
||||
contentDescription = stringResource(android.R.string.cancel)
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
@Composable
|
||||
private fun MainScreen(
|
||||
state: UsernameLinkSettingsState,
|
||||
navController: NavController? = null,
|
||||
lifecycleOwner: LifecycleOwner = previewLifecycleOwner,
|
||||
disposables: CompositeDisposable = CompositeDisposable(),
|
||||
cameraPermissionState: PermissionState = previewPermissionState(),
|
||||
onCodeTabSelected: () -> Unit = {},
|
||||
onScanTabSelected: () -> Unit = {},
|
||||
onUsernameLinkResetResultHandled: () -> Unit = {},
|
||||
onShareBadge: () -> Unit = {},
|
||||
onQrCodeScanned: (String) -> Unit = {},
|
||||
onQrResultHandled: () -> Unit = {},
|
||||
onLinkReset: () -> Unit = {},
|
||||
onBackNavigationPressed: () -> Unit = {},
|
||||
linkCopiedEvent: UUID? = null
|
||||
) {
|
||||
val snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
|
||||
val scope: CoroutineScope = rememberCoroutineScope()
|
||||
var showResetDialog: Boolean by remember { mutableStateOf(false) }
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
|
||||
val linkCopiedString = stringResource(R.string.UsernameLinkSettings_link_copied_toast)
|
||||
|
||||
LaunchedEffect(linkCopiedEvent) {
|
||||
if (linkCopiedEvent != null) {
|
||||
snackbarHostState.showSnackbar(linkCopiedString)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TabButton(label: String, active: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
val colors = if (active) {
|
||||
ButtonDefaults.filledTonalButtonColors()
|
||||
} else {
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = SignalTheme.colors.colorSurface2,
|
||||
contentColor = MaterialTheme.colorScheme.onSurface
|
||||
Scaffold(
|
||||
snackbarHost = { Snackbars.Host(snackbarHostState) },
|
||||
topBar = {
|
||||
TopAppBarContent(
|
||||
activeTab = state.activeTab,
|
||||
scrollBehavior = scrollBehavior,
|
||||
onCodeTabSelected = onCodeTabSelected,
|
||||
onScanTabSelected = onScanTabSelected,
|
||||
cameraPermissionState = cameraPermissionState,
|
||||
onBackNavigationPressed = onBackNavigationPressed
|
||||
)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||
) { contentPadding ->
|
||||
|
||||
if (state.indeterminateProgress) {
|
||||
Dialogs.IndeterminateProgressDialog()
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = state.activeTab == ActiveTab.Code,
|
||||
enter = slideInHorizontally(initialOffsetX = { fullWidth -> -fullWidth }),
|
||||
exit = slideOutHorizontally(targetOffsetX = { fullWidth -> -fullWidth })
|
||||
) {
|
||||
UsernameLinkShareScreen(
|
||||
state = state,
|
||||
snackbarHostState = snackbarHostState,
|
||||
scope = scope,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
navController = navController,
|
||||
onShareBadge = onShareBadge,
|
||||
onResetClicked = { showResetDialog = true },
|
||||
onLinkResultHandled = onUsernameLinkResetResultHandled
|
||||
)
|
||||
}
|
||||
Buttons.Small(
|
||||
onClick = onClick,
|
||||
modifier = modifier.defaultMinSize(minWidth = 100.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = colors
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = state.activeTab == ActiveTab.Scan,
|
||||
enter = slideInHorizontally(initialOffsetX = { fullWidth -> fullWidth }),
|
||||
exit = slideOutHorizontally(targetOffsetX = { fullWidth -> fullWidth })
|
||||
) {
|
||||
Text(label)
|
||||
UsernameQrScanScreen(
|
||||
lifecycleOwner = lifecycleOwner,
|
||||
disposables = disposables,
|
||||
qrScanResult = state.qrScanResult,
|
||||
onQrCodeScanned = onQrCodeScanned,
|
||||
onQrResultHandled = onQrResultHandled,
|
||||
modifier = Modifier.padding(contentPadding)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ResetDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_title),
|
||||
body = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_body),
|
||||
confirm = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_confirm_button),
|
||||
dismiss = stringResource(id = android.R.string.cancel),
|
||||
onConfirm = onConfirm,
|
||||
onDismiss = onDismiss
|
||||
if (showResetDialog) {
|
||||
ResetDialog(
|
||||
onConfirm = {
|
||||
onLinkReset()
|
||||
showResetDialog = false
|
||||
},
|
||||
onDismiss = { showResetDialog = false }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewAppBar() {
|
||||
SignalTheme {
|
||||
Surface {
|
||||
@Composable
|
||||
private fun TopAppBarContent(
|
||||
activeTab: ActiveTab,
|
||||
scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(),
|
||||
onCodeTabSelected: () -> Unit = {},
|
||||
onScanTabSelected: () -> Unit = {},
|
||||
cameraPermissionState: PermissionState = previewPermissionState(),
|
||||
onBackNavigationPressed: () -> Unit = {}
|
||||
) {
|
||||
CenterAlignedTopAppBar(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
title = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
TabButton(
|
||||
label = stringResource(R.string.UsernameLinkSettings_code_tab_name),
|
||||
active = activeTab == ActiveTab.Code,
|
||||
onClick = onCodeTabSelected,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
TabButton(
|
||||
label = stringResource(R.string.UsernameLinkSettings_scan_tab_name),
|
||||
active = activeTab == ActiveTab.Scan,
|
||||
onClick = {
|
||||
if (cameraPermissionState.status.isGranted) {
|
||||
onScanTabSelected()
|
||||
} else {
|
||||
cameraPermissionState.launchPermissionRequest()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onBackNavigationPressed
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.symbol_x_24),
|
||||
contentDescription = stringResource(android.R.string.cancel)
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TabButton(label: String, active: Boolean, onClick: () -> Unit, modifier: Modifier = Modifier) {
|
||||
val colors = if (active) {
|
||||
ButtonDefaults.filledTonalButtonColors()
|
||||
} else {
|
||||
ButtonDefaults.buttonColors(
|
||||
containerColor = SignalTheme.colors.colorSurface2,
|
||||
contentColor = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
Buttons.Small(
|
||||
onClick = onClick,
|
||||
modifier = modifier.defaultMinSize(minWidth = 100.dp),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = colors
|
||||
) {
|
||||
Text(label)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ResetDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) {
|
||||
Dialogs.SimpleAlertDialog(
|
||||
title = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_title),
|
||||
body = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_body),
|
||||
confirm = stringResource(id = R.string.UsernameLinkSettings_reset_link_dialog_confirm_button),
|
||||
dismiss = stringResource(id = android.R.string.cancel),
|
||||
onConfirm = onConfirm,
|
||||
onDismiss = onDismiss
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun AppBarPreview() {
|
||||
SignalTheme {
|
||||
Surface {
|
||||
Column {
|
||||
TopAppBarContent(activeTab = ActiveTab.Code)
|
||||
TopAppBarContent(activeTab = ActiveTab.Scan)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PreviewAll() {
|
||||
FragmentContent()
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewResetDialog() {
|
||||
SignalTheme {
|
||||
Surface {
|
||||
ResetDialog(onConfirm = {}, onDismiss = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun previewPermissionState(): PermissionState {
|
||||
return object : PermissionState {
|
||||
override val permission: String = ""
|
||||
override val status: PermissionStatus = PermissionStatus.Granted
|
||||
override fun launchPermissionRequest() = Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun shareQrBadge(badge: Bitmap?) {
|
||||
if (badge == null) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream().use { byteArrayOutputStream ->
|
||||
badge.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
|
||||
byteArrayOutputStream.flush()
|
||||
val bytes = byteArrayOutputStream.toByteArray()
|
||||
val shareUri = BlobProvider.getInstance()
|
||||
.forData(bytes)
|
||||
.withMimeType("image/png")
|
||||
.withFileName("SignalGroupQr.png")
|
||||
.createForSingleSessionInMemory()
|
||||
|
||||
val intent = ShareCompat.IntentBuilder.from(requireActivity())
|
||||
.setType("image/png")
|
||||
.setStream(shareUri)
|
||||
.createChooserIntent()
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
startActivity(intent)
|
||||
}
|
||||
} finally {
|
||||
badge.recycle()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun MainScreenPreview() {
|
||||
SignalTheme {
|
||||
MainScreen(
|
||||
state = UsernameLinkSettingsState(
|
||||
activeTab = ActiveTab.Code,
|
||||
username = "PeterParker.42",
|
||||
usernameLinkState = UsernameLinkState.Present("https://signal.org"),
|
||||
qrCodeState = QrCodeState.Present(QrCodeData.forData("PeterParker.42", 64)),
|
||||
qrCodeColorScheme = UsernameQrCodeColorScheme.Orange
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light Theme", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark Theme", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun ResetDialogPreview() {
|
||||
SignalTheme {
|
||||
Surface {
|
||||
ResetDialog(onConfirm = {}, onDismiss = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun previewPermissionState(): PermissionState {
|
||||
return object : PermissionState {
|
||||
override val permission: String = ""
|
||||
override val status: PermissionStatus = PermissionStatus.Granted
|
||||
override fun launchPermissionRequest() = Unit
|
||||
}
|
||||
}
|
||||
|
||||
private val previewLifecycleOwner: LifecycleOwner = object : LifecycleOwner {
|
||||
override val lifecycle: Lifecycle
|
||||
get() = TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
private fun shareQrBadge(activity: Activity, badge: Bitmap?) {
|
||||
if (badge == null) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream().use { byteArrayOutputStream ->
|
||||
badge.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
|
||||
byteArrayOutputStream.flush()
|
||||
val bytes = byteArrayOutputStream.toByteArray()
|
||||
val shareUri = BlobProvider.getInstance()
|
||||
.forData(bytes)
|
||||
.withMimeType("image/png")
|
||||
.withFileName("SignalGroupQr.png")
|
||||
.createForSingleSessionInMemory()
|
||||
|
||||
val intent = ShareCompat.IntentBuilder(activity)
|
||||
.setType("image/png")
|
||||
.setStream(shareUri)
|
||||
.createChooserIntent()
|
||||
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
} finally {
|
||||
badge.recycle()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ fun UsernameLinkShareScreen(
|
|||
onLinkResultHandled: () -> Unit,
|
||||
snackbarHostState: SnackbarHostState,
|
||||
scope: CoroutineScope,
|
||||
navController: NavController,
|
||||
navController: NavController?,
|
||||
onShareBadge: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onResetClicked: () -> Unit
|
||||
|
@ -93,9 +93,9 @@ fun UsernameLinkShareScreen(
|
|||
|
||||
ButtonBar(
|
||||
onShareClicked = onShareBadge,
|
||||
onColorClicked = { navController.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkQrColorPickerFragment()) },
|
||||
onColorClicked = { navController?.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkQrColorPickerFragment()) },
|
||||
onLinkClicked = {
|
||||
navController.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkShareBottomSheet())
|
||||
navController?.safeNavigate(UsernameLinkSettingsFragmentDirections.actionUsernameLinkSettingsFragmentToUsernameLinkShareBottomSheet())
|
||||
},
|
||||
linkState = state.usernameLinkState
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue