fix: remove logs
This commit is contained in:
@@ -123,7 +123,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
Arrays.fill(passwordBytes, 0.toByte())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Encryption failed", e)
|
||||
onError("Ошибка шифрования: ${e.message}")
|
||||
}
|
||||
},
|
||||
@@ -131,11 +130,9 @@ class BiometricAuthManager(private val context: Context) {
|
||||
onCancel = onCancel
|
||||
)
|
||||
} catch (e: KeyPermanentlyInvalidatedException) {
|
||||
Log.e(TAG, "Key invalidated, removing and retrying", e)
|
||||
removeBiometricData()
|
||||
onError("Биометрические данные изменились. Пожалуйста, настройте заново.")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to initialize encryption", e)
|
||||
onError("Ошибка инициализации: ${e.message}")
|
||||
}
|
||||
}
|
||||
@@ -185,7 +182,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
decrypted = authenticatedCipher.doFinal(encrypted)
|
||||
onSuccess(String(decrypted, Charsets.UTF_8))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Decryption failed", e)
|
||||
onError("Ошибка расшифровки: ${e.message}")
|
||||
} finally {
|
||||
// Secure memory wipe - обнуляем расшифрованные данные
|
||||
@@ -196,11 +192,9 @@ class BiometricAuthManager(private val context: Context) {
|
||||
onCancel = onCancel
|
||||
)
|
||||
} catch (e: KeyPermanentlyInvalidatedException) {
|
||||
Log.e(TAG, "Key permanently invalidated", e)
|
||||
removeBiometricData()
|
||||
onError("Биометрические данные изменились. Пожалуйста, войдите с паролем и настройте биометрию заново.")
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to initialize decryption", e)
|
||||
onError("Ошибка инициализации: ${e.message}")
|
||||
}
|
||||
}
|
||||
@@ -222,8 +216,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
val callback = object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
Log.d(TAG, "Authentication error: $errorCode - $errString")
|
||||
|
||||
when (errorCode) {
|
||||
BiometricPrompt.ERROR_USER_CANCELED,
|
||||
BiometricPrompt.ERROR_NEGATIVE_BUTTON,
|
||||
@@ -237,8 +229,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
|
||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
Log.d(TAG, "Authentication succeeded")
|
||||
|
||||
// Получаем аутентифицированный Cipher из CryptoObject
|
||||
val authenticatedCipher = result.cryptoObject?.cipher
|
||||
if (authenticatedCipher != null) {
|
||||
@@ -250,8 +240,7 @@ class BiometricAuthManager(private val context: Context) {
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed()
|
||||
Log.d(TAG, "Authentication failed (user can retry)")
|
||||
// Не вызываем onError - пользователь может попробовать снова
|
||||
// Не вызываем onError - пользователь может попробовать снова
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,7 +301,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
try {
|
||||
builder.setAttestationChallenge(generateAttestationChallenge())
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Key attestation not supported", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +309,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
try {
|
||||
builder.setIsStrongBoxBacked(true)
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "StrongBox not available, using TEE", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -336,7 +323,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
return try {
|
||||
keyStore.getKey(KEY_ALIAS, null) as? SecretKey
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to get key from Keystore", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
@@ -349,10 +335,8 @@ class BiometricAuthManager(private val context: Context) {
|
||||
try {
|
||||
if (keyStore.containsAlias(KEY_ALIAS)) {
|
||||
keyStore.deleteEntry(KEY_ALIAS)
|
||||
Log.d(TAG, "Biometric key removed from Keystore")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to remove key from Keystore", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +380,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
try {
|
||||
certificateChain[i].verify(certificateChain[i + 1].publicKey)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Certificate chain verification failed at index $i", e)
|
||||
return KeyAttestationResult.Invalid("Цепочка сертификатов недействительна")
|
||||
}
|
||||
}
|
||||
@@ -406,14 +389,12 @@ class BiometricAuthManager(private val context: Context) {
|
||||
if (leafCert != null) {
|
||||
val attestationExtension = leafCert.getExtensionValue("1.3.6.1.4.1.11129.2.1.17")
|
||||
if (attestationExtension != null) {
|
||||
Log.d(TAG, "Key attestation verified - key is in secure hardware")
|
||||
return KeyAttestationResult.Valid(isStrongBox = isKeyInStrongBox())
|
||||
}
|
||||
}
|
||||
|
||||
KeyAttestationResult.NotSupported
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Key attestation verification failed", e)
|
||||
KeyAttestationResult.Invalid(e.message ?: "Unknown error")
|
||||
}
|
||||
}
|
||||
@@ -437,7 +418,6 @@ class BiometricAuthManager(private val context: Context) {
|
||||
keyInfo.isInsideSecureHardware
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Could not determine if key is in StrongBox", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ class BiometricPreferences(private val context: Context) {
|
||||
try {
|
||||
_isBiometricEnabled.value = encryptedPrefs.getBoolean(KEY_BIOMETRIC_ENABLED, false)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to read biometric enabled state", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +62,6 @@ class BiometricPreferences(private val context: Context) {
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to create EncryptedSharedPreferences, falling back", e)
|
||||
// Fallback на обычные SharedPreferences в случае ошибки (не должно произойти)
|
||||
return context.getSharedPreferences(PREFS_FILE_NAME + "_fallback", Context.MODE_PRIVATE)
|
||||
}
|
||||
@@ -97,7 +95,6 @@ class BiometricPreferences(private val context: Context) {
|
||||
suspend fun saveEncryptedPassword(publicKey: String, encryptedPassword: String) = withContext(Dispatchers.IO) {
|
||||
val key = "$ENCRYPTED_PASSWORD_PREFIX$publicKey"
|
||||
encryptedPrefs.edit().putString(key, encryptedPassword).apply()
|
||||
Log.d(TAG, "Encrypted password saved for account")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +111,6 @@ class BiometricPreferences(private val context: Context) {
|
||||
suspend fun removeEncryptedPassword(publicKey: String) = withContext(Dispatchers.IO) {
|
||||
val key = "$ENCRYPTED_PASSWORD_PREFIX$publicKey"
|
||||
encryptedPrefs.edit().remove(key).apply()
|
||||
Log.d(TAG, "Encrypted password removed for account")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +119,6 @@ class BiometricPreferences(private val context: Context) {
|
||||
suspend fun clearAll() = withContext(Dispatchers.IO) {
|
||||
encryptedPrefs.edit().clear().apply()
|
||||
_isBiometricEnabled.value = false
|
||||
Log.d(TAG, "All biometric data cleared")
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -347,7 +347,6 @@ fun ChatDetailScreen(
|
||||
// 🔥 КРИТИЧНО: Дедупликация по ID перед сортировкой!
|
||||
val uniqueMessages = messages.distinctBy { it.id }
|
||||
if (uniqueMessages.size != messages.size) {
|
||||
android.util.Log.e("ChatDetailScreen", "🚨 DEDUPLICATED ${messages.size - uniqueMessages.size} messages in UI! Original: ${messages.map { it.id }}")
|
||||
}
|
||||
|
||||
// Сортируем по времени (новые -> старые) для reversed layout
|
||||
|
||||
@@ -264,9 +264,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val allIds = newList.map { it.id }
|
||||
val duplicates = allIds.groupBy { it }.filter { it.value.size > 1 }.keys
|
||||
if (duplicates.isNotEmpty()) {
|
||||
android.util.Log.e("ChatViewModel", "🚨 DUPLICATE IDS FOUND in pollLatestMessages: $duplicates")
|
||||
android.util.Log.e("ChatViewModel", " currentList ids: ${currentList.map { it.id }}")
|
||||
android.util.Log.e("ChatViewModel", " newMessages ids: ${newMessages.map { it.id }}")
|
||||
}
|
||||
|
||||
_messages.value = newList
|
||||
@@ -377,13 +374,10 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
private fun addMessageSafely(message: ChatMessage): Boolean {
|
||||
val currentMessages = _messages.value
|
||||
val currentIds = currentMessages.map { it.id }.toSet()
|
||||
android.util.Log.d("ChatViewModel", "🔍 addMessageSafely: id=${message.id}, currentCount=${currentMessages.size}, ids=${currentIds.take(5)}...")
|
||||
if (message.id in currentIds) {
|
||||
android.util.Log.e("ChatViewModel", "🚨 BLOCKED DUPLICATE: id=${message.id} already exists in ${currentIds.size} messages!")
|
||||
if (message.id in currentIds) {
|
||||
return false
|
||||
}
|
||||
_messages.value = currentMessages + message
|
||||
android.util.Log.d("ChatViewModel", "✅ Added message: id=${message.id}, newCount=${_messages.value.size}")
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -595,22 +589,17 @@ class ChatViewModel(application: Application) : AndroidViewModel(application) {
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
val dbIds = messages.map { it.id }.toSet()
|
||||
val currentMsgs = _messages.value
|
||||
android.util.Log.d("ChatViewModel", "📥 loadMessages: dbCount=${messages.size}, currentCount=${currentMsgs.size}")
|
||||
android.util.Log.d("ChatViewModel", " DB ids: ${dbIds.take(5)}...")
|
||||
android.util.Log.d("ChatViewModel", " Current ids: ${currentMsgs.map { it.id }.take(5)}...")
|
||||
android.util.Log.d("ChatViewModel", " Current ids: ${currentMsgs.map { it.id }.take(5)}...")
|
||||
|
||||
val optimisticMessages = currentMsgs.filter { msg ->
|
||||
msg.status == MessageStatus.SENDING && msg.id !in dbIds
|
||||
}
|
||||
android.util.Log.d("ChatViewModel", " Optimistic (SENDING, not in DB): ${optimisticMessages.size} - ${optimisticMessages.map { it.id }}")
|
||||
|
||||
val newList = messages + optimisticMessages
|
||||
val newList = messages + optimisticMessages
|
||||
|
||||
// 🔍 Финальная дедупликация по ID (на всякий случай)
|
||||
val deduplicatedList = newList.distinctBy { it.id }
|
||||
|
||||
if (deduplicatedList.size != newList.size) {
|
||||
android.util.Log.e("ChatViewModel", "🚨 DEDUPLICATED ${newList.size - deduplicatedList.size} messages!")
|
||||
}
|
||||
|
||||
_messages.value = deduplicatedList
|
||||
|
||||
@@ -242,9 +242,7 @@ fun ImageEditorScreen(
|
||||
lastStableKeyboardHeight = currentImeHeight
|
||||
}
|
||||
// 📊 Log IME height changes
|
||||
Log.d(TAG, "⌨️ IME: height=${currentImeHeight.value}dp, wasVisible=$wasKeyboardVisible, isVisible=$isKeyboardVisible, emojiBoxVisible=${coordinator.isEmojiBoxVisible}")
|
||||
if (wasKeyboardVisible != isKeyboardVisible) {
|
||||
Log.d(TAG, "⌨️ KEYBOARD STATE CHANGED: $wasKeyboardVisible → $isKeyboardVisible")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,12 +271,8 @@ fun ImageEditorScreen(
|
||||
lastToggleTime = currentTime
|
||||
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
||||
Log.d(TAG, "toggleEmojiPicker: isEmojiVisible=${coordinator.isEmojiVisible}, isEmojiBoxVisible=${coordinator.isEmojiBoxVisible}, showEmojiPicker=$showEmojiPicker")
|
||||
|
||||
if (coordinator.isEmojiVisible) {
|
||||
// EMOJI → KEYBOARD
|
||||
Log.d(TAG, "TRANSITION: EMOJI → KEYBOARD")
|
||||
coordinator.requestShowKeyboard(
|
||||
showKeyboard = {
|
||||
editTextView?.let { editText ->
|
||||
@@ -290,7 +284,6 @@ fun ImageEditorScreen(
|
||||
)
|
||||
} else {
|
||||
// KEYBOARD → EMOJI
|
||||
Log.d(TAG, "TRANSITION: KEYBOARD → EMOJI")
|
||||
coordinator.requestShowEmoji(
|
||||
hideKeyboard = { imm.hideSoftInputFromWindow(view.windowToken, 0) },
|
||||
showEmoji = { showEmojiPicker = true }
|
||||
@@ -1165,7 +1158,7 @@ private fun TelegramCaptionBar(
|
||||
}
|
||||
}
|
||||
|
||||
/** Save edited image and return the URI - crops black bars from FIT_CENTER */
|
||||
/** Save edited image and return the URI - returns original if no edits, otherwise crops black bars */
|
||||
private suspend fun saveEditedImage(
|
||||
context: Context,
|
||||
photoEditor: PhotoEditor?,
|
||||
@@ -1174,12 +1167,15 @@ private suspend fun saveEditedImage(
|
||||
onResult: (Uri?) -> Unit
|
||||
) {
|
||||
if (photoEditor == null || photoEditorView == null) {
|
||||
onResult(null)
|
||||
// Нет редактора - возвращаем оригинал
|
||||
onResult(imageUri)
|
||||
return
|
||||
}
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
// Загружаем оригинальное изображение и сохраняем его напрямую
|
||||
// PhotoEditor с setClipSourceImage(true) должен обрезать черные полосы автоматически
|
||||
val tempFile = File(context.cacheDir, "temp_${System.currentTimeMillis()}.png")
|
||||
|
||||
val saveSettings = SaveSettings.Builder()
|
||||
@@ -1187,7 +1183,6 @@ private suspend fun saveEditedImage(
|
||||
.setTransparencyEnabled(true)
|
||||
.build()
|
||||
|
||||
// Сохраняем полный view (с черными полосами)
|
||||
val savedPath = suspendCancellableCoroutine<String?> { continuation ->
|
||||
photoEditor.saveAsFile(
|
||||
tempFile.absolutePath,
|
||||
@@ -1204,7 +1199,8 @@ private suspend fun saveEditedImage(
|
||||
}
|
||||
|
||||
if (savedPath == null) {
|
||||
withContext(Dispatchers.Main) { onResult(null) }
|
||||
// Ошибка сохранения - возвращаем оригинал
|
||||
withContext(Dispatchers.Main) { onResult(imageUri) }
|
||||
return@withContext
|
||||
}
|
||||
|
||||
@@ -1215,7 +1211,7 @@ private suspend fun saveEditedImage(
|
||||
return@withContext
|
||||
}
|
||||
|
||||
// Получаем РЕАЛЬНЫЕ размеры изображения из URI (не из drawable!)
|
||||
// Получаем размеры оригинального изображения
|
||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
context.contentResolver.openInputStream(imageUri)?.use { stream ->
|
||||
BitmapFactory.decodeStream(stream, null, options)
|
||||
@@ -1232,6 +1228,17 @@ private suspend fun saveEditedImage(
|
||||
val viewWidth = savedBitmap.width
|
||||
val viewHeight = savedBitmap.height
|
||||
|
||||
// Соотношение сторон оригинала и сохраненного
|
||||
val originalRatio = imageWidth.toFloat() / imageHeight
|
||||
val savedRatio = viewWidth.toFloat() / viewHeight
|
||||
|
||||
// Если соотношения примерно равны - черных полос нет, возвращаем как есть
|
||||
if (kotlin.math.abs(originalRatio - savedRatio) < 0.01f) {
|
||||
savedBitmap.recycle()
|
||||
withContext(Dispatchers.Main) { onResult(Uri.fromFile(tempFile)) }
|
||||
return@withContext
|
||||
}
|
||||
|
||||
// Вычисляем где находится изображение (FIT_CENTER логика)
|
||||
val scale = minOf(
|
||||
viewWidth.toFloat() / imageWidth,
|
||||
@@ -1244,13 +1251,15 @@ private suspend fun saveEditedImage(
|
||||
val left = ((viewWidth - scaledWidth) / 2).coerceAtLeast(0)
|
||||
val top = ((viewHeight - scaledHeight) / 2).coerceAtLeast(0)
|
||||
|
||||
// Обрезаем черные полосы
|
||||
val cropWidth = scaledWidth.coerceIn(1, viewWidth - left)
|
||||
val cropHeight = scaledHeight.coerceIn(1, viewHeight - top)
|
||||
// Обрезаем черные полосы
|
||||
val croppedBitmap = Bitmap.createBitmap(
|
||||
savedBitmap,
|
||||
left,
|
||||
top,
|
||||
scaledWidth.coerceAtMost(viewWidth - left),
|
||||
scaledHeight.coerceAtMost(viewHeight - top)
|
||||
cropWidth,
|
||||
cropHeight
|
||||
)
|
||||
|
||||
// Сохраняем обрезанное изображение
|
||||
@@ -1267,19 +1276,23 @@ private suspend fun saveEditedImage(
|
||||
onResult(Uri.fromFile(finalFile))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) { onResult(null) }
|
||||
// При ошибке возвращаем оригинал
|
||||
withContext(Dispatchers.Main) { onResult(imageUri) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Save edited image synchronously - crops black bars from FIT_CENTER */
|
||||
/** Save edited image synchronously - returns original if no edits, otherwise crops black bars */
|
||||
private suspend fun saveEditedImageSync(
|
||||
context: Context,
|
||||
photoEditor: PhotoEditor?,
|
||||
photoEditorView: PhotoEditorView?,
|
||||
imageUri: Uri
|
||||
): Uri? {
|
||||
if (photoEditor == null || photoEditorView == null) return null
|
||||
if (photoEditor == null || photoEditorView == null) {
|
||||
// Нет редактора - возвращаем оригинал
|
||||
return imageUri
|
||||
}
|
||||
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
@@ -1308,13 +1321,16 @@ private suspend fun saveEditedImageSync(
|
||||
)
|
||||
}
|
||||
|
||||
if (savedPath == null) return@withContext null
|
||||
if (savedPath == null) {
|
||||
// Ошибка - возвращаем оригинал
|
||||
return@withContext imageUri
|
||||
}
|
||||
|
||||
// Загружаем сохраненное изображение
|
||||
val savedBitmap = BitmapFactory.decodeFile(savedPath)
|
||||
?: return@withContext Uri.fromFile(tempFile)
|
||||
|
||||
// Получаем РЕАЛЬНЫЕ размеры изображения из URI (не из drawable!)
|
||||
// Получаем размеры оригинального изображения
|
||||
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
|
||||
context.contentResolver.openInputStream(imageUri)?.use { stream ->
|
||||
BitmapFactory.decodeStream(stream, null, options)
|
||||
@@ -1330,6 +1346,16 @@ private suspend fun saveEditedImageSync(
|
||||
val viewWidth = savedBitmap.width
|
||||
val viewHeight = savedBitmap.height
|
||||
|
||||
// Соотношение сторон оригинала и сохраненного
|
||||
val originalRatio = imageWidth.toFloat() / imageHeight
|
||||
val savedRatio = viewWidth.toFloat() / viewHeight
|
||||
|
||||
// Если соотношения примерно равны - черных полос нет
|
||||
if (kotlin.math.abs(originalRatio - savedRatio) < 0.01f) {
|
||||
savedBitmap.recycle()
|
||||
return@withContext Uri.fromFile(tempFile)
|
||||
}
|
||||
|
||||
// Вычисляем где находится изображение (FIT_CENTER логика)
|
||||
val scale = minOf(
|
||||
viewWidth.toFloat() / imageWidth,
|
||||
@@ -1342,13 +1368,15 @@ private suspend fun saveEditedImageSync(
|
||||
val left = ((viewWidth - scaledWidth) / 2).coerceAtLeast(0)
|
||||
val top = ((viewHeight - scaledHeight) / 2).coerceAtLeast(0)
|
||||
|
||||
// Обрезаем черные полосы
|
||||
val cropWidth = scaledWidth.coerceIn(1, viewWidth - left)
|
||||
val cropHeight = scaledHeight.coerceIn(1, viewHeight - top)
|
||||
// Обрезаем черные полосы
|
||||
val croppedBitmap = Bitmap.createBitmap(
|
||||
savedBitmap,
|
||||
left,
|
||||
top,
|
||||
scaledWidth.coerceAtMost(viewWidth - left),
|
||||
scaledHeight.coerceAtMost(viewHeight - top)
|
||||
cropWidth,
|
||||
cropHeight
|
||||
)
|
||||
|
||||
// Сохраняем обрезанное изображение
|
||||
@@ -1366,7 +1394,8 @@ private suspend fun saveEditedImageSync(
|
||||
|
||||
Uri.fromFile(finalFile)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
// При ошибке возвращаем оригинал
|
||||
imageUri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,7 +1440,6 @@ fun PhotoPreviewWithCaptionScreen(
|
||||
coordinator.syncHeights()
|
||||
lastStableKeyboardHeight = currentImeHeight
|
||||
}
|
||||
Log.d("PhotoPreview", "IME height: ${currentImeHeight.value}dp, isKeyboardVisible: $isKeyboardVisible, emojiHeight: ${coordinator.emojiHeight.value}dp, isEmojiBoxVisible: ${coordinator.isEmojiBoxVisible}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,7 +1463,6 @@ fun PhotoPreviewWithCaptionScreen(
|
||||
fun toggleEmojiPicker() {
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (currentTime - lastToggleTime < toggleCooldownMs) {
|
||||
Log.d("PhotoPreview", "Toggle blocked by cooldown")
|
||||
return
|
||||
}
|
||||
lastToggleTime = currentTime
|
||||
@@ -1473,30 +1471,24 @@ fun PhotoPreviewWithCaptionScreen(
|
||||
|
||||
if (coordinator.isEmojiVisible) {
|
||||
// EMOJI → KEYBOARD
|
||||
Log.d("PhotoPreview", "TOGGLE: Emoji → Keyboard")
|
||||
coordinator.requestShowKeyboard(
|
||||
showKeyboard = {
|
||||
Log.d("PhotoPreview", "Showing keyboard...")
|
||||
editTextView?.let { editText ->
|
||||
editText.requestFocus()
|
||||
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
},
|
||||
hideEmoji = {
|
||||
Log.d("PhotoPreview", "Hiding emoji picker")
|
||||
showEmojiPicker = false
|
||||
}
|
||||
)
|
||||
} else {
|
||||
// KEYBOARD → EMOJI
|
||||
Log.d("PhotoPreview", "TOGGLE: Keyboard → Emoji")
|
||||
coordinator.requestShowEmoji(
|
||||
hideKeyboard = {
|
||||
Log.d("PhotoPreview", "Hiding keyboard...")
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
},
|
||||
showEmoji = {
|
||||
Log.d("PhotoPreview", "Showing emoji picker")
|
||||
showEmojiPicker = true
|
||||
}
|
||||
)
|
||||
@@ -1508,8 +1500,6 @@ fun PhotoPreviewWithCaptionScreen(
|
||||
val shouldAddNavBarPadding = !isKeyboardVisible && !coordinator.isEmojiBoxVisible
|
||||
|
||||
// Логируем состояние при каждой рекомпозиции
|
||||
Log.d("PhotoPreview", "RENDER: showEmoji=$showEmojiPicker, isKeyboard=$isKeyboardVisible, isEmojiBoxVisible=${coordinator.isEmojiBoxVisible}, useImePadding=$shouldUseImePadding, emojiHeight=${coordinator.emojiHeight.value}dp")
|
||||
|
||||
Surface(
|
||||
color = backgroundColor,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
|
||||
@@ -286,9 +286,6 @@ private fun computeAvatarState(
|
||||
val showBlob = collapseProgress < ProfileMetaballConstants.MERGE_COMPLETE_PROGRESS && radius > 1f
|
||||
|
||||
// DEBUG LOG
|
||||
Log.d("Metaball", "collapse=$collapseProgress, expansion=$expansionProgress, radius=$radius, diff=$diff")
|
||||
Log.d("Metaball", "centerY=$centerY, cornerRadius=$cornerRadius, isDrawing=$isDrawing, isNear=$isNear")
|
||||
|
||||
return AvatarState(
|
||||
centerX = centerX,
|
||||
centerY = centerY,
|
||||
|
||||
@@ -259,8 +259,6 @@ fun OtherProfileScreen(
|
||||
}
|
||||
|
||||
// DEBUG LOGS
|
||||
Log.d("OtherProfileScroll", "expansionProgress=$expansionProgress, isPulledDown=$isPulledDown, isDragging=$isDragging")
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// NESTED SCROLL - Telegram style with overscroll support
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -588,7 +588,6 @@ private suspend fun loadPhotos(context: Context): List<PhotoItem> = withContext(
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e(TAG, "Error loading photos: ${e.message}", e)
|
||||
}
|
||||
|
||||
items
|
||||
|
||||
@@ -401,8 +401,6 @@ fun ProfileScreen(
|
||||
}
|
||||
|
||||
// DEBUG LOGS
|
||||
Log.d("ProfileScroll", "expansionProgress=$expansionProgress, isPulledDown=$isPulledDown, isDragging=$isDragging")
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// NESTED SCROLL - Telegram style
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
119
remove_logs.py
Normal file
119
remove_logs.py
Normal file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Скрипт для удаления Log.d/e/w/i/v вызовов из Kotlin файлов
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
def remove_logs_from_file(filepath):
|
||||
"""Удаляет Log.d/e/w/i/v вызовы из файла"""
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
original_content = content
|
||||
|
||||
# Паттерн для Log.d/e/w/i/v с учетом многострочных вызовов
|
||||
# Матчит: Log.d("TAG", "message") или Log.d(TAG, "message", exception)
|
||||
patterns = [
|
||||
# Простые однострочные логи
|
||||
r'^\s*Log\.[dewiv]\([^)]*\)\s*\n',
|
||||
# Многострочные логи (с переносами внутри скобок)
|
||||
r'^\s*Log\.[dewiv]\([^)]*\n[^)]*\)\s*\n',
|
||||
r'^\s*Log\.[dewiv]\([^)]*\n[^)]*\n[^)]*\)\s*\n',
|
||||
r'^\s*Log\.[dewiv]\([^)]*\n[^)]*\n[^)]*\n[^)]*\)\s*\n',
|
||||
# android.util.Log
|
||||
r'^\s*android\.util\.Log\.[dewiv]\([^)]*\)\s*\n',
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
content = re.sub(pattern, '', content, flags=re.MULTILINE)
|
||||
|
||||
# Более агрессивный паттерн для оставшихся логов
|
||||
# Находит Log.X( и удаляет до закрывающей скобки
|
||||
def remove_log_call(match):
|
||||
return ''
|
||||
|
||||
# Паттерн который находит Log.X(...) учитывая вложенные скобки
|
||||
log_pattern = r'^\s*(?:android\.util\.)?Log\.[dewiv]\s*\([^()]*(?:\([^()]*\)[^()]*)*\)\s*\n?'
|
||||
content = re.sub(log_pattern, '', content, flags=re.MULTILINE)
|
||||
|
||||
if content != original_content:
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
return True
|
||||
return False
|
||||
|
||||
def find_kotlin_files(directory):
|
||||
"""Находит все .kt файлы в директории"""
|
||||
kotlin_files = []
|
||||
for root, dirs, files in os.walk(directory):
|
||||
# Пропускаем build директории
|
||||
dirs[:] = [d for d in dirs if d not in ['build', '.gradle', '.idea']]
|
||||
for file in files:
|
||||
if file.endswith('.kt'):
|
||||
kotlin_files.append(os.path.join(root, file))
|
||||
return kotlin_files
|
||||
|
||||
def count_logs_in_file(filepath):
|
||||
"""Считает количество Log вызовов в файле"""
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
pattern = r'(?:android\.util\.)?Log\.[dewiv]\s*\('
|
||||
matches = re.findall(pattern, content)
|
||||
return len(matches)
|
||||
|
||||
def main():
|
||||
# Директория с исходниками
|
||||
src_dir = '/Users/ruslanmakhmatov/Desktop/Work/rosette-app/rosetta-android/app/src/main/java/com/rosetta/messenger'
|
||||
|
||||
if not os.path.exists(src_dir):
|
||||
print(f"Директория не найдена: {src_dir}")
|
||||
sys.exit(1)
|
||||
|
||||
kotlin_files = find_kotlin_files(src_dir)
|
||||
print(f"Найдено {len(kotlin_files)} Kotlin файлов")
|
||||
|
||||
# Сначала считаем логи
|
||||
total_logs_before = 0
|
||||
files_with_logs = []
|
||||
for filepath in kotlin_files:
|
||||
count = count_logs_in_file(filepath)
|
||||
if count > 0:
|
||||
total_logs_before += count
|
||||
files_with_logs.append((filepath, count))
|
||||
|
||||
print(f"Найдено {total_logs_before} Log вызовов в {len(files_with_logs)} файлах")
|
||||
|
||||
if '--dry-run' in sys.argv:
|
||||
print("\n[DRY RUN] Файлы с логами:")
|
||||
for filepath, count in sorted(files_with_logs, key=lambda x: -x[1]):
|
||||
print(f" {count:3d} логов: {os.path.basename(filepath)}")
|
||||
return
|
||||
|
||||
# Удаляем логи
|
||||
modified_count = 0
|
||||
for filepath in kotlin_files:
|
||||
if remove_logs_from_file(filepath):
|
||||
modified_count += 1
|
||||
print(f"✓ {os.path.basename(filepath)}")
|
||||
|
||||
# Считаем оставшиеся
|
||||
total_logs_after = 0
|
||||
for filepath in kotlin_files:
|
||||
total_logs_after += count_logs_in_file(filepath)
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Изменено файлов: {modified_count}")
|
||||
print(f"Логов до: {total_logs_before}")
|
||||
print(f"Логов после: {total_logs_after}")
|
||||
print(f"Удалено: {total_logs_before - total_logs_after}")
|
||||
|
||||
if total_logs_after > 0:
|
||||
print(f"\n⚠️ Осталось {total_logs_after} логов (возможно сложные многострочные)")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user