diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt index 6b519ea1f2..e82fb6a71a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/usernamelinks/main/UsernameLinkSettingsFragment.kt @@ -1,3 +1,5 @@ +@file:OptIn(ExperimentalMaterial3Api::class) + package org.thoughtcrime.securesms.components.settings.app.usernamelinks.main import android.content.Intent @@ -9,21 +11,24 @@ 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.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.defaultMinSize -import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Surface import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -32,6 +37,8 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -41,6 +48,7 @@ import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import com.google.accompanist.permissions.ExperimentalPermissionsApi 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 kotlinx.coroutines.CoroutineScope @@ -65,6 +73,7 @@ class UsernameLinkSettingsFragment : ComposeFragment() { private val screenshotController = ScreenshotController() + @OptIn(ExperimentalMaterial3Api::class) @Composable override fun FragmentContent() { val state by viewModel.state @@ -72,10 +81,21 @@ class UsernameLinkSettingsFragment : ComposeFragment() { val scope: CoroutineScope = rememberCoroutineScope() val navController: NavController by remember { mutableStateOf(findNavController()) } var showResetDialog: Boolean by remember { mutableStateOf(false) } + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val cameraPermissionState: PermissionState = rememberPermissionState(permission = android.Manifest.permission.CAMERA) Scaffold( snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - topBar = { TopAppBarContent(state.activeTab) } + 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) { @@ -138,41 +158,57 @@ class UsernameLinkSettingsFragment : ComposeFragment() { viewModel.onResume() } + @OptIn(ExperimentalMaterial3Api::class) @Composable - private fun TopAppBarContent(activeTab: ActiveTab) { - val cameraPermissionState: PermissionState = rememberPermissionState(permission = android.Manifest.permission.CAMERA) - - Box( + private fun TopAppBarContent( + activeTab: ActiveTab, + scrollBehavior: TopAppBarScrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(), + onCodeTabSelected: () -> Unit = {}, + onScanTabSelected: () -> Unit = {}, + cameraPermissionState: PermissionState = previewPermissionState() + ) { + CenterAlignedTopAppBar( modifier = Modifier - .fillMaxWidth() - .height(64.dp) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .fillMaxHeight(), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - TabButton( - label = stringResource(R.string.UsernameLinkSettings_code_tab_name), - active = activeTab == ActiveTab.Code, - onClick = { viewModel.onTabSelected(ActiveTab.Code) }, - modifier = Modifier.padding(end = 8.dp) - ) - TabButton( - label = stringResource(R.string.UsernameLinkSettings_scan_tab_name), - active = activeTab == ActiveTab.Scan, - onClick = { - if (cameraPermissionState.status.isGranted) { - viewModel.onTabSelected(ActiveTab.Scan) - } else { - cameraPermissionState.launchPermissionRequest() - } - } - ) - } - } + .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().onNavigateUp() } + ) { + Icon( + painter = painterResource(R.drawable.symbol_x_24), + contentDescription = stringResource(android.R.string.cancel) + ) + } + }, + scrollBehavior = scrollBehavior + ) } @Composable @@ -185,7 +221,7 @@ class UsernameLinkSettingsFragment : ComposeFragment() { contentColor = MaterialTheme.colorScheme.onSurface ) } - Buttons.MediumTonal( + Buttons.Small( onClick = onClick, modifier = modifier.defaultMinSize(minWidth = 100.dp), shape = RoundedCornerShape(12.dp), @@ -234,6 +270,14 @@ class UsernameLinkSettingsFragment : ComposeFragment() { } } + 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) { try { ByteArrayOutputStream().use { byteArrayOutputStream ->