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

@@ -27,9 +27,13 @@ class BiometricPreferences(private val context: Context) {
private const val PREFS_FILE_NAME = "rosetta_secure_biometric_prefs"
private const val KEY_BIOMETRIC_ENABLED = "biometric_enabled"
private const val ENCRYPTED_PASSWORD_PREFIX = "encrypted_password_"
// Shared between all BiometricPreferences instances so UI in different screens
// receives updates immediately (ProfileScreen <-> BiometricEnableScreen).
private val biometricEnabledState = MutableStateFlow(false)
}
private val _isBiometricEnabled = MutableStateFlow(false)
private val appContext = context.applicationContext
private val _isBiometricEnabled = biometricEnabledState
private val encryptedPrefs: SharedPreferences by lazy {
createEncryptedPreferences()
@@ -49,13 +53,13 @@ class BiometricPreferences(private val context: Context) {
private fun createEncryptedPreferences(): SharedPreferences {
try {
// Создаем MasterKey с максимальной защитой
val masterKey = MasterKey.Builder(context)
val masterKey = MasterKey.Builder(appContext)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
.setUserAuthenticationRequired(false) // Биометрия проверяется отдельно в BiometricAuthManager
.build()
return EncryptedSharedPreferences.create(
context,
appContext,
PREFS_FILE_NAME,
masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
@@ -63,7 +67,7 @@ class BiometricPreferences(private val context: Context) {
)
} catch (e: Exception) {
// Fallback на обычные SharedPreferences в случае ошибки (не должно произойти)
return context.getSharedPreferences(PREFS_FILE_NAME + "_fallback", Context.MODE_PRIVATE)
return appContext.getSharedPreferences(PREFS_FILE_NAME + "_fallback", Context.MODE_PRIVATE)
}
}
@@ -76,16 +80,22 @@ class BiometricPreferences(private val context: Context) {
* Включить биометрическую аутентификацию
*/
suspend fun enableBiometric() = withContext(Dispatchers.IO) {
encryptedPrefs.edit().putBoolean(KEY_BIOMETRIC_ENABLED, true).apply()
_isBiometricEnabled.value = true
val success = encryptedPrefs.edit().putBoolean(KEY_BIOMETRIC_ENABLED, true).commit()
if (!success) {
Log.w(TAG, "Failed to persist biometric enabled state")
}
_isBiometricEnabled.value = encryptedPrefs.getBoolean(KEY_BIOMETRIC_ENABLED, false)
}
/**
* Отключить биометрическую аутентификацию
*/
suspend fun disableBiometric() = withContext(Dispatchers.IO) {
encryptedPrefs.edit().putBoolean(KEY_BIOMETRIC_ENABLED, false).apply()
_isBiometricEnabled.value = false
val success = encryptedPrefs.edit().putBoolean(KEY_BIOMETRIC_ENABLED, false).commit()
if (!success) {
Log.w(TAG, "Failed to persist biometric disabled state")
}
_isBiometricEnabled.value = encryptedPrefs.getBoolean(KEY_BIOMETRIC_ENABLED, false)
}
/**
@@ -117,8 +127,11 @@ class BiometricPreferences(private val context: Context) {
* Удалить все биометрические данные
*/
suspend fun clearAll() = withContext(Dispatchers.IO) {
encryptedPrefs.edit().clear().apply()
_isBiometricEnabled.value = false
val success = encryptedPrefs.edit().clear().commit()
if (!success) {
Log.w(TAG, "Failed to clear biometric preferences")
}
_isBiometricEnabled.value = encryptedPrefs.getBoolean(KEY_BIOMETRIC_ENABLED, false)
}
/**