diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt index b9c0c43995..3611006734 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/database/DatabaseView.kt @@ -62,6 +62,7 @@ fun DatabaseView( importArchiveAlert(m, context, uri, progressIndicator) } } + val appFilesCountAndSize = remember { mutableStateOf(directoryFileCountAndSize(getAppFilesDirectory(context))) } LaunchedEffect(m.chatRunning) { runChat.value = m.chatRunning.value ?: true } @@ -78,10 +79,12 @@ fun DatabaseView( chatArchiveName, chatArchiveTime, chatLastStart, + appFilesCountAndSize, startChat = { startChat(m, runChat, chatLastStart, m.chatDbChanged) }, stopChatAlert = { stopChatAlert(m, runChat, context) }, exportArchive = { exportArchive(context, m, progressIndicator, chatArchiveName, chatArchiveTime, chatArchiveFile, saveArchiveLauncher) }, deleteChatAlert = { deleteChatAlert(m, progressIndicator) }, + deleteAppFilesAndMedia = { deleteFilesAndMediaAlert(context, appFilesCountAndSize) }, showSettingsModal ) if (progressIndicator.value) { @@ -112,10 +115,12 @@ fun DatabaseLayout( chatArchiveName: MutableState, chatArchiveTime: MutableState, chatLastStart: MutableState, + appFilesCountAndSize: MutableState>, startChat: () -> Unit, stopChatAlert: () -> Unit, exportArchive: () -> Unit, deleteChatAlert: () -> Unit, + deleteAppFilesAndMedia: () -> Unit, showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit) ) { val stopped = !runChat @@ -196,6 +201,28 @@ fun DatabaseLayout( stringResource(R.string.stop_chat_to_enable_database_actions) } ) + SectionSpacer() + + SectionView(stringResource(R.string.files_section)) { + val deleteFilesDisabled = operationsDisabled || appFilesCountAndSize.value.first == 0 + SectionItemView( + deleteAppFilesAndMedia, + disabled = deleteFilesDisabled + ) { + Text( + stringResource(R.string.delete_files_and_media), + color = if (deleteFilesDisabled) HighOrLowlight else Color.Red + ) + } + } + val (count, size) = appFilesCountAndSize.value + SectionTextFooter( + if (count == 0) { + stringResource(R.string.no_received_app_files) + } else { + String.format(stringResource(R.string.total_files_count_and_size), count, formatBytes(size)) + } + ) } } @@ -502,6 +529,21 @@ private fun deleteChat(m: ChatModel, progressIndicator: MutableState) { } } +private fun deleteFilesAndMediaAlert(context: Context, appFilesCountAndSize: MutableState>) { + AlertManager.shared.showAlertDialog( + title = generalGetString(R.string.delete_files_and_media_question), + text = generalGetString(R.string.delete_files_and_media_desc), + confirmText = generalGetString(R.string.delete_verb), + onConfirm = { deleteFiles(appFilesCountAndSize, context) }, + destructive = true + ) +} + +private fun deleteFiles(appFilesCountAndSize: MutableState>, context: Context) { + deleteAppFiles(context) + appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory(context)) +} + private fun operationEnded(m: ChatModel, progressIndicator: MutableState, alert: () -> Unit) { m.chatDbChanged.value = true progressIndicator.value = false @@ -527,10 +569,12 @@ fun PreviewDatabaseLayout() { chatArchiveName = remember { mutableStateOf("dummy_archive") }, chatArchiveTime = remember { mutableStateOf(Clock.System.now()) }, chatLastStart = remember { mutableStateOf(Clock.System.now()) }, + appFilesCountAndSize = remember { mutableStateOf(0 to 0L) }, startChat = {}, stopChatAlert = {}, exportArchive = {}, deleteChatAlert = {}, + deleteAppFilesAndMedia = {}, showSettingsModal = { {} } ) } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt index 12af59fc89..374355582e 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Util.kt @@ -24,8 +24,7 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.* import androidx.core.content.FileProvider import androidx.core.text.HtmlCompat -import chat.simplex.app.BuildConfig -import chat.simplex.app.SimplexApp +import chat.simplex.app.* import chat.simplex.app.model.CIFile import kotlinx.coroutines.* import java.io.* @@ -405,6 +404,31 @@ fun removeFile(context: Context, fileName: String): Boolean { return fileDeleted } +fun deleteAppFiles(context: Context) { + val dir = File(getAppFilesDirectory(context)) + try { + dir.list()?.forEach { + removeFile(context, it) + } + } catch (e: java.lang.Exception) { + Log.e(TAG, "Util deleteAppFiles error: ${e.stackTraceToString()}") + } +} + +fun directoryFileCountAndSize(dir: String): Pair { // count, size in bytes + var fileCount = 0 + var bytes = 0L + try { + File(dir).listFiles()?.forEach { + fileCount++ + bytes += it.length() + } + } catch (e: java.lang.Exception) { + Log.e(TAG, "Util directoryFileCountAndSize error: ${e.stackTraceToString()}") + } + return fileCount to bytes +} + fun ByteArray.toBase64String() = Base64.encodeToString(this, Base64.DEFAULT) fun String.toByteArrayFromBase64() = Base64.decode(this, Base64.DEFAULT) diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index e9e8f976a9..1879d9c5b2 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -556,6 +556,12 @@ Перезапустите приложение, чтобы создать новый профиль. Используйте самую последнюю версию архива чата и ТОЛЬКО на одном устройстве, иначе вы можете перестать получать сообщения от некоторых контактов. Остановите чат, чтобы разблокировать операции с архивом чата. + ФАЙЛЫ + Удалить файлы и медиа + Удалить файлы и медиа? + Это действие нельзя отменить — все полученные и отправленные файлы будут удалены. Изображения останутся в низком разрешении. + Нет полученных или отправленных файлов + %d файл(ов) общим размером %s Сохранить пароль в Keystore diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 88bebbf341..b415efd011 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -557,6 +557,12 @@ Restart the app to create a new chat profile. You must use the most recent version of your chat database on one device ONLY, otherwise you may stop receiving the messages from some contacts. Stop chat to enable database actions. + FILES + Delete files \& media + Delete files and media? + This action cannot be undone - all received and sent files and media will be deleted. Low resolution pictures will remain. + No received or sent files + %d file(s) with total size of %s Save passphrase in Keystore