fix: enhance gallery and image editor interactions with improved animations and state management

This commit is contained in:
k1ngsterr1
2026-02-02 03:33:31 +05:00
parent 330f9e77ed
commit 44df5691d8

View File

@@ -44,6 +44,8 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.compose.ui.window.Popup import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties import androidx.compose.ui.window.PopupProperties
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
@@ -244,18 +246,27 @@ fun MediaPickerBottomSheet(
label = "scrim_fade" label = "scrim_fade"
) )
// Показываем галерею // Показываем галерею (но НЕ когда редактируем фото)
val showSheet = isVisible && editingItem == null && pendingPhotoUri == null && previewPhotoUri == null val showSheet = isVisible && pendingPhotoUri == null && previewPhotoUri == null
val showGalleryContent = showSheet && editingItem == null && !isClosing
// Запускаем анимацию когда showSheet меняется // Запускаем анимацию когда showSheet меняется
LaunchedEffect(showSheet) { LaunchedEffect(showSheet) {
if (showSheet) { if (showSheet && editingItem == null) {
shouldShow = true shouldShow = true
isClosing = false isClosing = false
sheetHeightPx.snapTo(collapsedHeightPx) sheetHeightPx.snapTo(collapsedHeightPx)
} }
} }
// Закрываем popup когда переходим к редактору
LaunchedEffect(editingItem) {
if (editingItem != null) {
// Галерея уже скрылась, скрываем popup
shouldShow = false
}
}
// Функция для анимированного закрытия // Функция для анимированного закрытия
val animatedClose: () -> Unit = { val animatedClose: () -> Unit = {
if (!isClosing) { if (!isClosing) {
@@ -560,9 +571,10 @@ fun MediaPickerBottomSheet(
onOpenCamera() onOpenCamera()
}, },
onItemClick = { item, position -> onItemClick = { item, position ->
// Telegram-style: клик на фото сразу открывает редактор с caption // Telegram-style: клик на фото сразу открывает редактор
if (!item.isVideo) { if (!item.isVideo) {
thumbnailPosition = position thumbnailPosition = position
// Сразу открываем редактор - галерея закроется автоматически
editingItem = item editingItem = item
} else { } else {
// Для видео - добавляем/убираем из selection // Для видео - добавляем/убираем из selection
@@ -590,49 +602,107 @@ fun MediaPickerBottomSheet(
} }
} }
// Image Editor overlay для фото из галереи // Image Editor FULLSCREEN overlay для фото из галереи
editingItem?.let { item -> if (editingItem != null) {
ImageEditorScreen( // 🎨 Чёрный статус бар для ImageEditor
imageUri = item.uri, DisposableEffect(Unit) {
onDismiss = { val window = (view.context as? android.app.Activity)?.window
val originalStatusBarColor = window?.statusBarColor ?: 0
window?.statusBarColor = android.graphics.Color.BLACK
onDispose {
window?.statusBarColor = originalStatusBarColor
}
}
// Используем Dialog для полного перекрытия экрана включая статус бар
Dialog(
onDismissRequest = {
editingItem = null editingItem = null
thumbnailPosition = null thumbnailPosition = null
shouldShow = true
}, },
onSave = { editedUri -> properties = DialogProperties(
editingItem = null dismissOnBackPress = true,
thumbnailPosition = null dismissOnClickOutside = false,
// Если нет onMediaSelectedWithCaption - открываем preview usePlatformDefaultWidth = false,
if (onMediaSelectedWithCaption == null) { decorFitsSystemWindows = false // Позволяет рисовать под статус баром
previewPhotoUri = editedUri )
} else { ) {
// Отправляем без caption (если нажали Done вместо Send) // Делаем статус бар прозрачным и рисуем под ним
val mediaItem = MediaItem( val dialogView = LocalView.current
id = System.currentTimeMillis(), LaunchedEffect(Unit) {
uri = editedUri, val window = (dialogView.context as? android.app.Activity)?.window
mimeType = "image/png", ?: (dialogView.parent as? android.view.View)?.context?.let {
dateModified = System.currentTimeMillis() (it as? android.app.Activity)?.window
) }
onMediaSelected(listOf(mediaItem)) // Для Dialog нужно получить window диалога
onDismiss() val dialogWindow = (dialogView.parent as? android.view.View)?.let {
var v: android.view.View? = it
while (v != null) {
if (v.context is android.app.Activity) {
break
}
v = v.parent as? android.view.View
}
(v?.context as? android.app.Activity)?.window
} }
}, }
onSaveWithCaption = if (onMediaSelectedWithCaption != null) { editedUri, caption ->
editingItem = null // Fullscreen black background + content
thumbnailPosition = null Box(
val mediaItem = MediaItem( modifier = Modifier
id = System.currentTimeMillis(), .fillMaxSize()
uri = editedUri, .background(Color.Black)
mimeType = "image/png", .systemBarsPadding() // Отступы от системных баров
dateModified = System.currentTimeMillis() ) {
) editingItem?.let { item ->
onMediaSelectedWithCaption(mediaItem, caption) ImageEditorScreen(
onDismiss() imageUri = item.uri,
} else null, onDismiss = {
isDarkTheme = isDarkTheme, editingItem = null
showCaptionInput = onMediaSelectedWithCaption != null, thumbnailPosition = null
recipientName = recipientName, // Возвращаем галерею обратно
thumbnailPosition = thumbnailPosition shouldShow = true
) },
onSave = { editedUri ->
editingItem = null
thumbnailPosition = null
// Если нет onMediaSelectedWithCaption - открываем preview
if (onMediaSelectedWithCaption == null) {
previewPhotoUri = editedUri
} else {
// Отправляем без caption (если нажали Done вместо Send)
val mediaItem = MediaItem(
id = System.currentTimeMillis(),
uri = editedUri,
mimeType = "image/png",
dateModified = System.currentTimeMillis()
)
onMediaSelected(listOf(mediaItem))
onDismiss()
}
},
onSaveWithCaption = if (onMediaSelectedWithCaption != null) { editedUri, caption ->
editingItem = null
thumbnailPosition = null
val mediaItem = MediaItem(
id = System.currentTimeMillis(),
uri = editedUri,
mimeType = "image/png",
dateModified = System.currentTimeMillis()
)
onMediaSelectedWithCaption(mediaItem, caption)
onDismiss()
} else null,
isDarkTheme = isDarkTheme,
showCaptionInput = onMediaSelectedWithCaption != null,
recipientName = recipientName,
thumbnailPosition = thumbnailPosition
)
}
}
}
} }
// Image Editor overlay для фото с камеры // Image Editor overlay для фото с камеры