Add image compression and improve document edit UI

- Add Swift ImageCompression helper to enforce 200KB limit on iOS
- Update iOS views to use compression for all image uploads
- Fix iOS EditDocumentView to show success only after all uploads complete
- Add AsyncImage thumbnails to Android EditDocumentScreen
- Fix Android success message visibility with delay before state reset
- Add proper error handling for failed image uploads
- Add resetUpdateState on error for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Trey t
2025-11-11 21:23:22 -06:00
parent 7740438ea6
commit 22949d18a7
10 changed files with 321 additions and 14 deletions

View File

@@ -0,0 +1,69 @@
package com.mycrib.util
import com.mycrib.platform.ImageData
import kotlinx.cinterop.*
import platform.Foundation.*
import platform.UIKit.*
import platform.posix.memcpy
/**
* iOS implementation of image compression
* Compresses images to JPEG format and ensures they don't exceed MAX_IMAGE_SIZE_BYTES
*/
@OptIn(ExperimentalForeignApi::class)
actual object ImageCompressor {
/**
* Compress an ImageData to JPEG format with size limit
* @param imageData The image to compress
* @return Compressed image data as ByteArray
*/
actual fun compressImage(imageData: ImageData): ByteArray {
// Convert ByteArray to NSData
val nsData = imageData.bytes.usePinned { pinned ->
NSData.create(
bytes = pinned.addressOf(0),
length = imageData.bytes.size.toULong()
)
}
// Create UIImage from data
val image = UIImage.imageWithData(nsData) ?: return imageData.bytes
// Compress with iterative quality reduction
return compressImageToTarget(image, ImageConfig.MAX_IMAGE_SIZE_BYTES.toLong())
}
/**
* Compress a UIImage to target size
*/
private fun compressImageToTarget(image: UIImage, targetSizeBytes: Long): ByteArray {
var quality = ImageConfig.INITIAL_JPEG_QUALITY / 100.0
var compressedData: NSData? = null
while (quality >= ImageConfig.MIN_JPEG_QUALITY / 100.0) {
compressedData = UIImageJPEGRepresentation(image, quality)
if (compressedData != null && compressedData.length.toLong() <= targetSizeBytes) {
break
}
quality -= 0.05 // Reduce quality by 5%
}
// Convert NSData to ByteArray
return compressedData?.toByteArray() ?: image.let {
UIImageJPEGRepresentation(it, ImageConfig.MIN_JPEG_QUALITY / 100.0)?.toByteArray() ?: ByteArray(0)
}
}
/**
* Convert NSData to ByteArray
*/
private fun NSData.toByteArray(): ByteArray {
return ByteArray(this.length.toInt()).apply {
usePinned {
memcpy(it.addressOf(0), this@toByteArray.bytes, this@toByteArray.length)
}
}
}
}