Refactor image handling and decoding logic

- Introduced a maximum bitmap decode dimension to prevent excessive memory usage.
- Enhanced base64 to bitmap conversion by extracting payload and applying EXIF orientation.
- Improved error handling for image downloads and decoding processes.
- Simplified media picker and chat input components to manage keyboard visibility more effectively.
- Updated color selection grid to adaptively adjust based on available width.
- Added safety checks for notifications and call actions in profile screens.
- Optimized bitmap decoding in uriToBase64Image to handle large images more efficiently.
This commit is contained in:
2026-02-20 02:45:00 +05:00
parent 5cf8b2866f
commit 88e2084f8b
26 changed files with 943 additions and 464 deletions

View File

@@ -1020,17 +1020,9 @@ object MessageCrypto {
val keySpec = SecretKeySpec(keyBytes, "AES")
val ivSpec = IvParameterSpec(iv)
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec)
val decompressed = cipher.doFinal(ciphertext)
val compressedBytes = cipher.doFinal(ciphertext)
// Decompress with inflate
val inflater = java.util.zip.Inflater()
inflater.setInput(decompressed)
val outputBuffer = ByteArray(decompressed.size * 10)
val outputSize = inflater.inflate(outputBuffer)
inflater.end()
val plaintext = String(outputBuffer, 0, outputSize, Charsets.UTF_8)
plaintext
inflateToUtf8(compressedBytes)
} catch (e: Exception) {
// Fallback: пробуем SHA1 для обратной совместимости со старыми сообщениями
try {
@@ -1052,20 +1044,44 @@ object MessageCrypto {
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(keyBytesSha1, "AES"), IvParameterSpec(iv))
val decompressed = cipher.doFinal(ciphertext)
val compressedBytes = cipher.doFinal(ciphertext)
val inflater = java.util.zip.Inflater()
inflater.setInput(decompressed)
val outputBuffer = ByteArray(decompressed.size * 10)
val outputSize = inflater.inflate(outputBuffer)
inflater.end()
String(outputBuffer, 0, outputSize, Charsets.UTF_8)
inflateToUtf8(compressedBytes)
} catch (e2: Exception) {
// Return as-is, might be plain JSON
encryptedBlob
}
}
}
private fun inflateToUtf8(compressedBytes: ByteArray): String {
val inflater = java.util.zip.Inflater()
return try {
inflater.setInput(compressedBytes)
val output = java.io.ByteArrayOutputStream()
val buffer = ByteArray(8 * 1024)
while (!inflater.finished()) {
val count = inflater.inflate(buffer)
if (count > 0) {
output.write(buffer, 0, count)
continue
}
if (inflater.needsInput()) {
break
}
if (inflater.needsDictionary()) {
throw java.util.zip.DataFormatException("Inflater requires dictionary")
}
throw java.util.zip.DataFormatException("Inflater stalled")
}
if (!inflater.finished()) {
throw java.util.zip.DataFormatException("Inflater did not finish")
}
String(output.toByteArray(), Charsets.UTF_8)
} finally {
inflater.end()
}
}
}
// Extension functions для конвертации