From 56ce7c5aa4dff8d1a30fba070d5f7bc442e5f6ce Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 12:32:06 +1000 Subject: [PATCH 01/30] Added settings migrating section --- app/src/main/res/layout/activity_settings.xml | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 99dfaa9b..154f95f9 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -367,6 +367,47 @@ android:text="@string/password_protect_whole_app" /> + + + + + + + + + + + + + + + + From 5363af1071adaee9a4a1947b5e62fa8c9250d45c Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 12:38:31 +1000 Subject: [PATCH 02/30] Added serialization --- app/build.gradle | 12 ++++++++---- .../smsmessenger/models/MmsAddress.kt | 2 ++ .../smsmessenger/models/MmsBackup.kt | 2 ++ .../simplemobiletools/smsmessenger/models/MmsPart.kt | 2 ++ .../smsmessenger/models/SmsBackup.kt | 2 ++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 7f9727a4..19659240 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,10 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-android-extensions' + id 'kotlin-kapt' + id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version" +} def keystorePropertiesFile = rootProject.file("keystore.properties") def keystoreProperties = new Properties() @@ -71,6 +74,7 @@ dependencies { implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.googlecode.ez-vcard:ez-vcard:0.11.3' implementation 'androidx.lifecycle:lifecycle-process:2.5.1' + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1" kapt "androidx.room:room-compiler:2.5.1" implementation "androidx.room:room-runtime:2.5.1" diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsAddress.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsAddress.kt index 07148905..821047cc 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsAddress.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsAddress.kt @@ -4,7 +4,9 @@ import android.content.ContentValues import android.provider.Telephony import androidx.core.content.contentValuesOf import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable +@Serializable data class MmsAddress( @SerializedName("address") val address: String, diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt index e8957d93..c2c2c93c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt @@ -4,7 +4,9 @@ import android.content.ContentValues import android.provider.Telephony import androidx.core.content.contentValuesOf import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable +@Serializable data class MmsBackup( @SerializedName("creator") val creator: String?, diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsPart.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsPart.kt index ac5d53d1..8edde56e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsPart.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsPart.kt @@ -4,7 +4,9 @@ import android.content.ContentValues import android.provider.Telephony import androidx.core.content.contentValuesOf import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable +@Serializable data class MmsPart( @SerializedName("cd") val contentDisposition: String?, diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt index a6daa883..41b128e1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt @@ -5,7 +5,9 @@ import android.content.ContentValues import android.provider.Telephony import androidx.core.content.contentValuesOf import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable +@Serializable data class SmsBackup( @SerializedName("sub_id") val subscriptionId: Long, From 5a8cc0f14d33f15835fd9d8e32748c5d17a86298 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 16:21:44 +1000 Subject: [PATCH 03/30] Added BackupType with BackupSerializer --- .../smsmessenger/models/BackupType.kt | 13 +++++++++++ .../smsmessenger/models/MessagesBackup.kt | 23 +++++++++++++++++++ .../smsmessenger/models/MmsBackup.kt | 4 +++- .../smsmessenger/models/SmsBackup.kt | 6 +++-- 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/BackupType.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/BackupType.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/BackupType.kt new file mode 100644 index 00000000..c6132aee --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/BackupType.kt @@ -0,0 +1,13 @@ +package com.simplemobiletools.smsmessenger.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +enum class BackupType { + @SerialName("sms") + SMS, + + @SerialName("mms") + MMS, +} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt new file mode 100644 index 00000000..9f97aac2 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt @@ -0,0 +1,23 @@ +package com.simplemobiletools.smsmessenger.models + +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.* + +@Serializable(with = BackupSerializer::class) +sealed class MessagesBackup() { + @SerialName("backupType") + abstract val backupType: BackupType +} + +object BackupSerializer : + JsonContentPolymorphicSerializer(MessagesBackup::class) { + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { + return when (element.jsonObject["backupType"]?.jsonPrimitive?.content) { + "sms" -> SmsBackup.serializer() + "mms" -> MmsBackup.serializer() + else -> throw Exception("ERROR: No Serializer found. Serialization failed.") + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt index c2c2c93c..3d0c9d25 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MmsBackup.kt @@ -46,7 +46,9 @@ data class MmsBackup( val addresses: List, @SerializedName("parts") val parts: List, -) { + + override val backupType: BackupType = BackupType.MMS, +): MessagesBackup() { fun toContentValues(): ContentValues { return contentValuesOf( diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt index 41b128e1..ff3c9a39 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/SmsBackup.kt @@ -30,8 +30,10 @@ data class SmsBackup( @SerializedName("type") val type: Int, @SerializedName("service_center") - val serviceCenter: String? -) { + val serviceCenter: String?, + + override val backupType: BackupType = BackupType.SMS, + ): MessagesBackup() { fun toContentValues(): ContentValues { return contentValuesOf( From 30b100b62f2e2635b196a3c1e140e334c0c07898 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 16:22:14 +1000 Subject: [PATCH 04/30] Dialogs refactoring --- .../dialogs/ExportMessagesDialog.kt | 79 ++++++------------- .../dialogs/ImportMessagesDialog.kt | 15 ++-- .../res/layout/dialog_export_messages.xml | 15 ---- 3 files changed, 34 insertions(+), 75 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt index 56c9791d..48bb8d5f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt @@ -2,76 +2,49 @@ package com.simplemobiletools.smsmessenger.dialogs import android.view.ViewGroup import androidx.appcompat.app.AlertDialog -import com.simplemobiletools.commons.dialogs.FilePickerDialog -import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.extensions.getAlertDialogBuilder +import com.simplemobiletools.commons.extensions.getCurrentFormattedDateTime +import com.simplemobiletools.commons.extensions.isAValidFilename +import com.simplemobiletools.commons.extensions.setupDialogStuff +import com.simplemobiletools.commons.extensions.toast +import com.simplemobiletools.commons.extensions.value import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity import com.simplemobiletools.smsmessenger.extensions.config -import com.simplemobiletools.smsmessenger.helpers.EXPORT_FILE_EXT -import kotlinx.android.synthetic.main.dialog_export_messages.view.* -import java.io.File +import kotlinx.android.synthetic.main.dialog_export_messages.view.export_messages_filename +import kotlinx.android.synthetic.main.dialog_export_messages.view.export_mms_checkbox +import kotlinx.android.synthetic.main.dialog_export_messages.view.export_sms_checkbox class ExportMessagesDialog( private val activity: SimpleActivity, - private val path: String, - private val hidePath: Boolean, - private val callback: (file: File) -> Unit, + private val callback: (fileName: String) -> Unit, ) { - private var realPath = if (path.isEmpty()) activity.internalStoragePath else path private val config = activity.config init { val view = (activity.layoutInflater.inflate(R.layout.dialog_export_messages, null) as ViewGroup).apply { - export_messages_folder.setText(activity.humanizePath(realPath)) - export_messages_filename.setText("${activity.getString(R.string.messages)}_${activity.getCurrentFormattedDateTime()}") export_sms_checkbox.isChecked = config.exportSms export_mms_checkbox.isChecked = config.exportMms + export_messages_filename.setText("${activity.getString(R.string.messages)}_${activity.getCurrentFormattedDateTime()}") + } - if (hidePath) { - export_messages_folder_hint.beGone() - } else { - export_messages_folder.setOnClickListener { - activity.hideKeyboard(export_messages_filename) - FilePickerDialog(activity, realPath, false, showFAB = true) { - export_messages_folder.setText(activity.humanizePath(it)) - realPath = it + activity.getAlertDialogBuilder().setPositiveButton(R.string.ok, null).setNegativeButton(R.string.cancel, null).apply { + activity.setupDialogStuff(view, this, R.string.export_messages) { alertDialog -> + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { + config.exportSms = view.export_sms_checkbox.isChecked + config.exportMms = view.export_mms_checkbox.isChecked + val filename = view.export_messages_filename.value + when { + filename.isEmpty() -> activity.toast(R.string.empty_name) + filename.isAValidFilename() -> { + callback(filename) + alertDialog.dismiss() + } + + else -> activity.toast(R.string.invalid_name) } } } } - - activity.getAlertDialogBuilder() - .setPositiveButton(R.string.ok, null) - .setNegativeButton(R.string.cancel, null) - .apply { - activity.setupDialogStuff(view, this, R.string.export_messages) { alertDialog -> - alertDialog.showKeyboard(view.export_messages_filename) - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { - val filename = view.export_messages_filename.value - when { - filename.isEmpty() -> activity.toast(R.string.empty_name) - filename.isAValidFilename() -> { - val file = File(realPath, "$filename$EXPORT_FILE_EXT") - if (!hidePath && file.exists()) { - activity.toast(R.string.name_taken) - return@setOnClickListener - } - - if (!view.export_sms_checkbox.isChecked && !view.export_mms_checkbox.isChecked) { - activity.toast(R.string.no_option_selected) - return@setOnClickListener - } - - config.exportSms = view.export_sms_checkbox.isChecked - config.exportMms = view.export_mms_checkbox.isChecked - config.lastExportPath = file.absolutePath.getParentPath() - callback(file) - alertDialog.dismiss() - } - else -> activity.toast(R.string.invalid_name) - } - } - } - } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt index 3a493dc6..24828490 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt @@ -10,13 +10,13 @@ import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.helpers.MessagesImporter -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_OK -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_PARTIAL +import com.simplemobiletools.smsmessenger.models.MessagesBackup +import com.simplemobiletools.smsmessenger.models.ImportResult import kotlinx.android.synthetic.main.dialog_import_messages.view.* class ImportMessagesDialog( private val activity: SimpleActivity, - private val path: String, + private val messages: List, ) { private val config = activity.config @@ -48,7 +48,7 @@ class ImportMessagesDialog( config.importSms = view.import_sms_checkbox.isChecked config.importMms = view.import_mms_checkbox.isChecked ensureBackgroundThread { - MessagesImporter(activity).importMessages(path) { + MessagesImporter(activity).importMessages(messages) { handleParseResult(it) alertDialog.dismiss() } @@ -58,11 +58,12 @@ class ImportMessagesDialog( } } - private fun handleParseResult(result: MessagesImporter.ImportResult) { + private fun handleParseResult(result: ImportResult) { activity.toast( when (result) { - IMPORT_OK -> R.string.importing_successful - IMPORT_PARTIAL -> R.string.importing_some_entries_failed + ImportResult.IMPORT_OK -> R.string.importing_successful + ImportResult.IMPORT_PARTIAL -> R.string.importing_some_entries_failed + ImportResult.IMPORT_FAIL -> R.string.importing_failed else -> R.string.no_items_found } ) diff --git a/app/src/main/res/layout/dialog_export_messages.xml b/app/src/main/res/layout/dialog_export_messages.xml index 7fb85583..55747ed5 100644 --- a/app/src/main/res/layout/dialog_export_messages.xml +++ b/app/src/main/res/layout/dialog_export_messages.xml @@ -14,21 +14,6 @@ android:paddingTop="@dimen/activity_margin" android:paddingEnd="@dimen/activity_margin"> - - - - - - Date: Tue, 18 Jul 2023 16:23:04 +1000 Subject: [PATCH 05/30] ImportResult extracted to a separate class and MainActivity cleared --- .../smsmessenger/activities/MainActivity.kt | 119 ------------------ .../smsmessenger/helpers/MessagesExporter.kt | 68 ---------- .../smsmessenger/models/ImportResult.kt | 5 + app/src/main/res/menu/menu_main.xml | 10 -- 4 files changed, 5 insertions(+), 197 deletions(-) delete mode 100644 app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesExporter.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ImportResult.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt index 1204d748..07f056c0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt @@ -3,19 +3,15 @@ package com.simplemobiletools.smsmessenger.activities import android.annotation.SuppressLint import android.app.Activity import android.app.role.RoleManager -import android.content.ActivityNotFoundException import android.content.Intent import android.content.pm.ShortcutInfo import android.content.pm.ShortcutManager import android.graphics.drawable.Icon import android.graphics.drawable.LayerDrawable -import android.net.Uri import android.os.Bundle import android.provider.Telephony import android.text.TextUtils -import android.widget.Toast import androidx.coordinatorlayout.widget.CoordinatorLayout -import com.simplemobiletools.commons.dialogs.FilePickerDialog import com.simplemobiletools.commons.dialogs.PermissionRequiredDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* @@ -25,8 +21,6 @@ import com.simplemobiletools.smsmessenger.BuildConfig import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.adapters.ConversationsAdapter import com.simplemobiletools.smsmessenger.adapters.SearchResultsAdapter -import com.simplemobiletools.smsmessenger.dialogs.ExportMessagesDialog -import com.simplemobiletools.smsmessenger.dialogs.ImportMessagesDialog import com.simplemobiletools.smsmessenger.extensions.* import com.simplemobiletools.smsmessenger.helpers.* import com.simplemobiletools.smsmessenger.models.Conversation @@ -37,19 +31,14 @@ import kotlinx.android.synthetic.main.activity_main.* import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -import java.io.FileOutputStream -import java.io.OutputStream class MainActivity : SimpleActivity() { private val MAKE_DEFAULT_APP_REQUEST = 1 - private val PICK_IMPORT_SOURCE_INTENT = 11 - private val PICK_EXPORT_FILE_INTENT = 21 private var storedTextColor = 0 private var storedFontSize = 0 private var lastSearchedText = "" private var bus: EventBus? = null - private val smsExporter by lazy { MessagesExporter(this) } private var wasProtectionHandled = false @SuppressLint("InlinedApi") @@ -174,8 +163,6 @@ class MainActivity : SimpleActivity() { main_menu.getToolbar().setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { - R.id.import_messages -> tryImportMessages() - R.id.export_messages -> tryToExportMessages() R.id.more_apps_from_us -> launchMoreAppsFromUsIntent() R.id.settings -> launchSettings() R.id.about -> launchAbout() @@ -199,11 +186,6 @@ class MainActivity : SimpleActivity() { } else { finish() } - } else if (requestCode == PICK_IMPORT_SOURCE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { - tryImportMessagesFromFile(resultData.data!!) - } else if (requestCode == PICK_EXPORT_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { - val outputStream = contentResolver.openOutputStream(resultData.data!!) - exportMessagesTo(outputStream) } } @@ -578,107 +560,6 @@ class MainActivity : SimpleActivity() { startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true) } - private fun tryToExportMessages() { - if (isQPlus()) { - ExportMessagesDialog(this, config.lastExportPath, true) { file -> - Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - type = EXPORT_MIME_TYPE - putExtra(Intent.EXTRA_TITLE, file.name) - addCategory(Intent.CATEGORY_OPENABLE) - - try { - startActivityForResult(this, PICK_EXPORT_FILE_INTENT) - } catch (e: ActivityNotFoundException) { - toast(R.string.system_service_disabled, Toast.LENGTH_LONG) - } catch (e: Exception) { - showErrorToast(e) - } - } - } - } else { - handlePermission(PERMISSION_WRITE_STORAGE) { - if (it) { - ExportMessagesDialog(this, config.lastExportPath, false) { file -> - getFileOutputStream(file.toFileDirItem(this), true) { outStream -> - exportMessagesTo(outStream) - } - } - } - } - } - } - - private fun exportMessagesTo(outputStream: OutputStream?) { - toast(R.string.exporting) - ensureBackgroundThread { - smsExporter.exportMessages(outputStream) { - val toastId = when (it) { - MessagesExporter.ExportResult.EXPORT_OK -> R.string.exporting_successful - else -> R.string.exporting_failed - } - - toast(toastId) - } - } - } - - private fun tryImportMessages() { - if (isQPlus()) { - Intent(Intent.ACTION_GET_CONTENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = EXPORT_MIME_TYPE - - try { - startActivityForResult(this, PICK_IMPORT_SOURCE_INTENT) - } catch (e: ActivityNotFoundException) { - toast(R.string.system_service_disabled, Toast.LENGTH_LONG) - } catch (e: Exception) { - showErrorToast(e) - } - } - } else { - handlePermission(PERMISSION_READ_STORAGE) { - if (it) { - importEvents() - } - } - } - } - - private fun importEvents() { - FilePickerDialog(this) { - showImportEventsDialog(it) - } - } - - private fun showImportEventsDialog(path: String) { - ImportMessagesDialog(this, path) - } - - private fun tryImportMessagesFromFile(uri: Uri) { - when (uri.scheme) { - "file" -> showImportEventsDialog(uri.path!!) - "content" -> { - val tempFile = getTempFile("messages", "backup.json") - if (tempFile == null) { - toast(R.string.unknown_error_occurred) - return - } - - try { - val inputStream = contentResolver.openInputStream(uri) - val out = FileOutputStream(tempFile) - inputStream!!.copyTo(out) - showImportEventsDialog(tempFile.absolutePath) - } catch (e: Exception) { - showErrorToast(e) - } - } - - else -> toast(R.string.invalid_file_format) - } - } - @Subscribe(threadMode = ThreadMode.MAIN) fun refreshMessages(event: Events.RefreshMessages) { initMessenger() diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesExporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesExporter.kt deleted file mode 100644 index 49c2d4b6..00000000 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesExporter.kt +++ /dev/null @@ -1,68 +0,0 @@ -package com.simplemobiletools.smsmessenger.helpers - -import android.content.Context -import com.google.gson.Gson -import com.google.gson.stream.JsonWriter -import com.simplemobiletools.commons.helpers.ensureBackgroundThread -import com.simplemobiletools.smsmessenger.extensions.config -import com.simplemobiletools.smsmessenger.extensions.getConversationIds -import java.io.OutputStream - -class MessagesExporter(private val context: Context) { - enum class ExportResult { - EXPORT_FAIL, EXPORT_OK - } - - private val config = context.config - private val messageReader = MessagesReader(context) - private val gson = Gson() - - fun exportMessages(outputStream: OutputStream?, onProgress: (total: Int, current: Int) -> Unit = { _, _ -> }, callback: (result: ExportResult) -> Unit) { - ensureBackgroundThread { - if (outputStream == null) { - callback.invoke(ExportResult.EXPORT_FAIL) - return@ensureBackgroundThread - } - val writer = JsonWriter(outputStream.bufferedWriter()) - writer.use { - try { - var written = 0 - writer.beginArray() - val conversationIds = context.getConversationIds() - val totalMessages = messageReader.getMessagesCount() - for (threadId in conversationIds) { - writer.beginObject() - if (config.exportSms && messageReader.getSmsCount() > 0) { - writer.name("sms") - writer.beginArray() - messageReader.forEachSms(threadId) { - writer.jsonValue(gson.toJson(it)) - written++ - onProgress.invoke(totalMessages, written) - } - writer.endArray() - } - - if (config.exportMms && messageReader.getMmsCount() > 0) { - writer.name("mms") - writer.beginArray() - messageReader.forEachMms(threadId) { - writer.jsonValue(gson.toJson(it)) - written++ - onProgress.invoke(totalMessages, written) - } - - writer.endArray() - } - - writer.endObject() - } - writer.endArray() - callback.invoke(ExportResult.EXPORT_OK) - } catch (e: Exception) { - callback.invoke(ExportResult.EXPORT_FAIL) - } - } - } - } -} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ImportResult.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ImportResult.kt new file mode 100644 index 00000000..c4151d15 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/ImportResult.kt @@ -0,0 +1,5 @@ +package com.simplemobiletools.smsmessenger.models + +enum class ImportResult { + IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL, IMPORT_NOTHING_NEW +} diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index d60f5871..0c9486f7 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -3,16 +3,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:ignore="AppCompatResource,AlwaysShowAction"> - - Date: Tue, 18 Jul 2023 16:23:46 +1000 Subject: [PATCH 06/30] MessagesImporter and MessagesReader refactoring --- .../smsmessenger/helpers/MessagesImporter.kt | 92 ++------- .../smsmessenger/helpers/MessagesReader.kt | 178 ++++++++++-------- 2 files changed, 114 insertions(+), 156 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index 7377d057..c5020e31 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -1,102 +1,46 @@ package com.simplemobiletools.smsmessenger.helpers import android.content.Context -import android.util.JsonToken -import com.google.gson.Gson -import com.google.gson.reflect.TypeToken import com.simplemobiletools.commons.extensions.showErrorToast import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.smsmessenger.extensions.config -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_FAIL -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_NOTHING_NEW -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_OK -import com.simplemobiletools.smsmessenger.helpers.MessagesImporter.ImportResult.IMPORT_PARTIAL -import com.simplemobiletools.smsmessenger.models.MmsBackup -import com.simplemobiletools.smsmessenger.models.SmsBackup -import java.io.File +import com.simplemobiletools.smsmessenger.models.* class MessagesImporter(private val context: Context) { - enum class ImportResult { - IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL, IMPORT_NOTHING_NEW - } - private val gson = Gson() private val messageWriter = MessagesWriter(context) private val config = context.config private var messagesImported = 0 private var messagesFailed = 0 - fun importMessages(path: String, onProgress: (total: Int, current: Int) -> Unit = { _, _ -> }, callback: (result: ImportResult) -> Unit) { + fun importMessages(messagesBackup: List, callback: (result: ImportResult) -> Unit) { ensureBackgroundThread { try { - val inputStream = if (path.contains("/")) { - File(path).inputStream() - } else { - context.assets.open(path) - } - - inputStream.bufferedReader().use { reader -> - val jsonReader = gson.newJsonReader(reader) - val smsMessageType = object : TypeToken() {}.type - val mmsMessageType = object : TypeToken() {}.type - - jsonReader.beginArray() - while (jsonReader.hasNext()) { - jsonReader.beginObject() - while (jsonReader.hasNext()) { - val nextToken = jsonReader.peek() - if (nextToken.ordinal == JsonToken.NAME.ordinal) { - val msgType = jsonReader.nextName() - - if ((!msgType.equals("sms") && !msgType.equals("mms")) || - (msgType.equals("sms") && !config.importSms) || - (msgType.equals("mms") && !config.importMms) - ) { - jsonReader.skipValue() - continue - } - - jsonReader.beginArray() - while (jsonReader.hasNext()) { - try { - if (msgType.equals("sms")) { - val message = gson.fromJson(jsonReader, smsMessageType) - messageWriter.writeSmsMessage(message) - } else { - val message = gson.fromJson(jsonReader, mmsMessageType) - messageWriter.writeMmsMessage(message) - } - - messagesImported++ - } catch (e: Exception) { - context.showErrorToast(e) - messagesFailed++ - - } - } - jsonReader.endArray() - } else { - jsonReader.skipValue() - } + messagesBackup.forEach { message -> + try { + if (message.backupType == BackupType.SMS && config.importSms) { + messageWriter.writeSmsMessage(message as SmsBackup) + } else if (message.backupType == BackupType.MMS && config.importMms) { + messageWriter.writeMmsMessage(message as MmsBackup) } - - jsonReader.endObject() - refreshMessages() + else return@forEach + messagesImported++ + } catch (e: Exception) { + context.showErrorToast(e) + messagesFailed++ } - - jsonReader.endArray() } + refreshMessages() } catch (e: Exception) { context.showErrorToast(e) - messagesFailed++ } callback.invoke( when { - messagesImported == 0 && messagesFailed == 0 -> IMPORT_NOTHING_NEW - messagesFailed > 0 && messagesImported > 0 -> IMPORT_PARTIAL - messagesFailed > 0 -> IMPORT_FAIL - else -> IMPORT_OK + messagesImported == 0 && messagesFailed == 0 -> ImportResult.IMPORT_NOTHING_NEW + messagesFailed > 0 && messagesImported > 0 -> ImportResult.IMPORT_PARTIAL + messagesFailed > 0 -> ImportResult.IMPORT_FAIL + else -> ImportResult.IMPORT_OK } ) } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt index 175ad735..fbf164c5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt @@ -9,49 +9,60 @@ import android.util.Base64 import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.isQPlus import com.simplemobiletools.commons.helpers.isRPlus -import com.simplemobiletools.smsmessenger.models.MmsAddress -import com.simplemobiletools.smsmessenger.models.MmsBackup -import com.simplemobiletools.smsmessenger.models.MmsPart -import com.simplemobiletools.smsmessenger.models.SmsBackup +import com.simplemobiletools.smsmessenger.extensions.getConversationIds +import com.simplemobiletools.smsmessenger.models.* import java.io.IOException import java.io.InputStream class MessagesReader(private val context: Context) { - fun forEachSms(threadId: Long, block: (SmsBackup) -> Unit) { + + fun getMessagesToExport( + getSms: Boolean, + getMms: Boolean, + callback: (messages: List) -> Unit + ) { + val conversationIds = context.getConversationIds() + var smsMessages = listOf() + var mmsMessages = listOf() + + if (getSms) { + smsMessages = getSmsMessages(conversationIds) + } + if (getMms) { + mmsMessages = getMmsMessages(conversationIds) + } + callback(smsMessages + mmsMessages) + } + + private fun getSmsMessages(threadIds: List): List { val projection = arrayOf( - Sms.SUBSCRIPTION_ID, - Sms.ADDRESS, - Sms.BODY, - Sms.DATE, - Sms.DATE_SENT, - Sms.LOCKED, - Sms.PROTOCOL, - Sms.READ, - Sms.STATUS, - Sms.TYPE, - Sms.SERVICE_CENTER + Sms.SUBSCRIPTION_ID, Sms.ADDRESS, Sms.BODY, Sms.DATE, Sms.DATE_SENT, Sms.LOCKED, Sms.PROTOCOL, Sms.READ, Sms.STATUS, Sms.TYPE, Sms.SERVICE_CENTER ) val selection = "${Sms.THREAD_ID} = ?" - val selectionArgs = arrayOf(threadId.toString()) - context.queryCursor(Sms.CONTENT_URI, projection, selection, selectionArgs) { cursor -> - val subscriptionId = cursor.getLongValue(Sms.SUBSCRIPTION_ID) - val address = cursor.getStringValue(Sms.ADDRESS) - val body = cursor.getStringValueOrNull(Sms.BODY) - val date = cursor.getLongValue(Sms.DATE) - val dateSent = cursor.getLongValue(Sms.DATE_SENT) - val locked = cursor.getIntValue(Sms.DATE_SENT) - val protocol = cursor.getStringValueOrNull(Sms.PROTOCOL) - val read = cursor.getIntValue(Sms.READ) - val status = cursor.getIntValue(Sms.STATUS) - val type = cursor.getIntValue(Sms.TYPE) - val serviceCenter = cursor.getStringValueOrNull(Sms.SERVICE_CENTER) - block(SmsBackup(subscriptionId, address, body, date, dateSent, locked, protocol, read, status, type, serviceCenter)) + val smsList = mutableListOf() + + threadIds.map { it.toString() }.forEach { threadId -> + context.queryCursor(Sms.CONTENT_URI, projection, selection, arrayOf(threadId)) { cursor -> + val subscriptionId = cursor.getLongValue(Sms.SUBSCRIPTION_ID) + val address = cursor.getStringValue(Sms.ADDRESS) + val body = cursor.getStringValueOrNull(Sms.BODY) + val date = cursor.getLongValue(Sms.DATE) + val dateSent = cursor.getLongValue(Sms.DATE_SENT) + val locked = cursor.getIntValue(Sms.DATE_SENT) + val protocol = cursor.getStringValueOrNull(Sms.PROTOCOL) + val read = cursor.getIntValue(Sms.READ) + val status = cursor.getIntValue(Sms.STATUS) + val type = cursor.getIntValue(Sms.TYPE) + val serviceCenter = cursor.getStringValueOrNull(Sms.SERVICE_CENTER) + smsList.add(SmsBackup(subscriptionId, address, body, date, dateSent, locked, protocol, read, status, type, serviceCenter)) + } } + + return smsList } - // all mms from simple sms are non-text messages - fun forEachMms(threadId: Long, includeTextOnlyAttachment: Boolean = false, block: (MmsBackup) -> Unit) { + private fun getMmsMessages(threadIds: List, includeTextOnlyAttachment: Boolean = false): List { val projection = arrayOf( Mms._ID, Mms.CREATOR, @@ -71,65 +82,67 @@ class MessagesReader(private val context: Context) { Mms.SUBSCRIPTION_ID, Mms.TRANSACTION_ID ) - val selection = if (includeTextOnlyAttachment) { "${Mms.THREAD_ID} = ? AND ${Mms.TEXT_ONLY} = ?" } else { "${Mms.THREAD_ID} = ?" } + val mmsList = mutableListOf() - val selectionArgs = if (includeTextOnlyAttachment) { - arrayOf(threadId.toString(), "1") - } else { - arrayOf(threadId.toString()) - } + threadIds.map { it.toString() }.forEach { threadId -> + val selectionArgs = if (includeTextOnlyAttachment) { + arrayOf(threadId, "1") + } else { + arrayOf(threadId) + } + context.queryCursor(Mms.CONTENT_URI, projection, selection, selectionArgs) { cursor -> + val mmsId = cursor.getLongValue(Mms._ID) + val creator = cursor.getStringValueOrNull(Mms.CREATOR) + val contentType = cursor.getStringValueOrNull(Mms.CONTENT_TYPE) + val deliveryReport = cursor.getIntValue(Mms.DELIVERY_REPORT) + val date = cursor.getLongValue(Mms.DATE) + val dateSent = cursor.getLongValue(Mms.DATE_SENT) + val locked = cursor.getIntValue(Mms.LOCKED) + val messageType = cursor.getIntValue(Mms.MESSAGE_TYPE) + val messageBox = cursor.getIntValue(Mms.MESSAGE_BOX) + val read = cursor.getIntValue(Mms.READ) + val readReport = cursor.getIntValue(Mms.READ_REPORT) + val seen = cursor.getIntValue(Mms.SEEN) + val textOnly = cursor.getIntValue(Mms.TEXT_ONLY) + val status = cursor.getStringValueOrNull(Mms.STATUS) + val subject = cursor.getStringValueOrNull(Mms.SUBJECT) + val subjectCharSet = cursor.getStringValueOrNull(Mms.SUBJECT_CHARSET) + val subscriptionId = cursor.getLongValue(Mms.SUBSCRIPTION_ID) + val transactionId = cursor.getStringValueOrNull(Mms.TRANSACTION_ID) - context.queryCursor(Mms.CONTENT_URI, projection, selection, selectionArgs) { cursor -> - val mmsId = cursor.getLongValue(Mms._ID) - val creator = cursor.getStringValueOrNull(Mms.CREATOR) - val contentType = cursor.getStringValueOrNull(Mms.CONTENT_TYPE) - val deliveryReport = cursor.getIntValue(Mms.DELIVERY_REPORT) - val date = cursor.getLongValue(Mms.DATE) - val dateSent = cursor.getLongValue(Mms.DATE_SENT) - val locked = cursor.getIntValue(Mms.LOCKED) - val messageType = cursor.getIntValue(Mms.MESSAGE_TYPE) - val messageBox = cursor.getIntValue(Mms.MESSAGE_BOX) - val read = cursor.getIntValue(Mms.READ) - val readReport = cursor.getIntValue(Mms.READ_REPORT) - val seen = cursor.getIntValue(Mms.SEEN) - val textOnly = cursor.getIntValue(Mms.TEXT_ONLY) - val status = cursor.getStringValueOrNull(Mms.STATUS) - val subject = cursor.getStringValueOrNull(Mms.SUBJECT) - val subjectCharSet = cursor.getStringValueOrNull(Mms.SUBJECT_CHARSET) - val subscriptionId = cursor.getLongValue(Mms.SUBSCRIPTION_ID) - val transactionId = cursor.getStringValueOrNull(Mms.TRANSACTION_ID) - - val parts = getParts(mmsId) - val addresses = getMmsAddresses(mmsId) - block( - MmsBackup( - creator, - contentType, - deliveryReport, - date, - dateSent, - locked, - messageType, - messageBox, - read, - readReport, - seen, - textOnly, - status, - subject, - subjectCharSet, - subscriptionId, - transactionId, - addresses, - parts + val parts = getParts(mmsId) + val addresses = getMmsAddresses(mmsId) + mmsList.add( + MmsBackup( + creator, + contentType, + deliveryReport, + date, + dateSent, + locked, + messageType, + messageBox, + read, + readReport, + seen, + textOnly, + status, + subject, + subjectCharSet, + subscriptionId, + transactionId, + addresses, + parts + ) ) - ) + } } + return mmsList } @SuppressLint("NewApi") @@ -172,6 +185,7 @@ class MessagesReader(private val context: Context) { stream.readBytes().toString(Charsets.UTF_8) } } + else -> { usePart(partId) { stream -> Base64.encodeToString(stream.readBytes(), Base64.DEFAULT) From 47866a1c19ea298e1020bace1fae04a84180c7b7 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 16:24:04 +1000 Subject: [PATCH 07/30] Settings activity configured import/export --- .../activities/SettingsActivity.kt | 90 ++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt index d97e67d0..cb697ece 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt @@ -2,21 +2,32 @@ package com.simplemobiletools.smsmessenger.activities import android.annotation.TargetApi import android.content.Intent +import android.net.Uri import android.os.Build import android.os.Bundle +import androidx.activity.result.contract.ActivityResultContracts import com.simplemobiletools.commons.activities.ManageBlockedNumbersActivity import com.simplemobiletools.commons.dialogs.* import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.smsmessenger.R +import com.simplemobiletools.smsmessenger.dialogs.ExportMessagesDialog +import com.simplemobiletools.smsmessenger.dialogs.ImportMessagesDialog import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.helpers.* +import com.simplemobiletools.smsmessenger.models.* import kotlinx.android.synthetic.main.activity_settings.* +import kotlinx.serialization.SerializationException +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import java.util.* +import kotlin.system.exitProcess class SettingsActivity : SimpleActivity() { private var blockedNumbersAtPause = -1 + private val messagesFileType = "application/json" override fun onCreate(savedInstanceState: Bundle?) { isMaterialActivity = true @@ -48,6 +59,8 @@ class SettingsActivity : SimpleActivity() { setupLockScreenVisibility() setupMMSFileSizeLimit() setupAppPasswordProtection() + setupMessagesExport() + setupMessagesImport() updateTextColors(settings_nested_scrollview) if (blockedNumbersAtPause != -1 && blockedNumbersAtPause != getBlockedNumbers().hashCode()) { @@ -59,12 +72,85 @@ class SettingsActivity : SimpleActivity() { settings_general_settings_label, settings_outgoing_messages_label, settings_notifications_label, - settings_security_label + settings_security_label, + settings_migrating_label ).forEach { it.setTextColor(getProperPrimaryColor()) } } + private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> + if (uri != null) { + toast(R.string.importing) + importMessages(uri) + } + } + + private val saveDocument = registerForActivityResult(ActivityResultContracts.CreateDocument(messagesFileType)) { uri -> + if (uri != null) { + toast(R.string.exporting) + exportMessages(uri) + } + } + + private fun setupMessagesExport() { + settings_export_messages_holder.setOnClickListener { + ExportMessagesDialog(this) { fileName -> + saveDocument.launch(fileName) + } + } + } + + private fun setupMessagesImport() { + settings_import_messages_holder.setOnClickListener { + getContent.launch(messagesFileType) + } + } + + private fun exportMessages(uri: Uri) { + ensureBackgroundThread { + try { + MessagesReader(this).getMessagesToExport(config.exportSms, config.exportMms) { messagesToExport -> + if (messagesToExport.isEmpty()) { + toast(R.string.no_entries_for_exporting) + return@getMessagesToExport + } + val json = Json { encodeDefaults = true } + val jsonString = json.encodeToString(messagesToExport) + val outputStream = contentResolver.openOutputStream(uri)!! + + outputStream.use { + it.write(jsonString.toByteArray()) + } + toast(R.string.exporting_successful) + } + } catch (e: Exception) { + showErrorToast(e) + } + } + } + + private fun importMessages(uri: Uri) { + try { + val jsonString = contentResolver.openInputStream(uri)!!.use { inputStream -> + inputStream.bufferedReader().readText() + } + + val deserializedList = Json.decodeFromString>(jsonString) + if (deserializedList.isEmpty()) { + toast(R.string.no_entries_for_importing) + return + } + ImportMessagesDialog(this, deserializedList) + } catch (e: SerializationException) { + toast(R.string.invalid_file_format) + } catch (e: IllegalArgumentException) { + toast(R.string.invalid_file_format) + } catch (e: Exception) { + showErrorToast(e) + } + } + override fun onPause() { super.onPause() blockedNumbersAtPause = getBlockedNumbers().hashCode() @@ -97,7 +183,7 @@ class SettingsActivity : SimpleActivity() { settings_use_english_holder.setOnClickListener { settings_use_english.toggle() config.useEnglish = settings_use_english.isChecked - System.exit(0) + exitProcess(0) } } From db5decfcd888650c22343f3f1a5230b5bebe9f10 Mon Sep 17 00:00:00 2001 From: merkost Date: Tue, 18 Jul 2023 17:17:52 +1000 Subject: [PATCH 08/30] Added additional types for txt or xml and moved import logic to Importer --- .../activities/SettingsActivity.kt | 32 +--- .../dialogs/ImportMessagesDialog.kt | 2 +- .../smsmessenger/helpers/MessagesImporter.kt | 157 +++++++++++++++++- 3 files changed, 158 insertions(+), 33 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt index 310c81f9..47aac9c5 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt @@ -28,6 +28,7 @@ import kotlin.system.exitProcess class SettingsActivity : SimpleActivity() { private var blockedNumbersAtPause = -1 private val messagesFileType = "application/json" + private val messageImportFileType = "application/json, application/xml, text/plain" override fun onCreate(savedInstanceState: Bundle?) { isMaterialActivity = true @@ -83,7 +84,13 @@ class SettingsActivity : SimpleActivity() { private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> if (uri != null) { toast(R.string.importing) - importMessages(uri) + MessagesImporter(this).importMessages(uri) { deserializedList -> + if (deserializedList.isEmpty()) { + toast(R.string.no_entries_for_importing) + } else { + ImportMessagesDialog(this, deserializedList) + } + } } } @@ -104,7 +111,7 @@ class SettingsActivity : SimpleActivity() { private fun setupMessagesImport() { settings_import_messages_holder.setOnClickListener { - getContent.launch(messagesFileType) + getContent.launch(messageImportFileType) } } @@ -131,27 +138,6 @@ class SettingsActivity : SimpleActivity() { } } - private fun importMessages(uri: Uri) { - try { - val jsonString = contentResolver.openInputStream(uri)!!.use { inputStream -> - inputStream.bufferedReader().readText() - } - - val deserializedList = Json.decodeFromString>(jsonString) - if (deserializedList.isEmpty()) { - toast(R.string.no_entries_for_importing) - return - } - ImportMessagesDialog(this, deserializedList) - } catch (e: SerializationException) { - toast(R.string.invalid_file_format) - } catch (e: IllegalArgumentException) { - toast(R.string.invalid_file_format) - } catch (e: Exception) { - showErrorToast(e) - } - } - override fun onPause() { super.onPause() blockedNumbersAtPause = getBlockedNumbers().hashCode() diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt index 24828490..626115fa 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ImportMessagesDialog.kt @@ -48,7 +48,7 @@ class ImportMessagesDialog( config.importSms = view.import_sms_checkbox.isChecked config.importMms = view.import_mms_checkbox.isChecked ensureBackgroundThread { - MessagesImporter(activity).importMessages(messages) { + MessagesImporter(activity).restoreMessages(messages) { handleParseResult(it) alertDialog.dismiss() } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index 149c9489..8d04ec47 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -1,20 +1,68 @@ package com.simplemobiletools.smsmessenger.helpers -import android.content.Context +import android.net.Uri +import android.util.Xml import com.simplemobiletools.commons.extensions.showErrorToast +import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.smsmessenger.R +import com.simplemobiletools.smsmessenger.activities.SimpleActivity +import com.simplemobiletools.smsmessenger.dialogs.ImportMessagesDialog import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.models.* +import kotlinx.serialization.SerializationException +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import org.xmlpull.v1.XmlPullParser +import java.io.InputStream -class MessagesImporter(private val context: Context) { +class MessagesImporter(private val activity: SimpleActivity) { - private val messageWriter = MessagesWriter(context) - private val config = context.config + private val messageWriter = MessagesWriter(activity) + private val config = activity.config private var messagesImported = 0 private var messagesFailed = 0 - fun importMessages(messagesBackup: List, callback: (result: ImportResult) -> Unit) { + fun importMessages(uri: Uri) { + try { + val fileType = activity.contentResolver.getType(uri).orEmpty() + + val isXml = isXmlMimeType(fileType) || (uri.path?.endsWith("txt") == true && isFileXml(uri)) + + if (isXml) { + getInputStreamFromUri(uri)!!.importXml() + } else { + importJson(uri) + } + + } catch (e: Exception) { + activity.showErrorToast(e) + } + } + + private fun importJson(uri: Uri) { + try { + val jsonString = activity.contentResolver.openInputStream(uri)!!.use { inputStream -> + inputStream.bufferedReader().readText() + } + + val deserializedList = Json.decodeFromString>(jsonString) + if (deserializedList.isEmpty()) { + activity.toast(R.string.no_entries_for_importing) + return + } + ImportMessagesDialog(activity, deserializedList) + } catch (e: SerializationException) { + activity.toast(R.string.invalid_file_format) + } catch (e: IllegalArgumentException) { + activity.toast(R.string.invalid_file_format) + } catch (e: Exception) { + activity.showErrorToast(e) + } + } + + fun restoreMessages(messagesBackup: List, callback: (ImportResult) -> Unit) { ensureBackgroundThread { try { messagesBackup.forEach { message -> @@ -23,17 +71,16 @@ class MessagesImporter(private val context: Context) { messageWriter.writeSmsMessage(message as SmsBackup) } else if (message.backupType == BackupType.MMS && config.importMms) { messageWriter.writeMmsMessage(message as MmsBackup) - } - else return@forEach + } else return@forEach messagesImported++ } catch (e: Exception) { - context.showErrorToast(e) + activity.showErrorToast(e) messagesFailed++ } } refreshMessages() } catch (e: Exception) { - context.showErrorToast(e) + activity.showErrorToast(e) } callback.invoke( @@ -46,4 +93,96 @@ class MessagesImporter(private val context: Context) { ) } } + + private fun InputStream.importXml() { + bufferedReader().use { reader -> + val xmlParser = Xml.newPullParser().apply { + setInput(reader) + } + + xmlParser.nextTag() + xmlParser.require(XmlPullParser.START_TAG, null, "smses") + + var depth = 1 + while (depth != 0) { + when (xmlParser.next()) { + XmlPullParser.END_TAG -> depth-- + XmlPullParser.START_TAG -> depth++ + } + + if (xmlParser.eventType != XmlPullParser.START_TAG) { + continue + } + + try { + if (xmlParser.name == "sms") { + if (config.importSms) { + val message = xmlParser.readSms() + messageWriter.writeSmsMessage(message) + messagesImported++ + } else { + xmlParser.skip() + } + } else { + xmlParser.skip() + } + } catch (e: Exception) { + activity.showErrorToast(e) + messagesFailed++ + } + } + refreshMessages() + } + // TODO: Add result to xml import + } + + private fun XmlPullParser.readSms(): SmsBackup { + require(XmlPullParser.START_TAG, null, "sms") + + return SmsBackup( + subscriptionId = 0, + address = getAttributeValue(null, "address"), + body = getAttributeValue(null, "body"), + date = getAttributeValue(null, "date").toLong(), + dateSent = getAttributeValue(null, "date").toLong(), + locked = getAttributeValue(null, "locked").toInt(), + protocol = getAttributeValue(null, "protocol"), + read = getAttributeValue(null, "read").toInt(), + status = getAttributeValue(null, "status").toInt(), + type = getAttributeValue(null, "type").toInt(), + serviceCenter = getAttributeValue(null, "service_center") + ) + } + + private fun XmlPullParser.skip() { + if (eventType != XmlPullParser.START_TAG) { + throw IllegalStateException() + } + var depth = 1 + while (depth != 0) { + when (next()) { + XmlPullParser.END_TAG -> depth-- + XmlPullParser.START_TAG -> depth++ + } + } + } + + private fun getInputStreamFromUri(uri: Uri): InputStream? { + return try { + activity.contentResolver.openInputStream(uri) + } catch (e: Exception) { + null + } + } + + private fun isFileXml(uri: Uri): Boolean { + val inputStream = getInputStreamFromUri(uri) + return inputStream?.bufferedReader()?.use { reader -> + reader.readLine()?.startsWith(" Date: Thu, 20 Jul 2023 13:37:54 +1000 Subject: [PATCH 09/30] Added and refactored xml import support --- .../smsmessenger/activities/SettingsActivity.kt | 17 ++++------------- .../smsmessenger/helpers/MessagesImporter.kt | 15 ++++++++++----- .../smsmessenger/models/MessagesBackup.kt | 3 ++- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt index 47aac9c5..094f5e56 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt @@ -13,13 +13,10 @@ import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.dialogs.ExportMessagesDialog -import com.simplemobiletools.smsmessenger.dialogs.ImportMessagesDialog import com.simplemobiletools.smsmessenger.extensions.config import com.simplemobiletools.smsmessenger.helpers.* import com.simplemobiletools.smsmessenger.models.* import kotlinx.android.synthetic.main.activity_settings.* -import kotlinx.serialization.SerializationException -import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.util.* @@ -28,7 +25,7 @@ import kotlin.system.exitProcess class SettingsActivity : SimpleActivity() { private var blockedNumbersAtPause = -1 private val messagesFileType = "application/json" - private val messageImportFileType = "application/json, application/xml, text/plain" + private val messageImportFileTypes = listOf("application/json", "application/xml", "text/xml") override fun onCreate(savedInstanceState: Bundle?) { isMaterialActivity = true @@ -81,16 +78,10 @@ class SettingsActivity : SimpleActivity() { } } - private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> + private val getContent = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> if (uri != null) { toast(R.string.importing) - MessagesImporter(this).importMessages(uri) { deserializedList -> - if (deserializedList.isEmpty()) { - toast(R.string.no_entries_for_importing) - } else { - ImportMessagesDialog(this, deserializedList) - } - } + MessagesImporter(this).importMessages(uri) } } @@ -111,7 +102,7 @@ class SettingsActivity : SimpleActivity() { private fun setupMessagesImport() { settings_import_messages_holder.setOnClickListener { - getContent.launch(messageImportFileType) + getContent.launch(messageImportFileTypes.toTypedArray()) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index 8d04ec47..66eaff0c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -27,15 +27,12 @@ class MessagesImporter(private val activity: SimpleActivity) { fun importMessages(uri: Uri) { try { val fileType = activity.contentResolver.getType(uri).orEmpty() - val isXml = isXmlMimeType(fileType) || (uri.path?.endsWith("txt") == true && isFileXml(uri)) - if (isXml) { getInputStreamFromUri(uri)!!.importXml() } else { importJson(uri) } - } catch (e: Exception) { activity.showErrorToast(e) } @@ -133,7 +130,11 @@ class MessagesImporter(private val activity: SimpleActivity) { } refreshMessages() } - // TODO: Add result to xml import + when { + messagesFailed > 0 && messagesImported > 0 -> activity.toast(R.string.importing_some_entries_failed) + messagesFailed > 0 -> activity.toast(R.string.importing_failed) + else -> activity.toast(R.string.importing_successful) + } } private fun XmlPullParser.readSms(): SmsBackup { @@ -183,6 +184,10 @@ class MessagesImporter(private val activity: SimpleActivity) { } private fun isXmlMimeType(mimeType: String): Boolean { - return mimeType.equals("application/xml", ignoreCase = true) + return mimeType.equals("application/xml", ignoreCase = true) || mimeType.equals("text/xml", ignoreCase = true) + } + + private fun isJsonMimeType(mimeType: String): Boolean { + return mimeType.equals("application/json", ignoreCase = true) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt index 9f97aac2..a01137c9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/MessagesBackup.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.smsmessenger.models import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException import kotlinx.serialization.json.* @Serializable(with = BackupSerializer::class) @@ -17,7 +18,7 @@ object BackupSerializer : return when (element.jsonObject["backupType"]?.jsonPrimitive?.content) { "sms" -> SmsBackup.serializer() "mms" -> MmsBackup.serializer() - else -> throw Exception("ERROR: No Serializer found. Serialization failed.") + else -> throw SerializationException("ERROR: No Serializer found. Serialization failed.") } } } From c72dc199aac17a5326328b112721c800475f4223 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 22 Jul 2023 00:10:17 +1000 Subject: [PATCH 10/30] ExportMessagesDialog code refactoring --- .../dialogs/ExportMessagesDialog.kt | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt index c3f5818f..d694b313 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt @@ -2,12 +2,7 @@ package com.simplemobiletools.smsmessenger.dialogs import android.view.ViewGroup import androidx.appcompat.app.AlertDialog -import com.simplemobiletools.commons.extensions.getAlertDialogBuilder -import com.simplemobiletools.commons.extensions.getCurrentFormattedDateTime -import com.simplemobiletools.commons.extensions.isAValidFilename -import com.simplemobiletools.commons.extensions.setupDialogStuff -import com.simplemobiletools.commons.extensions.toast -import com.simplemobiletools.commons.extensions.value +import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity import com.simplemobiletools.smsmessenger.extensions.config @@ -26,27 +21,32 @@ class ExportMessagesDialog( val view = (activity.layoutInflater.inflate(R.layout.dialog_export_messages, null) as ViewGroup).apply { export_sms_checkbox.isChecked = config.exportSms export_mms_checkbox.isChecked = config.exportMms - export_messages_filename.setText("${activity.getString(R.string.messages)}_${activity.getCurrentFormattedDateTime()}") + export_messages_filename.setText( + activity.getString(R.string.messages) + "_" + activity.getCurrentFormattedDateTime() + ) } - activity.getAlertDialogBuilder().setPositiveButton(R.string.ok, null).setNegativeButton(R.string.cancel, null).apply { - activity.setupDialogStuff(view, this, R.string.export_messages) { alertDialog -> - alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { - config.exportSms = view.export_sms_checkbox.isChecked - config.exportMms = view.export_mms_checkbox.isChecked - val filename = view.export_messages_filename.value - when { - filename.isEmpty() -> activity.toast(R.string.empty_name) - filename.isAValidFilename() -> { - callback(filename) - alertDialog.dismiss() + activity.getAlertDialogBuilder() + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .apply { + activity.setupDialogStuff(view, this, R.string.export_messages) { alertDialog -> + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { + config.exportSms = view.export_sms_checkbox.isChecked + config.exportMms = view.export_mms_checkbox.isChecked + val filename = view.export_messages_filename.value + when { + filename.isEmpty() -> activity.toast(R.string.empty_name) + filename.isAValidFilename() -> { + callback(filename) + alertDialog.dismiss() + } + + else -> activity.toast(R.string.invalid_name) } - - else -> activity.toast(R.string.invalid_name) } } } - } } } From 842368d0f415d19682631a14a3a1ac74c4dc734c Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 22 Jul 2023 00:14:55 +1000 Subject: [PATCH 11/30] Split lines in MessagesReader --- .../smsmessenger/helpers/MessagesReader.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt index 809e3325..eacd4345 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesReader.kt @@ -17,9 +17,7 @@ import java.io.InputStream class MessagesReader(private val context: Context) { fun getMessagesToExport( - getSms: Boolean, - getMms: Boolean, - callback: (messages: List) -> Unit + getSms: Boolean, getMms: Boolean, callback: (messages: List) -> Unit ) { val conversationIds = context.getConversationIds() var smsMessages = listOf() @@ -36,7 +34,17 @@ class MessagesReader(private val context: Context) { private fun getSmsMessages(threadIds: List): List { val projection = arrayOf( - Sms.SUBSCRIPTION_ID, Sms.ADDRESS, Sms.BODY, Sms.DATE, Sms.DATE_SENT, Sms.LOCKED, Sms.PROTOCOL, Sms.READ, Sms.STATUS, Sms.TYPE, Sms.SERVICE_CENTER + Sms.SUBSCRIPTION_ID, + Sms.ADDRESS, + Sms.BODY, + Sms.DATE, + Sms.DATE_SENT, + Sms.LOCKED, + Sms.PROTOCOL, + Sms.READ, + Sms.STATUS, + Sms.TYPE, + Sms.SERVICE_CENTER ) val selection = "${Sms.THREAD_ID} = ?" From 8c0508b0c1db9c50047f7910a39d1d1f8551d057 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 22 Jul 2023 00:31:24 +1000 Subject: [PATCH 12/30] Refactored message restoring in MessagesImporter --- .../smsmessenger/helpers/MessagesImporter.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index 66eaff0c..b3e625b8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -66,10 +66,11 @@ class MessagesImporter(private val activity: SimpleActivity) { try { if (message.backupType == BackupType.SMS && config.importSms) { messageWriter.writeSmsMessage(message as SmsBackup) + messagesImported++ } else if (message.backupType == BackupType.MMS && config.importMms) { messageWriter.writeMmsMessage(message as MmsBackup) - } else return@forEach - messagesImported++ + messagesImported++ + } } catch (e: Exception) { activity.showErrorToast(e) messagesFailed++ From 39ca2d60798e29ad50f4aff32fa712fc2387225f Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 22 Jul 2023 10:05:45 +1000 Subject: [PATCH 13/30] Added proguard-rules.pro for Kotlin Serialization --- app/proguard-rules.pro | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index e6c59860..2c52942d 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -4,3 +4,27 @@ @org.greenrobot.eventbus.Subscribe ; } -keep enum org.greenrobot.eventbus.ThreadMode { *; } + +# Keep `Companion` object fields of serializable classes. +# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects. +-if @kotlinx.serialization.Serializable class ** +-keepclassmembers class <1> { + static <1>$Companion Companion; +} + +# Keep `serializer()` on companion objects (both default and named) of serializable classes. +-if @kotlinx.serialization.Serializable class ** { + static **$* *; +} +-keepclassmembers class <2>$<3> { + kotlinx.serialization.KSerializer serializer(...); +} + +# Keep `INSTANCE.serializer()` of serializable objects. +-if @kotlinx.serialization.Serializable class ** { + public static ** INSTANCE; +} +-keepclassmembers class <1> { + public static <1> INSTANCE; + kotlinx.serialization.KSerializer serializer(...); +} From 3d95ce2b835d6266d400bacb79617a582037b5c4 Mon Sep 17 00:00:00 2001 From: spkprs Date: Sat, 22 Jul 2023 12:51:21 +0300 Subject: [PATCH 14/30] Update strings.xml --- app/src/main/res/values-el/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 0a3b2638..9c6d8374 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -59,17 +59,17 @@ Σήμανση ως Μη Αναγνωσμένο Εγώ - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + Μη αρχειοθέτηση + Διαγραφή όλων των αρχειοθετημένων συνομιλιών + Αρχειοθέτηση + Εμφάνιση αρχειοθετημένων συνομιλιών + Αρχειοθέτηση + Δεν βρέθηκαν αρχειοθετημένες συνομιλίες + Το αρχείο άδειασε με επιτυχία + Είστε σίγουροι ότι θέλετε να αδειάσετε το αρχείο; Όλες οι αρχειοθετημένες συνομιλίες θα χαθούν οριστικά. Είστε βέβαιοι ότι θέλετε να διαγράψετε όλα τα μηνύματα αυτής της συνομιλίας; - Are you sure you want to archive %s? + Σίγουρα θέλετε να αρχειοθετήσετε %s; %d συνομιλία From e244fd5a53058ab3a180ab24c97af0465d8dd727 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 22 Jul 2023 22:54:05 +1000 Subject: [PATCH 15/30] Moved "Importing" toast --- .../smsmessenger/activities/SettingsActivity.kt | 1 - .../simplemobiletools/smsmessenger/helpers/MessagesImporter.kt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt index 094f5e56..12c845f6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/SettingsActivity.kt @@ -80,7 +80,6 @@ class SettingsActivity : SimpleActivity() { private val getContent = registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri -> if (uri != null) { - toast(R.string.importing) MessagesImporter(this).importMessages(uri) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index b3e625b8..e9a70bf8 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -29,6 +29,7 @@ class MessagesImporter(private val activity: SimpleActivity) { val fileType = activity.contentResolver.getType(uri).orEmpty() val isXml = isXmlMimeType(fileType) || (uri.path?.endsWith("txt") == true && isFileXml(uri)) if (isXml) { + activity.toast(R.string.importing) getInputStreamFromUri(uri)!!.importXml() } else { importJson(uri) From b135263fa697880e3796218a6581dc3e78d46402 Mon Sep 17 00:00:00 2001 From: VfBFan Date: Sun, 16 Jul 2023 18:58:17 +0000 Subject: [PATCH 16/30] Translated using Weblate (German) Currently translated at 100.0% (91 of 91 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/de/ --- app/src/main/res/values-de/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index ee2b9d24..117a036f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -81,7 +81,7 @@ %d Nachrichten - Keyword + Schlüsselwort Blocked keywords Manage blocked keywords You are not blocking any keywords. You may add keywords here to block all messages containing them. @@ -128,4 +128,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From 68d88e97d064556246f5b40bf40f0cfb668952f0 Mon Sep 17 00:00:00 2001 From: VfBFan Date: Mon, 17 Jul 2023 10:18:17 +0000 Subject: [PATCH 17/30] Translated using Weblate (German) Currently translated at 100.0% (91 of 91 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/de/ --- app/src/main/res/values-de/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 117a036f..6c33ffcd 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -47,11 +47,11 @@ Nachricht aktualisieren Jetzt senden - Message details - Sender - Receiver - Sent at - Received at + Nachrichtendetails + Absender + Empfänger + Gesendet am + Empfangen am Empfangene SMS Neue Nachricht @@ -82,10 +82,10 @@ Schlüsselwort - Blocked keywords - Manage blocked keywords - You are not blocking any keywords. You may add keywords here to block all messages containing them. - Add a blocked keyword + Blockierte Schlüsselwörter + Blockierte Schlüsselwörter verwalten + Du hast keine Schlüsselwörter blockiert. Du kannst hier Schlüsselwörter hinzufügen, um alle Nachrichten zu blockieren, die sie enthalten. + Ein zu blockierendes Schlüsselwort hinzufügen Sichtbarkeit von Benachrichtigungen auf dem Sperrbildschirm Absender und Nachricht Nur Absender From 59b927333b7d0298e5e8cf0bfb1247980a60426d Mon Sep 17 00:00:00 2001 From: abc0922001 Date: Mon, 17 Jul 2023 05:22:56 +0000 Subject: [PATCH 18/30] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (17 of 17 strings) Translation: Simple Mobile Tools/Simple SMS Messenger metadata Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger-metadata/zh_Hant/ --- .../android/zh-TW/full_description.txt | 27 +++++++++++++++++++ .../android/zh-TW/short_description.txt | 1 + fastlane/metadata/android/zh-TW/title.txt | 1 + 3 files changed, 29 insertions(+) create mode 100644 fastlane/metadata/android/zh-TW/full_description.txt create mode 100644 fastlane/metadata/android/zh-TW/short_description.txt create mode 100644 fastlane/metadata/android/zh-TW/title.txt diff --git a/fastlane/metadata/android/zh-TW/full_description.txt b/fastlane/metadata/android/zh-TW/full_description.txt new file mode 100644 index 00000000..64a2d3aa --- /dev/null +++ b/fastlane/metadata/android/zh-TW/full_description.txt @@ -0,0 +1,27 @@ +這是一個與親人保持聯繫的好方法,可以發送簡訊和多媒體簡訊。這個應用程式還能正確處理群組訊息,就像 Android 7+ 的阻擋號碼功能一樣。使用手機上的簡訊應用程式與所有聯絡人保持聯繫,分享照片、發送表情符號或者簡單問候從未如此輕鬆。您可以進行很多有趣的簡訊操作,例如靜音對話、為特定聯絡人設定特殊簡訊提示音。這個簡訊和群組訊息應用程式讓您以更有趣的方式享受每天的私人訊息和群組訊息。 + +它提供多種日期格式供您選擇,讓您在使用時感到舒適。您還可以在12小時和24小時制之間切換。這個應用程式還提供簡訊備份的靈活性,這樣您就不需要將訊息保存在任何外部設備上,也不需要使用其他硬體來進行保存。這個簡訊備份功能將幫助您高效地保存簡訊和多媒體訊息的數據,而不會給內部存儲帶來負擔。 + +與競爭相比,這個訊息應用程式的大小非常小,下載速度非常快。當您需要更換設備或遭到竊取時,簡訊備份技術非常有用。這樣,您可以使用這個訊息應用程式中的簡訊備份輕鬆檢索群組訊息和私人訊息。 + +阻擋功能能夠輕鬆防止不需要的訊息,您還可以阻擋所有非存儲聯絡人的訊息。被阻擋的號碼可以導出和導入,以便輕鬆備份。所有對話都可以輕鬆導出到文件進行簡單備份,或在設備之間遷移。 + +您還可以自定義訊息在鎖定畫面上的顯示部分。您可以選擇只顯示發送者、訊息內容,或者為增強隱私而不顯示任何內容。 + +這個訊息應用程式還提供用戶快速高效地搜索訊息的能力。不再需要滾動所有私人訊息和群組訊息對話才能找到所需的訊息。只需使用這個簡訊應用程式進行搜索,即可輕鬆獲得所需的訊息。 + +它具有原生設計和暗色主題,提供出色的用戶體驗,使用起來輕鬆自如。相比其他應用程式,缺乏網路訪問可以為您提供更多隱私、安全性和穩定性。 + +不含廣告或不必要的權限。它是完全開源的,提供可自定義的顏色。 + +請查看完整的 Simple Tools 套件: +https://www.simplemobiletools.com + +Facebook: +https://www.facebook.com/simplemobiletools + +Reddit: +https://www.reddit.com/r/SimpleMobileTools + +Telegram: +https://t.me/SimpleMobileTools diff --git a/fastlane/metadata/android/zh-TW/short_description.txt b/fastlane/metadata/android/zh-TW/short_description.txt new file mode 100644 index 00000000..3ac72f41 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/short_description.txt @@ -0,0 +1 @@ +Android 上的簡訊 (SMS) 和多媒體簡訊 (MMS) 應用程式,能快速發送訊息,介面美觀 diff --git a/fastlane/metadata/android/zh-TW/title.txt b/fastlane/metadata/android/zh-TW/title.txt new file mode 100644 index 00000000..0b5383a9 --- /dev/null +++ b/fastlane/metadata/android/zh-TW/title.txt @@ -0,0 +1 @@ +簡易簡訊 From dac1bced86a52e5684eefdf46cace1fd7e6d1c7c Mon Sep 17 00:00:00 2001 From: VfBFan Date: Thu, 20 Jul 2023 06:52:49 +0000 Subject: [PATCH 19/30] Translated using Weblate (German) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/de/ --- app/src/main/res/values-de/strings.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 6c33ffcd..e0d82f23 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -59,17 +59,17 @@ Als ungelesen markieren Ich - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + Dearchivieren + Alle archivierten Unterhaltungen löschen + Archiv + Archivierte Unterhaltungen anzeigen + Archivieren + Es wurden keine archivierten Unterhaltungen gefunden + Das Archiv wurde erfolgreich geleert + Das Archiv wirklich leeren\? Alle archivierten Unterhaltungen sind dann unwiederbringlich gelöscht. Sollen wirklich alle Nachrichten dieser Unterhaltung gelöscht werden\? - Are you sure you want to archive %s? + %s wirklich archivieren\? %d Unterhaltung From 690d4aca301758bb3bf8734c153b699f0bea7e53 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Wed, 19 Jul 2023 16:05:10 +0000 Subject: [PATCH 20/30] Translated using Weblate (Dutch) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/nl/ --- app/src/main/res/values-nl/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index fe31236d..90a3c782 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -59,17 +59,17 @@ Als ongelezen markeren Ik - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + Herstellen + Alle gearchiveerde gesprekken verwijderen + Archief + Gearchiveerde gesprekken tonen + Archiveren + Geen gearchiveerde gesprekken gevonden + Archief is gewist + Het archief wissen\? Alle gearchiveerde gesprekken zullen permanent verwijderd worden. Alle berichten in dit gesprek verwijderen\? - Are you sure you want to archive %s? + %s archiveren\? %d gesprek @@ -128,4 +128,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From 661293be41c668c7801dce60bc8231d1dd334ba1 Mon Sep 17 00:00:00 2001 From: Agnieszka C Date: Wed, 19 Jul 2023 15:09:53 +0000 Subject: [PATCH 21/30] Translated using Weblate (Polish) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/pl/ --- app/src/main/res/values-pl/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index eabbbf34..7a64c240 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -61,17 +61,17 @@ Oznacz jako nieprzeczytane Ja - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + Cofnij archiwizację + Usuń wszystkie zarchiwizowane rozmowy + Archiwum + Pokaż zarchiwizowane rozmowy + Zarchiwizuj + Nie znaleziono zarchiwizowanych rozmów + Archiwum zostało opróżnione + Czy opróżnić archiwum\? Wszystkie zarchiwizowane rozmowy zostaną utracone bezpowrotnie. Czy usunąć wszystkie wiadomości z tej rozmowy\? - Are you sure you want to archive %s? + Czy zarchiwizować %s\? %d rozmowę @@ -134,4 +134,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From b92d85a0b6391998c4056ac70ea4dacadc27fd73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Wed, 19 Jul 2023 16:08:50 +0000 Subject: [PATCH 22/30] Translated using Weblate (Turkish) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/tr/ --- app/src/main/res/values-tr/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 9dfd7924..d1780fda 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -59,17 +59,17 @@ Okunmadı olarak işaretle Ben - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + Arşivden çıkar + Arşivlenen tüm görüşmeleri sil + Arşiv + Arşivlenen görüşmeleri göster + Arşiv + Arşivlenen görüşme bulunamadı + Arşiv başarıyla boşaltıldı + Arşivi boşaltmak istediğinizden emin misiniz\? Arşivlenen tüm görüşmeler kalıcı olarak kaybolacak. Bu görüşmenin tüm mesajlarını silmek istediğinizden emin misiniz\? - Are you sure you want to archive %s? + %s arşivlemek istediğinizden emin misiniz\? %d görüşme @@ -128,4 +128,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From e09de4d3346e8afdc22df538ea465bad0d114be9 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 20 Jul 2023 00:07:59 +0000 Subject: [PATCH 23/30] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/zh_Hans/ --- app/src/main/res/values-zh-rCN/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index c01af643..ef44420b 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -58,17 +58,17 @@ 标记为未读 自己 - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + 解压缩 + 删除所有已归档对话 + 归档 + 显示已归档对话 + 归档 + 尚未找到已归档对话 + 已成功清空归档 + 你确定要清空归档吗?所有已归档对话将永久丢失。 您确定要删除此对话的所有消息吗\? - Are you sure you want to archive %s? + 你确定要归档 %s 吗? %d 个对话 @@ -125,4 +125,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From 543050b9d4fbc03d0df2804fe90f63ff29b9b12b Mon Sep 17 00:00:00 2001 From: Rex_sa Date: Thu, 20 Jul 2023 00:24:32 +0000 Subject: [PATCH 24/30] Translated using Weblate (Arabic) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/ar/ --- app/src/main/res/values-ar/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 08100068..2a9569d1 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -63,17 +63,17 @@ وضع علامة كغير مقروءة Me - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + إلغاء الأرشفة + حذف جميع المحادثات المؤرشفة + أرشيف + إظهار المحادثات المؤرشفة + أرشيف + لم يتم العثور على محادثات مؤرشفة + تم إفراغ الأرشيف بنجاح + هل أنت متأكد من أنك تريد إفراغ الأرشيف؟ ستفقد جميع المحادثات المؤرشفة نهائيا. هل أنت متأكد أنك تريد حذف كافة رسائل هذه المحادثة؟ - Are you sure you want to archive %s? + هل أنت متأكد من أنك تريد أرشفة %s؟ محادثة %d @@ -140,4 +140,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From 264745c216ae113b82a9a69641ee1f3d4858177c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 20 Jul 2023 08:53:30 +0000 Subject: [PATCH 25/30] Translated using Weblate (Estonian) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/et/ --- app/src/main/res/values-et/strings.xml | 62 +++++++++++++------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index ebbf9b8f..b53d4e90 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -1,7 +1,7 @@ - Lihtne SMS Sõnumitooja - SMS Sõnumitooja + Lihtne SMS sõnumiklient + SMS sõnumid Kirjuta sõnum… Sõnum ei ole saadetud Saamata. Uuesti saatmiseks puuduta. @@ -16,7 +16,7 @@ Sõnumi saatja ei toeta vastuste võimalust Kavand Saadame… - Kinnitage ülaossa + Kinnita ülaossa Eemalda kinnitus Edasta Pildi muutmine valitud suurusesse ei õnnestu @@ -25,7 +25,7 @@ ja %d muud - ja %d teised + ja %d muud Uus vestlus @@ -48,10 +48,10 @@ Saada kohe Message details - Sender - Receiver - Sent at - Received at + Saatja + Saaja + Saatmise aeg + Saabumise aeg Vastuvõetud SMS Uus sõnum @@ -59,17 +59,17 @@ Märgi mitteloetuks Mina - Unarchive - Delete all archived conversations - Archive - Show archived conversations - Archive - No archived conversations have been found - The archive has been emptied successfully - Are you sure you want to empty the archive? All archived conversations will be permanently lost. + Eemalda arhiivist + Kustuta kõik arhiveeritud vestlused + Vestluste arhiiv + Näita arhiveeritud vestlusi + Arhiiv + Arhiveeritud vestlusi ei leidu + Arhiiv on edukalt tühjendatud + Kas kindlasti soovid arhiivi tühjendada\? Kõik arhiveeritud vestlused lähevad jäädavalt kaotsi. Kas oled kindel, et soovid kustutada kõik selle vestluse sõnumid\? - Are you sure you want to archive %s? + Kas sa oled kindel, et soovid lisada „%s“ arhiivi\? %d vestlus @@ -78,14 +78,14 @@ %d sõnum - %d sõnumeid + %d sõnumit - Keyword - Blocked keywords - Manage blocked keywords - You are not blocking any keywords. You may add keywords here to block all messages containing them. - Add a blocked keyword + Märksõna + Blokeeritud märksõnad + Halda blokeeritud märksõnu + Sa hetkel ei blokeeri ühtegi märksõna. Võid siia lisada märksõnu, et blokeerida kõik neid sisaldavad sõnumid. + Lisa blokeeritud märksõna Teavituse nähtavus lukustusvaates Saatja ja sõnum Ainult saatja @@ -96,15 +96,15 @@ Piirangut ei ole Väljuvad sõnumid Saada rühmasõnumid MMS-sõnumitena - Pikkade sõnumite saatmine MMS-ina + Saada pikad sõnumid MMS-ina Sõnumid - Sõnumite eksportimine - Ekspordi SMS - Ekspordi MMS - Sõnumite importimine - Impordi SMS - Impordi MMS + Ekspordi sõnumid + Ekspordi tekstisõnumid + Ekspordi MMS-sõnumid + Impordi sõnumid + Impordi tekstisõnumid + Impordi MMS-sõnumid Palun vali vähemalt üks kirje Kui number on sisestamata, siis sõnumit saata ei saa @@ -128,4 +128,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From 159e73ecc93a42265dee5dc009179f3e46ef775f Mon Sep 17 00:00:00 2001 From: VfBFan Date: Thu, 20 Jul 2023 06:53:08 +0000 Subject: [PATCH 26/30] Translated using Weblate (German) Currently translated at 100.0% (17 of 17 strings) Translation: Simple Mobile Tools/Simple SMS Messenger metadata Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger-metadata/de/ --- fastlane/metadata/android/de-DE/full_description.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/metadata/android/de-DE/full_description.txt b/fastlane/metadata/android/de-DE/full_description.txt index 96501b84..5a45b832 100644 --- a/fastlane/metadata/android/de-DE/full_description.txt +++ b/fastlane/metadata/android/de-DE/full_description.txt @@ -1,10 +1,10 @@ -Eine großartige Möglichkeit, mit Ihren Verwandten in Kontakt zu bleiben, indem Sie sowohl SMS- als auch MMS-Nachrichten senden. Die App verarbeitet auch Gruppen-Messaging ordnungsgemäß, genau wie das Blockieren von Nummern von Android 7+. Bleiben Sie mit allen Ihren Kontakten über die Messaging-App auf Ihrem Telefon in Kontakt. Es war noch nie einfacher, Fotos zu teilen, Emojis zu senden oder einfach nur schnell Hallo zu sagen. Mit Ihren Nachrichten können Sie so viel tun, z. B. Konversationen stummschalten oder bestimmten Kontakten spezielle Nachrichtentöne zuweisen. Mit dieser SMS- und Gruppen-Messaging-App können Sie die täglichen privaten Nachrichten und Gruppen-Nachrichten auf unterhaltsame Weise genießen. +Eine großartige Möglichkeit, mit Ihren Verwandten in Kontakt zu bleiben, indem Sie sowohl SMS- als auch MMS-Nachrichten senden. Die App verarbeitet auch Gruppen-Messaging ordnungsgemäß, genau wie das Blockieren von Nummern von Android 7+. Bleiben Sie mit allen Ihren Kontakten über die Messaging-App auf Ihrem Telefon in Kontakt. Es war noch nie einfacher, Fotos zu teilen, Emojis zu senden oder einfach nur schnell Hallo zu sagen. Mit Ihren Nachrichten können Sie so viel tun, z. B. Unterhaltungen stummschalten oder bestimmten Kontakten spezielle Nachrichtentöne zuweisen. Mit dieser SMS- und Gruppen-Messaging-App können Sie die täglichen privaten Nachrichten und Gruppen-Nachrichten auf unterhaltsame Weise genießen. Es bietet viele Datumsformate zur Auswahl, damit Sie sich bei der Verwendung wohl fühlen. Sie können auch zwischen dem 12- und 24-Stunden-Zeitformat wechseln. Diese App bietet Ihnen auch die Flexibilität der SMS-Sicherung. Auf diese Weise müssen Sie die Nachrichten nicht auf einem externen Gerät speichern oder andere Hardware zum Speichern verwenden. Mit dieser SMS-Sicherungsfunktion können Sie Textnachrichten und MMS-Daten effizient speichern, ohne den internen Speicher zu belasten. Diese Messaging-App hat im Vergleich zur Konkurrenz eine wirklich winzige App-Größe, wodurch sie wirklich schnell heruntergeladen werden kann. Die SMS-Sicherungstechnik ist hilfreich, wenn Sie Ihr Gerät wechseln müssen oder es gestohlen wird. Auf diese Weise können Sie die Textnachricht sowohl aus Gruppennachrichten als auch aus privaten Nachrichten abrufen, indem Sie die SMS-Sicherung in dieser Messaging-App verwenden. -Die Blockierungsfunktion hilft, unerwünschte Nachrichten leicht zu verhindern, Sie können auch alle Nachrichten von nicht gespeicherten Kontakten blockieren. Blockierte Nummern können zur einfachen Sicherung sowohl exportiert als auch importiert werden. Alle Konversationen können einfach in eine Datei exportiert werden, um auch ein einfaches Backup zu erstellen oder zwischen Geräten zu migrieren. +Die Blockierungsfunktion hilft, unerwünschte Nachrichten leicht zu verhindern, Sie können auch alle Nachrichten von nicht gespeicherten Kontakten blockieren. Blockierte Nummern können zur einfachen Sicherung sowohl exportiert als auch importiert werden. Alle Unterhaltungen können einfach in eine Datei exportiert werden, um auch ein einfaches Backup zu erstellen oder zwischen Geräten zu migrieren. Sie können auch anpassen, welcher Teil der Nachricht auf dem Sperrbildschirm sichtbar ist. Sie können wählen, ob nur der Absender angezeigt werden soll, die Nachricht oder nichts für mehr Privatsphäre. From d0fc0547748a9391a2d8ec37deb1d06b3286cf69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Thu, 20 Jul 2023 08:52:53 +0000 Subject: [PATCH 27/30] Translated using Weblate (Estonian) Currently translated at 100.0% (17 of 17 strings) Translation: Simple Mobile Tools/Simple SMS Messenger metadata Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger-metadata/et/ --- fastlane/metadata/android/et/title.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/et/title.txt b/fastlane/metadata/android/et/title.txt index 88394de0..05814411 100644 --- a/fastlane/metadata/android/et/title.txt +++ b/fastlane/metadata/android/et/title.txt @@ -1 +1 @@ -Lihtne SMS Sõnumitooja +Lihtne SMS sõnumiklient From dc093522131277fc61a1493de9dbe8e77ca82412 Mon Sep 17 00:00:00 2001 From: solokot Date: Sat, 22 Jul 2023 16:45:23 +0000 Subject: [PATCH 28/30] Translated using Weblate (Russian) Currently translated at 100.0% (100 of 100 strings) Translation: Simple Mobile Tools/Simple SMS Messenger Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-sms-messenger/ru/ --- app/src/main/res/values-ru/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 842108cc..d95f4e1d 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -61,11 +61,11 @@ Не прочитано Я - Unarchive + Разархивировать Delete all archived conversations Archive Show archived conversations - Archive + Архивировать No archived conversations have been found The archive has been emptied successfully Are you sure you want to empty the archive? All archived conversations will be permanently lost. @@ -134,4 +134,4 @@ Haven't found some strings? There's more at https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res --> - + \ No newline at end of file From 014ac2a4cff3a1329f62479e2e45c1f0ef957ba0 Mon Sep 17 00:00:00 2001 From: merkost Date: Mon, 24 Jul 2023 13:40:38 +1000 Subject: [PATCH 29/30] Added invalid_file_format toast on XML importing --- .../smsmessenger/helpers/MessagesImporter.kt | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt index e9a70bf8..af95f391 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/helpers/MessagesImporter.kt @@ -94,48 +94,52 @@ class MessagesImporter(private val activity: SimpleActivity) { } private fun InputStream.importXml() { - bufferedReader().use { reader -> - val xmlParser = Xml.newPullParser().apply { - setInput(reader) - } - - xmlParser.nextTag() - xmlParser.require(XmlPullParser.START_TAG, null, "smses") - - var depth = 1 - while (depth != 0) { - when (xmlParser.next()) { - XmlPullParser.END_TAG -> depth-- - XmlPullParser.START_TAG -> depth++ + try { + bufferedReader().use { reader -> + val xmlParser = Xml.newPullParser().apply { + setInput(reader) } - if (xmlParser.eventType != XmlPullParser.START_TAG) { - continue - } + xmlParser.nextTag() + xmlParser.require(XmlPullParser.START_TAG, null, "smses") - try { - if (xmlParser.name == "sms") { - if (config.importSms) { - val message = xmlParser.readSms() - messageWriter.writeSmsMessage(message) - messagesImported++ + var depth = 1 + while (depth != 0) { + when (xmlParser.next()) { + XmlPullParser.END_TAG -> depth-- + XmlPullParser.START_TAG -> depth++ + } + + if (xmlParser.eventType != XmlPullParser.START_TAG) { + continue + } + + try { + if (xmlParser.name == "sms") { + if (config.importSms) { + val message = xmlParser.readSms() + messageWriter.writeSmsMessage(message) + messagesImported++ + } else { + xmlParser.skip() + } } else { xmlParser.skip() } - } else { - xmlParser.skip() + } catch (e: Exception) { + activity.showErrorToast(e) + messagesFailed++ } - } catch (e: Exception) { - activity.showErrorToast(e) - messagesFailed++ } + refreshMessages() } - refreshMessages() - } - when { - messagesFailed > 0 && messagesImported > 0 -> activity.toast(R.string.importing_some_entries_failed) - messagesFailed > 0 -> activity.toast(R.string.importing_failed) - else -> activity.toast(R.string.importing_successful) + when { + messagesFailed > 0 && messagesImported > 0 -> activity.toast(R.string.importing_some_entries_failed) + messagesFailed > 0 -> activity.toast(R.string.importing_failed) + else -> activity.toast(R.string.importing_successful) + } + } catch (_: Exception) { + activity.toast(R.string.invalid_file_format) } } From deecd786507b91e1661043384db8395f79abf9a1 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Mon, 24 Jul 2023 10:55:10 +0200 Subject: [PATCH 30/30] minor code style update --- .../smsmessenger/dialogs/ExportMessagesDialog.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt index d694b313..b25556e0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/ExportMessagesDialog.kt @@ -10,7 +10,6 @@ import kotlinx.android.synthetic.main.dialog_export_messages.view.export_message import kotlinx.android.synthetic.main.dialog_export_messages.view.export_mms_checkbox import kotlinx.android.synthetic.main.dialog_export_messages.view.export_sms_checkbox - class ExportMessagesDialog( private val activity: SimpleActivity, private val callback: (fileName: String) -> Unit, @@ -40,7 +39,6 @@ class ExportMessagesDialog( filename.isAValidFilename() -> { callback(filename) alertDialog.dismiss() - } else -> activity.toast(R.string.invalid_name)