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.sp
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.PopupProperties
import androidx.activity.compose.BackHandler
@@ -244,18 +246,27 @@ fun MediaPickerBottomSheet(
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 меняется
LaunchedEffect(showSheet) {
if (showSheet) {
if (showSheet && editingItem == null) {
shouldShow = true
isClosing = false
sheetHeightPx.snapTo(collapsedHeightPx)
}
}
// Закрываем popup когда переходим к редактору
LaunchedEffect(editingItem) {
if (editingItem != null) {
// Галерея уже скрылась, скрываем popup
shouldShow = false
}
}
// Функция для анимированного закрытия
val animatedClose: () -> Unit = {
if (!isClosing) {
@@ -560,9 +571,10 @@ fun MediaPickerBottomSheet(
onOpenCamera()
},
onItemClick = { item, position ->
// Telegram-style: клик на фото сразу открывает редактор с caption
// Telegram-style: клик на фото сразу открывает редактор
if (!item.isVideo) {
thumbnailPosition = position
// Сразу открываем редактор - галерея закроется автоматически
editingItem = item
} else {
// Для видео - добавляем/убираем из selection
@@ -590,49 +602,107 @@ fun MediaPickerBottomSheet(
}
}
// Image Editor overlay для фото из галереи
editingItem?.let { item ->
ImageEditorScreen(
imageUri = item.uri,
onDismiss = {
// Image Editor FULLSCREEN overlay для фото из галереи
if (editingItem != null) {
// 🎨 Чёрный статус бар для ImageEditor
DisposableEffect(Unit) {
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
thumbnailPosition = null
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()
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = false,
usePlatformDefaultWidth = false,
decorFitsSystemWindows = false // Позволяет рисовать под статус баром
)
) {
// Делаем статус бар прозрачным и рисуем под ним
val dialogView = LocalView.current
LaunchedEffect(Unit) {
val window = (dialogView.context as? android.app.Activity)?.window
?: (dialogView.parent as? android.view.View)?.context?.let {
(it as? android.app.Activity)?.window
}
// Для Dialog нужно получить window диалога
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
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
)
}
// Fullscreen black background + content
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black)
.systemBarsPadding() // Отступы от системных баров
) {
editingItem?.let { item ->
ImageEditorScreen(
imageUri = item.uri,
onDismiss = {
editingItem = null
thumbnailPosition = null
// Возвращаем галерею обратно
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 для фото с камеры