FEATURE: Import and export blocked keywords
This commit is contained in:
parent
0058d6c6f9
commit
958644b290
9 changed files with 365 additions and 5 deletions
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String>,
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
50
app/src/main/res/layout/dialog_export_blocked_keywords.xml
Normal file
50
app/src/main/res/layout/dialog_export_blocked_keywords.xml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/export_blocked_keywords_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/export_blocked_keywords_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_margin"
|
||||
android:paddingTop="@dimen/activity_margin"
|
||||
android:paddingRight="@dimen/activity_margin">
|
||||
|
||||
<org.fossify.commons.views.MyTextView
|
||||
android:id="@+id/export_blocked_keywords_folder_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/small_margin"
|
||||
android:text="@string/folder"
|
||||
android:textSize="@dimen/smaller_text_size" />
|
||||
|
||||
<org.fossify.commons.views.MyTextView
|
||||
android:id="@+id/export_blocked_keywords_folder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/small_margin"
|
||||
android:paddingStart="@dimen/small_margin"
|
||||
android:paddingTop="@dimen/small_margin"
|
||||
android:paddingBottom="@dimen/activity_margin" />
|
||||
|
||||
<org.fossify.commons.views.MyTextInputLayout
|
||||
android:id="@+id/export_blocked_keywords_hint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/filename_without_txt">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/export_blocked_keywords_filename"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_margin"
|
||||
android:singleLine="true"
|
||||
android:textCursorDrawable="@null"
|
||||
android:textSize="@dimen/normal_text_size" />
|
||||
|
||||
</org.fossify.commons.views.MyTextInputLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
|
@ -6,4 +6,12 @@
|
|||
android:icon="@drawable/ic_plus_vector"
|
||||
android:title="@string/add_a_blocked_keyword"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/import_blocked_keywords"
|
||||
android:title="@string/import_blocked_keywords"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/export_blocked_keywords"
|
||||
android:title="@string/export_blocked_keywords"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@
|
|||
<string name="send_long_message_mms">Send long messages as MMS</string>
|
||||
<!-- Export / Import -->
|
||||
<string name="messages">Messages</string>
|
||||
<string name="keywords">Keywords</string>
|
||||
<string name="export_messages">Export messages</string>
|
||||
<string name="export_sms">Export SMS</string>
|
||||
<string name="export_mms">Export MMS</string>
|
||||
|
|
@ -113,6 +114,8 @@
|
|||
<string name="import_sms">Import SMS</string>
|
||||
<string name="import_mms">Import MMS</string>
|
||||
<string name="no_option_selected">You have to select at least one item</string>
|
||||
<string name="export_blocked_keywords">Export blocked keywords</string>
|
||||
<string name="import_blocked_keywords">Import blocked keywords</string>
|
||||
<!-- Errors -->
|
||||
<string name="empty_destination_address">Can\'t send message to an empty number</string>
|
||||
<string name="unable_to_save_message">Unable to save message to the telephony database</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue