fix: enhance gallery and image editor interactions with improved animations and state management
This commit is contained in:
@@ -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 для фото с камеры
|
||||||
|
|||||||
Reference in New Issue
Block a user