diff --git a/.cursor/rules/general.mdc b/.cursor/rules/general.mdc index 59eaf92..621cbfd 100644 --- a/.cursor/rules/general.mdc +++ b/.cursor/rules/general.mdc @@ -54,6 +54,11 @@ When working with the mobile app: - `GlobalScope.launch { }` for fire-and-forget background operations on iOS - Platform-specific logging with `ru.fromchat.core.Logger` +## Modifier.conditional +- Use `Modifier.conditional` when you need to apply different modifiers based on a condition. +- Both `if` and `else` closures are `@Composable` and receive the current Modifier; they return a Modifier to be appended. +- Source: `utils/shared/.../Compose.kt` — uses `composed { }`; when true applies `if`, when false applies `else` (default `{ Modifier }`). + ## C Interop Gotchas - NSDictionaryAsKMap (Kotlin's internal NSDictionary wrapper) ≠ NSDictionary (Foundation object) - Security framework expects strict CFDictionaryRef types, not NSDictionary toll-free bridging diff --git a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt index b244c7c..3d848c5 100644 --- a/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt +++ b/app/shared/src/commonMain/kotlin/ru/fromchat/ui/chat/AttachmentPreview.kt @@ -38,6 +38,7 @@ import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage import coil3.compose.rememberAsyncImagePainter +import com.pr0gramm3r101.utils.conditional import com.pr0gramm3r101.utils.crypto.Base64 import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -64,24 +65,33 @@ fun AttachmentPreview( fileAspectRatio: Float? = null, modifier: Modifier = Modifier ) { - val isImage = file?.let { isImageFilename(it.name) } ?: pendingFileUri?.let { - it.contains("image", ignoreCase = true) || it.endsWith(".jpg", true) || - it.endsWith(".png", true) || it.endsWith(".jpeg", true) || - it.endsWith(".gif", true) || it.endsWith(".webp", true) - } ?: false + val isImage = when { + file != null -> isImageFilename(file.name) + pendingFileUri != null -> { + isImageFilename( + pendingFileUri + .substringAfterLast('/') + .substringBefore('?') + ) + } + else -> false + } - val baseModifier = modifier - .then( - if (fileAspectRatio != null && fileAspectRatio > 0f) { - Modifier.aspectRatio(fileAspectRatio).sizeIn(maxWidth = IMAGE_SIZE, maxHeight = IMAGE_SIZE) - } else { - Modifier.size(IMAGE_SIZE) - } - ) - .clip(RoundedCornerShape(IMAGE_RADIUS)) - .background(MaterialTheme.colorScheme.surfaceVariant) Box( - modifier = baseModifier, + modifier = modifier + .conditional( + fileAspectRatio != null && fileAspectRatio > 0f, + `if` = { + Modifier + .aspectRatio(fileAspectRatio!!) + .sizeIn(maxWidth = IMAGE_SIZE, maxHeight = IMAGE_SIZE) + }, + `else` = { + Modifier.size(IMAGE_SIZE) + } + ) + .clip(RoundedCornerShape(IMAGE_RADIUS)) + .background(MaterialTheme.colorScheme.surfaceVariant), contentAlignment = Alignment.Center ) { when {