From 925151faf363ea8fa0dbb529c38ab30df10e4d4e Mon Sep 17 00:00:00 2001 From: m Date: Sat, 12 Sep 2026 15:46:53 +0200 Subject: [PATCH] floating nav bar interraction --- .../mobile/ui/folderlist/FolderListScreen.kt | 42 +++------ .../mobile/ui/navigation/FloatingNavBar.kt | 91 +++++++++++++++++++ 2 files changed, 106 insertions(+), 27 deletions(-) diff --git a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/folderlist/FolderListScreen.kt b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/folderlist/FolderListScreen.kt index a4a073d..9969cf2 100644 --- a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/folderlist/FolderListScreen.kt +++ b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/folderlist/FolderListScreen.kt @@ -30,9 +30,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.CreateNewFolder -import androidx.compose.material.icons.filled.DriveFileMove import androidx.compose.material.icons.filled.Folder -import androidx.compose.material.icons.filled.MergeType import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.Button import androidx.compose.material3.Card @@ -79,6 +77,7 @@ import com.vaultdrop.mobile.ui.components.ServerStatusBadge import com.vaultdrop.mobile.ui.components.rememberSelectionState import com.vaultdrop.mobile.ui.navigation.FloatingNavBar import com.vaultdrop.mobile.ui.navigation.NavTab +import com.vaultdrop.mobile.ui.navigation.SelectionNavBar import kotlinx.coroutines.delay import timber.log.Timber import java.util.Locale @@ -215,30 +214,7 @@ fun FolderListScreen( } }, actions = { - if (selection.active) { - IconButton( - onClick = { showMoveDialog = true }, - enabled = selection.ids.isNotEmpty(), - ) { - Icon( - Icons.Filled.DriveFileMove, - contentDescription = stringResource(R.string.move_files), - ) - } - IconButton( - onClick = { - val ids = selection.ids.toList() - selection.clear() - onBuildPdf(ids) - }, - enabled = selection.ids.isNotEmpty(), - ) { - Icon( - Icons.Filled.MergeType, - contentDescription = stringResource(R.string.selection_assemble), - ) - } - } else { + if (!selection.active) { ServerStatusBadge( status = connectionStatus, onClick = connectionStatusViewModel::checkNow, @@ -251,7 +227,19 @@ fun FolderListScreen( ) }, bottomBar = { - FloatingNavBar(selected = selectedTab, onSelect = onTabSelected) + if (selection.active) { + SelectionNavBar( + onMove = { showMoveDialog = true }, + onBuildPdf = { + val ids = selection.ids.toList() + selection.clear() + onBuildPdf(ids) + }, + enabled = selection.ids.isNotEmpty(), + ) + } else { + FloatingNavBar(selected = selectedTab, onSelect = onTabSelected) + } }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, ) { padding -> diff --git a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/FloatingNavBar.kt b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/FloatingNavBar.kt index 190d395..098ba2a 100644 --- a/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/FloatingNavBar.kt +++ b/mobile-kotlin/app/src/main/java/com/vaultdrop/mobile/ui/navigation/FloatingNavBar.kt @@ -12,7 +12,9 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.DriveFileMove import androidx.compose.material.icons.filled.Folder +import androidx.compose.material.icons.filled.MergeType import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.outlined.Folder @@ -119,3 +121,92 @@ fun FloatingNavBar( } } } + +/** Barre d'actions affichée à la place de la nav quand le mode multi-sélection est actif. */ +@Composable +fun SelectionNavBar( + onMove: () -> Unit, + onBuildPdf: () -> Unit, + enabled: Boolean, + modifier: Modifier = Modifier, +) { + Box( + modifier = modifier + .fillMaxWidth() + .padding(start = 20.dp, end = 20.dp, bottom = 16.dp), + contentAlignment = Alignment.Center, + ) { + Surface( + shape = RoundedCornerShape(30.dp), + color = MaterialTheme.colorScheme.surface, + shadowElevation = 8.dp, + modifier = Modifier.widthIn(max = 400.dp).fillMaxWidth(), + ) { + Row( + modifier = Modifier.padding(vertical = 8.dp, horizontal = 8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + SelectionAction( + label = stringResource(R.string.move_files), + icon = Icons.Filled.DriveFileMove, + enabled = enabled, + onClick = onMove, + modifier = Modifier.weight(1f), + ) + SelectionAction( + label = stringResource(R.string.selection_assemble), + icon = Icons.Filled.MergeType, + enabled = enabled, + onClick = onBuildPdf, + modifier = Modifier.weight(1f), + ) + } + } + } +} + +@Composable +private fun SelectionAction( + label: String, + icon: ImageVector, + enabled: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val tint = if (enabled) MaterialTheme.colorScheme.primary + else MaterialTheme.colorScheme.onSurfaceVariant + Surface( + onClick = onClick, + enabled = enabled, + shape = RoundedCornerShape(20.dp), + color = if (enabled) MaterialTheme.colorScheme.primaryContainer + else MaterialTheme.colorScheme.surfaceVariant, + modifier = modifier, + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 6.dp), + contentAlignment = Alignment.Center, + ) { + Column(horizontalAlignment = Alignment.CenterHorizontally) { + Icon( + imageVector = icon, + contentDescription = null, + tint = tint, + modifier = Modifier.size(22.dp), + ) + Text( + text = label, + color = tint, + fontSize = 11.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(top = 2.dp), + ) + } + } + } +}