diff --git a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesComponents.kt b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesComponents.kt index 80aceb6..9218ca9 100644 --- a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesComponents.kt +++ b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesComponents.kt @@ -21,9 +21,18 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowForward +import androidx.compose.material.icons.filled.ChatBubbleOutline +import androidx.compose.material.icons.filled.Close +import androidx.compose.material.icons.filled.Group +import androidx.compose.material.icons.filled.Star +import androidx.compose.material.icons.filled.StarBorder import androidx.compose.material3.Checkbox +import androidx.compose.material3.Icon import androidx.compose.material3.CheckboxDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.HorizontalDivider @@ -49,6 +58,7 @@ import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.text.PlatformTextStyle import androidx.compose.ui.text.TextStyle import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.boundsInWindow @@ -998,10 +1008,10 @@ fun FilesDetailsSheet( loading: Boolean, onDismiss: () -> Unit, onTabChange: (FileDetailsTab) -> Unit, + onToggleFavorite: () -> Unit, onWebOnlyAction: (String) -> Unit, ) { if (item == null) return - val base = serverUrl.trimEnd('/') var commentDraft by remember(item.relativePath) { mutableStateOf("") } androidx.compose.ui.window.Dialog(onDismissRequest = onDismiss) { Surface( @@ -1016,9 +1026,26 @@ fun FilesDetailsSheet( .fillMaxSize() .padding(20.dp), ) { + // Крестик закрытия — правый верхний угол (по макету) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + Box( + modifier = Modifier + .size(28.dp) + .clip(CircleShape) + .clickable(onClick = onDismiss), + contentAlignment = Alignment.Center, + ) { + Icon( + Icons.Filled.Close, + contentDescription = "Закрыть", + tint = F7Colors.TextSecondary, + modifier = Modifier.size(20.dp), + ) + } + } Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, + horizontalArrangement = Arrangement.spacedBy(12.dp), verticalAlignment = Alignment.Top, ) { Column(modifier = Modifier.weight(1f)) { @@ -1029,52 +1056,86 @@ fun FilesDetailsSheet( maxLines = 2, overflow = TextOverflow.Ellipsis, ) - Spacer(Modifier.height(6.dp)) - val metaParts = buildList { - item.size?.let { add(formatFileSize(it)) } - item.lastModified?.let { - add( - SimpleDateFormat("d MMMM", Locale("ru")).format(Date(it)), + Spacer(Modifier.height(8.dp)) + // Чип владельца (аватар-инициал + логин) — по макету + Row( + modifier = Modifier + .clip(RoundedCornerShape(100.dp)) + .background(F7Colors.SurfaceMuted) + .padding(start = 4.dp, end = 10.dp, top = 4.dp, bottom = 4.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(6.dp), + ) { + Box( + modifier = Modifier + .size(20.dp) + .clip(CircleShape) + .background(F7Colors.PrimaryLight), + contentAlignment = Alignment.Center, + ) { + Text( + ownerLabel.firstOrNull()?.uppercaseChar()?.toString() ?: "?", + style = MaterialTheme.typography.labelSmall, + color = F7Colors.Primary, + fontWeight = FontWeight.SemiBold, ) } - add("Владелец $ownerLabel") + Text( + ownerLabel, + style = MaterialTheme.typography.bodySmall, + color = F7Colors.TextSecondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) } - Text( - metaParts.joinToString(" • "), - style = MaterialTheme.typography.bodySmall, - color = F7Colors.TextSecondary, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - ) } - TextButton(onClick = onDismiss) { - Text("✕", style = MaterialTheme.typography.titleMedium) + Column(horizontalAlignment = Alignment.End) { + val dateSize = buildList { + item.lastModified?.let { + add(SimpleDateFormat("d MMMM", Locale("ru")).format(Date(it))) + } + item.size?.let { add(formatFileSize(it)) } + } + if (dateSize.isNotEmpty()) { + Text( + dateSize.joinToString(" / "), + style = MaterialTheme.typography.bodySmall, + color = F7Colors.TextSecondary, + ) + Spacer(Modifier.height(8.dp)) + } + Icon( + if (item.favorite) Icons.Filled.Star else Icons.Filled.StarBorder, + contentDescription = "Избранное", + tint = if (item.favorite) F7Colors.Primary else F7Colors.TextSecondary, + modifier = Modifier + .size(24.dp) + .clip(CircleShape) + .clickable(onClick = onToggleFavorite), + ) } } Spacer(Modifier.height(16.dp)) Row( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(24.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - FilesDetailsTabButton( - serverUrl = serverUrl, - label = "Общий доступ", - iconPath = "files/many-person-gray.svg", - selected = tab == FileDetailsTab.Sharing, - onClick = { onTabChange(FileDetailsTab.Sharing) }, - ) - FilesDetailsTabButton( - serverUrl = serverUrl, - label = "События", - iconPath = "files/grid-files-gray.svg", + FilesDetailsTabPill( + icon = Icons.Filled.ChatBubbleOutline, + contentDescription = "Обсуждение", selected = tab == FileDetailsTab.Events, onClick = { onTabChange(FileDetailsTab.Events) }, + modifier = Modifier.weight(1f), + ) + FilesDetailsTabPill( + icon = Icons.Filled.Group, + contentDescription = "Общий доступ", + selected = tab == FileDetailsTab.Sharing, + onClick = { onTabChange(FileDetailsTab.Sharing) }, + modifier = Modifier.weight(1f), ) } - HorizontalDivider( - modifier = Modifier.padding(top = 8.dp), - color = F7Colors.Border.copy(alpha = 0.5f), - ) + Spacer(Modifier.height(16.dp)) Box( modifier = Modifier .weight(1f) @@ -1117,42 +1178,28 @@ fun FilesDetailsSheet( } @Composable -private fun FilesDetailsTabButton( - serverUrl: String, - label: String, - iconPath: String, +private fun FilesDetailsTabPill( + icon: androidx.compose.ui.graphics.vector.ImageVector, + contentDescription: String, selected: Boolean, onClick: () -> Unit, + modifier: Modifier = Modifier, ) { - val base = serverUrl.trimEnd('/') - Column( - modifier = Modifier.clickable(onClick = onClick), - horizontalAlignment = Alignment.CenterHorizontally, + val shape = RoundedCornerShape(14.dp) + Box( + modifier = modifier + .height(40.dp) + .clip(shape) + .background(if (selected) F7Colors.PrimaryLight else F7Colors.Surface) + .border(1.dp, if (selected) Color.Transparent else F7Colors.Border, shape) + .clickable(onClick = onClick), + contentAlignment = Alignment.Center, ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - AsyncImage( - model = "$base/themes/forbion/images/$iconPath", - contentDescription = null, - modifier = Modifier.size(16.dp), - contentScale = ContentScale.Fit, - ) - Text( - label, - style = MaterialTheme.typography.bodyMedium, - fontWeight = if (selected) FontWeight.SemiBold else FontWeight.Medium, - color = if (selected) F7Colors.TextPrimary else F7Colors.TextSecondary, - ) - } - Spacer(Modifier.height(8.dp)) - Box( - modifier = Modifier - .height(2.dp) - .width(72.dp) - .clip(RoundedCornerShape(1.dp)) - .background(if (selected) F7Colors.Primary else Color.Transparent), + Icon( + icon, + contentDescription = contentDescription, + tint = if (selected) F7Colors.Primary else F7Colors.TextSecondary, + modifier = Modifier.size(20.dp), ) } } @@ -1348,8 +1395,24 @@ private fun FilesEventsTabContent( modifier = Modifier.weight(1f), onEnter = onSubmitComment, ) - TextButton(onClick = onSubmitComment) { - Text("→", fontSize = 20.sp) + Box( + modifier = Modifier + .size(40.dp) + .clip(CircleShape) + .background( + Brush.linearGradient( + listOf(F7Colors.PrimaryGradientStart, F7Colors.PrimaryGradientEnd), + ), + ) + .clickable(onClick = onSubmitComment), + contentAlignment = Alignment.Center, + ) { + Icon( + Icons.AutoMirrored.Filled.ArrowForward, + contentDescription = "Отправить", + tint = Color.White, + modifier = Modifier.size(18.dp), + ) } } Text( diff --git a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesScreen.kt b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesScreen.kt index 08d8654..79f5cfe 100644 --- a/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesScreen.kt +++ b/feature/files/src/main/java/ru/forbion/f7cloud/feature/files/FilesScreen.kt @@ -360,6 +360,7 @@ fun FilesScreen( loading = state.detailsLoading, onDismiss = vm::hideDetails, onTabChange = vm::setDetailsTab, + onToggleFavorite = { state.detailsItem?.let { vm.toggleFavorite(session, it) } }, onWebOnlyAction = vm::showWebOnlyMessage, )