From 958644b2900570501afeec051b657eb2b59951fa Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Tue, 30 Jan 2024 15:42:42 +0300 Subject: [PATCH 1/3] FEATURE: Import and export blocked keywords --- .../ManageBlockedKeywordsActivity.kt | 164 +++++++++++++++++- .../dialogs/ExportBlockedKeywordsDialog.kt | 71 ++++++++ .../helpers/BlockedKeywordsExporter.kt | 29 ++++ .../helpers/BlockedKeywordsImporter.kt | 37 ++++ .../org/fossify/messages/helpers/Config.kt | 5 + .../org/fossify/messages/helpers/Constants.kt | 3 + .../layout/dialog_export_blocked_keywords.xml | 50 ++++++ .../res/menu/menu_add_blocked_keyword.xml | 8 + app/src/main/res/values/strings.xml | 3 + 9 files changed, 365 insertions(+), 5 deletions(-) create mode 100644 app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt create mode 100644 app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsExporter.kt create mode 100644 app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsImporter.kt create mode 100644 app/src/main/res/layout/dialog_export_blocked_keywords.xml diff --git a/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt b/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt index a294acc0..f8270e61 100644 --- a/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt +++ b/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt @@ -1,21 +1,36 @@ package org.fossify.messages.activities +import android.app.Activity +import android.content.ActivityNotFoundException +import android.content.Intent +import android.net.Uri import android.os.Bundle +import android.widget.Toast import org.fossify.commons.activities.BaseSimpleActivity +import org.fossify.commons.dialogs.ExportBlockedNumbersDialog +import org.fossify.commons.dialogs.FilePickerDialog import org.fossify.commons.extensions.* -import org.fossify.commons.helpers.APP_ICON_IDS -import org.fossify.commons.helpers.APP_LAUNCHER_NAME -import org.fossify.commons.helpers.NavigationIcon -import org.fossify.commons.helpers.ensureBackgroundThread +import org.fossify.commons.helpers.* import org.fossify.commons.interfaces.RefreshRecyclerViewListener import org.fossify.messages.R import org.fossify.messages.databinding.ActivityManageBlockedKeywordsBinding import org.fossify.messages.dialogs.AddBlockedKeywordDialog +import org.fossify.messages.dialogs.ExportBlockedKeywordsDialog import org.fossify.messages.dialogs.ManageBlockedKeywordsAdapter import org.fossify.messages.extensions.config import org.fossify.messages.extensions.toArrayList +import org.fossify.messages.helpers.BlockedKeywordsExporter +import org.fossify.messages.helpers.BlockedKeywordsImporter +import java.io.FileOutputStream +import java.io.OutputStream class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewListener { + + private companion object { + private const val PICK_IMPORT_SOURCE_INTENT = 11 + private const val PICK_EXPORT_FILE_INTENT = 21 + } + override fun getAppIconIDs() = intent.getIntegerArrayListExtra(APP_ICON_IDS) ?: ArrayList() override fun getAppLauncherName() = intent.getStringExtra(APP_LAUNCHER_NAME) ?: "" @@ -60,11 +75,150 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL true } + R.id.export_blocked_keywords -> { + tryExportBlockedNumbers() + true + } + + R.id.import_blocked_keywords -> { + tryImportBlockedKeywords() + true + } + else -> false } } } + override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { + super.onActivityResult(requestCode, resultCode, resultData) + when { + requestCode == PICK_IMPORT_SOURCE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null -> { + tryImportBlockedKeywordsFromFile(resultData.data!!) + } + + requestCode == PICK_EXPORT_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null -> { + val outputStream = contentResolver.openOutputStream(resultData.data!!) + exportBlockedKeywordsTo(outputStream) + } + } + } + + + private fun tryImportBlockedKeywords() { + if (isQPlus()) { + Intent(Intent.ACTION_GET_CONTENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "text/plain" + + try { + startActivityForResult(this, PICK_IMPORT_SOURCE_INTENT) + } catch (e: ActivityNotFoundException) { + toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG) + } catch (e: Exception) { + showErrorToast(e) + } + } + } else { + handlePermission(PERMISSION_READ_STORAGE) { isAllowed -> + if (isAllowed) { + pickFileToImportBlockedKeywords() + } + } + } + } + + private fun pickFileToImportBlockedKeywords() { + FilePickerDialog(this) { + importBlockedKeywords(it) + } + } + + private fun tryImportBlockedKeywordsFromFile(uri: Uri) { + when (uri.scheme) { + "file" -> importBlockedKeywords(uri.path!!) + "content" -> { + val tempFile = getTempFile("blocked", "blocked_keywords.txt") + if (tempFile == null) { + toast(org.fossify.commons.R.string.unknown_error_occurred) + return + } + + try { + val inputStream = contentResolver.openInputStream(uri) + val out = FileOutputStream(tempFile) + inputStream!!.copyTo(out) + importBlockedKeywords(tempFile.absolutePath) + } catch (e: Exception) { + showErrorToast(e) + } + } + + else -> toast(org.fossify.commons.R.string.invalid_file_format) + } + } + + private fun importBlockedKeywords(path: String) { + ensureBackgroundThread { + val result = BlockedKeywordsImporter(this).importBlockedKeywords(path) + toast( + when (result) { + BlockedKeywordsImporter.ImportResult.IMPORT_OK -> org.fossify.commons.R.string.importing_successful + BlockedKeywordsImporter.ImportResult.IMPORT_FAIL -> org.fossify.commons.R.string.no_items_found + } + ) + updateBlockedKeywords() + } + } + + private fun exportBlockedKeywordsTo(outputStream: OutputStream?) { + ensureBackgroundThread { + val blockedKeywords = config.blockedKeywords.toArrayList() + if (blockedKeywords.isEmpty()) { + toast(org.fossify.commons.R.string.no_entries_for_exporting) + } else { + BlockedKeywordsExporter.exportBlockedKeywords(blockedKeywords, outputStream) { + toast( + when (it) { + ExportResult.EXPORT_OK -> org.fossify.commons.R.string.exporting_successful + else -> org.fossify.commons.R.string.exporting_failed + } + ) + } + } + } + } + + private fun tryExportBlockedNumbers() { + if (isQPlus()) { + ExportBlockedKeywordsDialog(this, config.lastBlockedKeywordExportPath, true) { file -> + Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + type = "text/plain" + putExtra(Intent.EXTRA_TITLE, file.name) + addCategory(Intent.CATEGORY_OPENABLE) + + try { + startActivityForResult(this, PICK_EXPORT_FILE_INTENT) + } catch (e: ActivityNotFoundException) { + toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG) + } catch (e: Exception) { + showErrorToast(e) + } + } + } + } else { + handlePermission(PERMISSION_WRITE_STORAGE) { isAllowed -> + if (isAllowed) { + ExportBlockedNumbersDialog(this, config.lastBlockedKeywordExportPath, false) { file -> + getFileOutputStream(file.toFileDirItem(this), true) { out -> + exportBlockedKeywordsTo(out) + } + } + } + } + } + } + override fun refreshItems() { updateBlockedKeywords() } @@ -85,7 +239,7 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL } } - private fun addOrEditBlockedKeyword(keyword: String? = null) { + fun addOrEditBlockedKeyword(keyword: String? = null) { AddBlockedKeywordDialog(this, keyword) { updateBlockedKeywords() } diff --git a/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt b/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt new file mode 100644 index 00000000..a05e2b94 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt @@ -0,0 +1,71 @@ +package org.fossify.messages.dialogs + +import androidx.appcompat.app.AlertDialog +import org.fossify.commons.activities.BaseSimpleActivity +import org.fossify.commons.dialogs.FilePickerDialog +import org.fossify.commons.extensions.* +import org.fossify.commons.helpers.ensureBackgroundThread +import org.fossify.messages.R +import org.fossify.messages.databinding.DialogExportBlockedKeywordsBinding +import org.fossify.messages.extensions.config +import org.fossify.messages.helpers.BLOCKED_KEYWORDS_EXPORT_EXTENSION +import java.io.File + +class ExportBlockedKeywordsDialog( + val activity: BaseSimpleActivity, + val path: String, + val hidePath: Boolean, + callback: (file: File) -> Unit, +) { + private var realPath = path.ifEmpty { activity.internalStoragePath } + private val config = activity.config + + init { + val view = DialogExportBlockedKeywordsBinding.inflate(activity.layoutInflater, null, false).apply { + exportBlockedKeywordsFolder.text = activity.humanizePath(realPath) + exportBlockedKeywordsFilename.setText("${activity.getString(R.string.blocked_keywords)}_${activity.getCurrentFormattedDateTime()}") + + if (hidePath) { + exportBlockedKeywordsFolderLabel.beGone() + exportBlockedKeywordsFolder.beGone() + } else { + exportBlockedKeywordsFolder.setOnClickListener { + FilePickerDialog(activity, realPath, false, showFAB = true) { + exportBlockedKeywordsFolder.text = activity.humanizePath(it) + realPath = it + } + } + } + } + + activity.getAlertDialogBuilder() + .setPositiveButton(org.fossify.commons.R.string.ok, null) + .setNegativeButton(org.fossify.commons.R.string.cancel, null) + .apply { + activity.setupDialogStuff(view.root, this, R.string.export_blocked_keywords) { alertDialog -> + alertDialog.showKeyboard(view.exportBlockedKeywordsFilename) + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { + val filename = view.exportBlockedKeywordsFilename.value + when { + filename.isEmpty() -> activity.toast(org.fossify.commons.R.string.empty_name) + filename.isAValidFilename() -> { + val file = File(realPath, "$filename$BLOCKED_KEYWORDS_EXPORT_EXTENSION") + if (!hidePath && file.exists()) { + activity.toast(org.fossify.commons.R.string.name_taken) + return@setOnClickListener + } + + ensureBackgroundThread { + config.lastBlockedKeywordExportPath = file.absolutePath.getParentPath() + callback(file) + alertDialog.dismiss() + } + } + + else -> activity.toast(org.fossify.commons.R.string.invalid_name) + } + } + } + } + } +} diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsExporter.kt b/app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsExporter.kt new file mode 100644 index 00000000..880b43b1 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsExporter.kt @@ -0,0 +1,29 @@ +package org.fossify.messages.helpers + +import org.fossify.commons.helpers.ExportResult +import java.io.OutputStream + +object BlockedKeywordsExporter { + + fun exportBlockedKeywords( + blockedKeywords: ArrayList, + outputStream: OutputStream?, + callback: (result: ExportResult) -> Unit, + ) { + if (outputStream == null) { + callback.invoke(ExportResult.EXPORT_FAIL) + return + } + + try { + outputStream.bufferedWriter().use { out -> + out.write(blockedKeywords.joinToString(BLOCKED_KEYWORDS_EXPORT_DELIMITER) { + it + }) + } + callback.invoke(ExportResult.EXPORT_OK) + } catch (e: Exception) { + callback.invoke(ExportResult.EXPORT_FAIL) + } + } +} diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsImporter.kt b/app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsImporter.kt new file mode 100644 index 00000000..d3ddc348 --- /dev/null +++ b/app/src/main/kotlin/org/fossify/messages/helpers/BlockedKeywordsImporter.kt @@ -0,0 +1,37 @@ +package org.fossify.messages.helpers + +import android.app.Activity +import org.fossify.commons.extensions.showErrorToast +import org.fossify.messages.extensions.config + +import java.io.File + +class BlockedKeywordsImporter( + private val activity: Activity, +) { + enum class ImportResult { + IMPORT_FAIL, IMPORT_OK + } + + fun importBlockedKeywords(path: String): ImportResult { + return try { + val inputStream = File(path).inputStream() + val keywords = inputStream.bufferedReader().use { + val content = it.readText().trimEnd().split(BLOCKED_KEYWORDS_EXPORT_DELIMITER) + content + } + if (keywords.isNotEmpty()) { + keywords.forEach { keyword: String -> + activity.config.addBlockedKeyword(keyword) + } + ImportResult.IMPORT_OK + } else { + ImportResult.IMPORT_FAIL + } + + } catch (e: Exception) { + activity.showErrorToast(e) + ImportResult.IMPORT_FAIL + } + } +} diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt b/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt index 8f2dcb48..f636525d 100644 --- a/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt +++ b/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt @@ -2,6 +2,7 @@ package org.fossify.messages.helpers import android.content.Context import org.fossify.commons.helpers.BaseConfig +import org.fossify.commons.helpers.LAST_BLOCKED_NUMBERS_EXPORT_PATH import org.fossify.messages.extensions.getDefaultKeyboardHeight import org.fossify.messages.models.Conversation @@ -127,4 +128,8 @@ class Config(context: Context) : BaseConfig(context) { fun removeCustomNotificationsByThreadId(threadId: Long) { customNotifications = customNotifications.minus(threadId.toString()) } + + var lastBlockedKeywordExportPath: String + get() = prefs.getString(LAST_BLOCKED_KEYWORD_EXPORT_PATH, "")!! + set(lastBlockedNumbersExportPath) = prefs.edit().putString(LAST_BLOCKED_KEYWORD_EXPORT_PATH, lastBlockedNumbersExportPath).apply() } diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt index 1c4cb454..01630cbd 100644 --- a/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt @@ -26,6 +26,9 @@ const val SEND_GROUP_MESSAGE_MMS = "send_group_message_mms" const val MMS_FILE_SIZE_LIMIT = "mms_file_size_limit" const val PINNED_CONVERSATIONS = "pinned_conversations" const val BLOCKED_KEYWORDS = "blocked_keywords" +const val BLOCKED_KEYWORDS_EXPORT_DELIMITER = "," +const val BLOCKED_KEYWORDS_EXPORT_EXTENSION = ".txt" +const val LAST_BLOCKED_KEYWORD_EXPORT_PATH = "last_blocked_keyword_export_path" const val EXPORT_SMS = "export_sms" const val EXPORT_MMS = "export_mms" const val JSON_FILE_EXTENSION = ".json" diff --git a/app/src/main/res/layout/dialog_export_blocked_keywords.xml b/app/src/main/res/layout/dialog_export_blocked_keywords.xml new file mode 100644 index 00000000..ed187263 --- /dev/null +++ b/app/src/main/res/layout/dialog_export_blocked_keywords.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_add_blocked_keyword.xml b/app/src/main/res/menu/menu_add_blocked_keyword.xml index 53c85055..555b7b3b 100644 --- a/app/src/main/res/menu/menu_add_blocked_keyword.xml +++ b/app/src/main/res/menu/menu_add_blocked_keyword.xml @@ -6,4 +6,12 @@ android:icon="@drawable/ic_plus_vector" android:title="@string/add_a_blocked_keyword" app:showAsAction="ifRoom" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a2753dff..c7a6e2d5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -106,6 +106,7 @@ Send long messages as MMS Messages + Keywords Export messages Export SMS Export MMS @@ -113,6 +114,8 @@ Import SMS Import MMS You have to select at least one item + Export blocked keywords + Import blocked keywords Can\'t send message to an empty number Unable to save message to the telephony database From c53f537b6367e231b7495bdfb6a498f46da886eb Mon Sep 17 00:00:00 2001 From: ronniedroid Date: Mon, 29 Apr 2024 12:01:17 +0300 Subject: [PATCH 2/3] switched to using ActivityResultContracts --- .../ManageBlockedKeywordsActivity.kt | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt b/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt index f8270e61..95e1fcb3 100644 --- a/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt +++ b/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt @@ -1,11 +1,11 @@ package org.fossify.messages.activities -import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri import android.os.Bundle import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.dialogs.ExportBlockedNumbersDialog import org.fossify.commons.dialogs.FilePickerDialog @@ -26,11 +26,6 @@ import java.io.OutputStream class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewListener { - private companion object { - private const val PICK_IMPORT_SOURCE_INTENT = 11 - private const val PICK_EXPORT_FILE_INTENT = 21 - } - override fun getAppIconIDs() = intent.getIntegerArrayListExtra(APP_ICON_IDS) ?: ArrayList() override fun getAppLauncherName() = intent.getStringExtra(APP_LAUNCHER_NAME) ?: "" @@ -90,17 +85,24 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL } } - override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { - super.onActivityResult(requestCode, resultCode, resultData) - when { - requestCode == PICK_IMPORT_SOURCE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null -> { - tryImportBlockedKeywordsFromFile(resultData.data!!) - } - - requestCode == PICK_EXPORT_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null -> { - val outputStream = contentResolver.openOutputStream(resultData.data!!) + private val exportActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri -> + try { + val outputStream = uri?.let { contentResolver.openOutputStream(it) } + if (outputStream != null) { exportBlockedKeywordsTo(outputStream) } + } catch (e: Exception) { + showErrorToast(e) + } + } + + private val importActivityResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> + try { + if (uri != null) { + tryImportBlockedKeywordsFromFile(uri) + } + } catch (e: Exception) { + showErrorToast(e) } } @@ -112,7 +114,7 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL type = "text/plain" try { - startActivityForResult(this, PICK_IMPORT_SOURCE_INTENT) + importActivityResultLauncher.launch(type) } catch (e: ActivityNotFoundException) { toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG) } catch (e: Exception) { @@ -198,7 +200,7 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL addCategory(Intent.CATEGORY_OPENABLE) try { - startActivityForResult(this, PICK_EXPORT_FILE_INTENT) + exportActivityResultLauncher.launch(file.name) } catch (e: ActivityNotFoundException) { toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG) } catch (e: Exception) { From 5683087ca06f80807d9d91c25ad9129f977a3266 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Wed, 25 Dec 2024 21:35:29 +0530 Subject: [PATCH 3/3] Format code --- .../ManageBlockedKeywordsActivity.kt | 78 +++++++++++++------ .../dialogs/ExportBlockedKeywordsDialog.kt | 49 ++++++++---- .../org/fossify/messages/helpers/Config.kt | 37 +++++---- .../org/fossify/messages/helpers/Constants.kt | 5 +- 4 files changed, 115 insertions(+), 54 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt b/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt index 88e15b0e..b698e126 100644 --- a/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt +++ b/app/src/main/kotlin/org/fossify/messages/activities/ManageBlockedKeywordsActivity.kt @@ -9,8 +9,24 @@ import androidx.activity.result.contract.ActivityResultContracts import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.dialogs.ExportBlockedNumbersDialog import org.fossify.commons.dialogs.FilePickerDialog -import org.fossify.commons.extensions.* -import org.fossify.commons.helpers.* +import org.fossify.commons.extensions.beVisibleIf +import org.fossify.commons.extensions.getFileOutputStream +import org.fossify.commons.extensions.getProperPrimaryColor +import org.fossify.commons.extensions.getTempFile +import org.fossify.commons.extensions.showErrorToast +import org.fossify.commons.extensions.toFileDirItem +import org.fossify.commons.extensions.toast +import org.fossify.commons.extensions.underlineText +import org.fossify.commons.extensions.updateTextColors +import org.fossify.commons.extensions.viewBinding +import org.fossify.commons.helpers.APP_ICON_IDS +import org.fossify.commons.helpers.APP_LAUNCHER_NAME +import org.fossify.commons.helpers.ExportResult +import org.fossify.commons.helpers.NavigationIcon +import org.fossify.commons.helpers.PERMISSION_READ_STORAGE +import org.fossify.commons.helpers.PERMISSION_WRITE_STORAGE +import org.fossify.commons.helpers.ensureBackgroundThread +import org.fossify.commons.helpers.isQPlus import org.fossify.commons.interfaces.RefreshRecyclerViewListener import org.fossify.messages.R import org.fossify.messages.databinding.ActivityManageBlockedKeywordsBinding @@ -45,7 +61,10 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL useTransparentNavigation = true, useTopSearchMenu = false ) - setupMaterialScrollListener(scrollingView = binding.manageBlockedKeywordsList, toolbar = binding.blockKeywordsToolbar) + setupMaterialScrollListener( + scrollingView = binding.manageBlockedKeywordsList, + toolbar = binding.blockKeywordsToolbar + ) updateTextColors(binding.manageBlockedKeywordsWrapper) binding.manageBlockedKeywordsPlaceholder2.apply { @@ -85,27 +104,28 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL } } - private val exportActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri -> - try { - val outputStream = uri?.let { contentResolver.openOutputStream(it) } - if (outputStream != null) { - exportBlockedKeywordsTo(outputStream) + private val exportActivityResultLauncher = + registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri -> + try { + val outputStream = uri?.let { contentResolver.openOutputStream(it) } + if (outputStream != null) { + exportBlockedKeywordsTo(outputStream) + } + } catch (e: Exception) { + showErrorToast(e) } - } catch (e: Exception) { - showErrorToast(e) } - } - private val importActivityResultLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> - try { - if (uri != null) { - tryImportBlockedKeywordsFromFile(uri) + private val importActivityResultLauncher = + registerForActivityResult(ActivityResultContracts.GetContent()) { uri -> + try { + if (uri != null) { + tryImportBlockedKeywordsFromFile(uri) + } + } catch (e: Exception) { + showErrorToast(e) } - } catch (e: Exception) { - showErrorToast(e) } - } - private fun tryImportBlockedKeywords() { if (isQPlus()) { @@ -202,7 +222,10 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL try { exportActivityResultLauncher.launch(file.name) } catch (e: ActivityNotFoundException) { - toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG) + toast( + org.fossify.commons.R.string.system_service_disabled, + Toast.LENGTH_LONG + ) } catch (e: Exception) { showErrorToast(e) } @@ -211,7 +234,11 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL } else { handlePermission(PERMISSION_WRITE_STORAGE) { isAllowed -> if (isAllowed) { - ExportBlockedNumbersDialog(this, config.lastBlockedKeywordExportPath, false) { file -> + ExportBlockedNumbersDialog( + this, + config.lastBlockedKeywordExportPath, + false + ) { file -> getFileOutputStream(file.toFileDirItem(this), true) { out -> exportBlockedKeywordsTo(out) } @@ -229,7 +256,12 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL ensureBackgroundThread { val blockedKeywords = config.blockedKeywords.sorted().toArrayList() runOnUiThread { - ManageBlockedKeywordsAdapter(this, blockedKeywords, this, binding.manageBlockedKeywordsList) { + ManageBlockedKeywordsAdapter( + activity = this, + blockedKeywords = blockedKeywords, + listener = this, + recyclerView = binding.manageBlockedKeywordsList + ) { addOrEditBlockedKeyword(it as String) }.apply { binding.manageBlockedKeywordsList.adapter = this @@ -241,7 +273,7 @@ class ManageBlockedKeywordsActivity : BaseSimpleActivity(), RefreshRecyclerViewL } } - fun addOrEditBlockedKeyword(keyword: String? = null) { + private fun addOrEditBlockedKeyword(keyword: String? = null) { AddBlockedKeywordDialog(this, keyword) { updateBlockedKeywords() } diff --git a/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt b/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt index a05e2b94..69a42dd1 100644 --- a/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt +++ b/app/src/main/kotlin/org/fossify/messages/dialogs/ExportBlockedKeywordsDialog.kt @@ -3,7 +3,17 @@ package org.fossify.messages.dialogs import androidx.appcompat.app.AlertDialog import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.dialogs.FilePickerDialog -import org.fossify.commons.extensions.* +import org.fossify.commons.extensions.beGone +import org.fossify.commons.extensions.getAlertDialogBuilder +import org.fossify.commons.extensions.getCurrentFormattedDateTime +import org.fossify.commons.extensions.getParentPath +import org.fossify.commons.extensions.humanizePath +import org.fossify.commons.extensions.internalStoragePath +import org.fossify.commons.extensions.isAValidFilename +import org.fossify.commons.extensions.setupDialogStuff +import org.fossify.commons.extensions.showKeyboard +import org.fossify.commons.extensions.toast +import org.fossify.commons.extensions.value import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.messages.R import org.fossify.messages.databinding.DialogExportBlockedKeywordsBinding @@ -21,42 +31,49 @@ class ExportBlockedKeywordsDialog( private val config = activity.config init { - val view = DialogExportBlockedKeywordsBinding.inflate(activity.layoutInflater, null, false).apply { - exportBlockedKeywordsFolder.text = activity.humanizePath(realPath) - exportBlockedKeywordsFilename.setText("${activity.getString(R.string.blocked_keywords)}_${activity.getCurrentFormattedDateTime()}") + val view = + DialogExportBlockedKeywordsBinding.inflate(activity.layoutInflater, null, false).apply { + exportBlockedKeywordsFolder.text = activity.humanizePath(realPath) + exportBlockedKeywordsFilename.setText("${activity.getString(R.string.blocked_keywords)}_${activity.getCurrentFormattedDateTime()}") - if (hidePath) { - exportBlockedKeywordsFolderLabel.beGone() - exportBlockedKeywordsFolder.beGone() - } else { - exportBlockedKeywordsFolder.setOnClickListener { - FilePickerDialog(activity, realPath, false, showFAB = true) { - exportBlockedKeywordsFolder.text = activity.humanizePath(it) - realPath = it + if (hidePath) { + exportBlockedKeywordsFolderLabel.beGone() + exportBlockedKeywordsFolder.beGone() + } else { + exportBlockedKeywordsFolder.setOnClickListener { + FilePickerDialog(activity, realPath, false, showFAB = true) { + exportBlockedKeywordsFolder.text = activity.humanizePath(it) + realPath = it + } } } } - } activity.getAlertDialogBuilder() .setPositiveButton(org.fossify.commons.R.string.ok, null) .setNegativeButton(org.fossify.commons.R.string.cancel, null) .apply { - activity.setupDialogStuff(view.root, this, R.string.export_blocked_keywords) { alertDialog -> + activity.setupDialogStuff( + view = view.root, + dialog = this, + titleId = R.string.export_blocked_keywords + ) { alertDialog -> alertDialog.showKeyboard(view.exportBlockedKeywordsFilename) alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { val filename = view.exportBlockedKeywordsFilename.value when { filename.isEmpty() -> activity.toast(org.fossify.commons.R.string.empty_name) filename.isAValidFilename() -> { - val file = File(realPath, "$filename$BLOCKED_KEYWORDS_EXPORT_EXTENSION") + val file = + File(realPath, "$filename$BLOCKED_KEYWORDS_EXPORT_EXTENSION") if (!hidePath && file.exists()) { activity.toast(org.fossify.commons.R.string.name_taken) return@setOnClickListener } ensureBackgroundThread { - config.lastBlockedKeywordExportPath = file.absolutePath.getParentPath() + config.lastBlockedKeywordExportPath = + file.absolutePath.getParentPath() callback(file) alertDialog.dismiss() } diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt b/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt index f636525d..29507906 100644 --- a/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt +++ b/app/src/main/kotlin/org/fossify/messages/helpers/Config.kt @@ -2,7 +2,6 @@ package org.fossify.messages.helpers import android.content.Context import org.fossify.commons.helpers.BaseConfig -import org.fossify.commons.helpers.LAST_BLOCKED_NUMBERS_EXPORT_PATH import org.fossify.messages.extensions.getDefaultKeyboardHeight import org.fossify.messages.models.Conversation @@ -19,11 +18,13 @@ class Config(context: Context) : BaseConfig(context) { var showCharacterCounter: Boolean get() = prefs.getBoolean(SHOW_CHARACTER_COUNTER, false) - set(showCharacterCounter) = prefs.edit().putBoolean(SHOW_CHARACTER_COUNTER, showCharacterCounter).apply() + set(showCharacterCounter) = prefs.edit() + .putBoolean(SHOW_CHARACTER_COUNTER, showCharacterCounter).apply() var useSimpleCharacters: Boolean get() = prefs.getBoolean(USE_SIMPLE_CHARACTERS, false) - set(useSimpleCharacters) = prefs.edit().putBoolean(USE_SIMPLE_CHARACTERS, useSimpleCharacters).apply() + set(useSimpleCharacters) = prefs.edit() + .putBoolean(USE_SIMPLE_CHARACTERS, useSimpleCharacters).apply() var sendOnEnter: Boolean get() = prefs.getBoolean(SEND_ON_ENTER, false) @@ -31,19 +32,23 @@ class Config(context: Context) : BaseConfig(context) { var enableDeliveryReports: Boolean get() = prefs.getBoolean(ENABLE_DELIVERY_REPORTS, false) - set(enableDeliveryReports) = prefs.edit().putBoolean(ENABLE_DELIVERY_REPORTS, enableDeliveryReports).apply() + set(enableDeliveryReports) = prefs.edit() + .putBoolean(ENABLE_DELIVERY_REPORTS, enableDeliveryReports).apply() var sendLongMessageMMS: Boolean get() = prefs.getBoolean(SEND_LONG_MESSAGE_MMS, false) - set(sendLongMessageMMS) = prefs.edit().putBoolean(SEND_LONG_MESSAGE_MMS, sendLongMessageMMS).apply() + set(sendLongMessageMMS) = prefs.edit().putBoolean(SEND_LONG_MESSAGE_MMS, sendLongMessageMMS) + .apply() var sendGroupMessageMMS: Boolean get() = prefs.getBoolean(SEND_GROUP_MESSAGE_MMS, false) - set(sendGroupMessageMMS) = prefs.edit().putBoolean(SEND_GROUP_MESSAGE_MMS, sendGroupMessageMMS).apply() + set(sendGroupMessageMMS) = prefs.edit() + .putBoolean(SEND_GROUP_MESSAGE_MMS, sendGroupMessageMMS).apply() var lockScreenVisibilitySetting: Int get() = prefs.getInt(LOCK_SCREEN_VISIBILITY, LOCK_SCREEN_SENDER_MESSAGE) - set(lockScreenVisibilitySetting) = prefs.edit().putInt(LOCK_SCREEN_VISIBILITY, lockScreenVisibilitySetting).apply() + set(lockScreenVisibilitySetting) = prefs.edit() + .putInt(LOCK_SCREEN_VISIBILITY, lockScreenVisibilitySetting).apply() var mmsFileSizeLimit: Long get() = prefs.getLong(MMS_FILE_SIZE_LIMIT, FILE_SIZE_600_KB) @@ -51,7 +56,8 @@ class Config(context: Context) : BaseConfig(context) { var pinnedConversations: Set get() = prefs.getStringSet(PINNED_CONVERSATIONS, HashSet())!! - set(pinnedConversations) = prefs.edit().putStringSet(PINNED_CONVERSATIONS, pinnedConversations).apply() + set(pinnedConversations) = prefs.edit() + .putStringSet(PINNED_CONVERSATIONS, pinnedConversations).apply() fun addPinnedConversationByThreadId(threadId: Long) { pinnedConversations = pinnedConversations.plus(threadId.toString()) @@ -66,7 +72,8 @@ class Config(context: Context) : BaseConfig(context) { } fun removePinnedConversations(conversations: List) { - pinnedConversations = pinnedConversations.minus(conversations.map { it.threadId.toString() }) + pinnedConversations = + pinnedConversations.minus(conversations.map { it.threadId.toString() }) } var blockedKeywords: Set @@ -111,15 +118,18 @@ class Config(context: Context) : BaseConfig(context) { var lastRecycleBinCheck: Long get() = prefs.getLong(LAST_RECYCLE_BIN_CHECK, 0L) - set(lastRecycleBinCheck) = prefs.edit().putLong(LAST_RECYCLE_BIN_CHECK, lastRecycleBinCheck).apply() + set(lastRecycleBinCheck) = prefs.edit().putLong(LAST_RECYCLE_BIN_CHECK, lastRecycleBinCheck) + .apply() var isArchiveAvailable: Boolean get() = prefs.getBoolean(IS_ARCHIVE_AVAILABLE, true) - set(isArchiveAvailable) = prefs.edit().putBoolean(IS_ARCHIVE_AVAILABLE, isArchiveAvailable).apply() + set(isArchiveAvailable) = prefs.edit().putBoolean(IS_ARCHIVE_AVAILABLE, isArchiveAvailable) + .apply() var customNotifications: Set get() = prefs.getStringSet(CUSTOM_NOTIFICATIONS, HashSet())!! - set(customNotifications) = prefs.edit().putStringSet(CUSTOM_NOTIFICATIONS, customNotifications).apply() + set(customNotifications) = prefs.edit() + .putStringSet(CUSTOM_NOTIFICATIONS, customNotifications).apply() fun addCustomNotificationsByThreadId(threadId: Long) { customNotifications = customNotifications.plus(threadId.toString()) @@ -131,5 +141,6 @@ class Config(context: Context) : BaseConfig(context) { var lastBlockedKeywordExportPath: String get() = prefs.getString(LAST_BLOCKED_KEYWORD_EXPORT_PATH, "")!! - set(lastBlockedNumbersExportPath) = prefs.edit().putString(LAST_BLOCKED_KEYWORD_EXPORT_PATH, lastBlockedNumbersExportPath).apply() + set(lastBlockedNumbersExportPath) = prefs.edit() + .putString(LAST_BLOCKED_KEYWORD_EXPORT_PATH, lastBlockedNumbersExportPath).apply() } diff --git a/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt index 01630cbd..75a0082f 100644 --- a/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/messages/helpers/Constants.kt @@ -26,8 +26,6 @@ const val SEND_GROUP_MESSAGE_MMS = "send_group_message_mms" const val MMS_FILE_SIZE_LIMIT = "mms_file_size_limit" const val PINNED_CONVERSATIONS = "pinned_conversations" const val BLOCKED_KEYWORDS = "blocked_keywords" -const val BLOCKED_KEYWORDS_EXPORT_DELIMITER = "," -const val BLOCKED_KEYWORDS_EXPORT_EXTENSION = ".txt" const val LAST_BLOCKED_KEYWORD_EXPORT_PATH = "last_blocked_keyword_export_path" const val EXPORT_SMS = "export_sms" const val EXPORT_MMS = "export_mms" @@ -92,6 +90,9 @@ const val CAPTURE_AUDIO_INTENT = 46 const val PICK_DOCUMENT_INTENT = 47 const val PICK_CONTACT_INTENT = 48 +const val BLOCKED_KEYWORDS_EXPORT_DELIMITER = "," +const val BLOCKED_KEYWORDS_EXPORT_EXTENSION = ".txt" + fun refreshMessages() { EventBus.getDefault().post(Events.RefreshMessages()) }