Rename package to org.fossify.messages

This commit is contained in:
Naveen 2024-01-18 01:05:03 +05:30
parent d71db351ca
commit e2f83f49da
No known key found for this signature in database
GPG key ID: 0E155DAD31671DA3
106 changed files with 417 additions and 418 deletions

View file

@ -0,0 +1,42 @@
package org.fossify.messages.dialogs
import androidx.appcompat.app.AlertDialog
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.commons.extensions.showKeyboard
import org.fossify.commons.extensions.value
import org.fossify.messages.databinding.DialogAddBlockedKeywordBinding
import org.fossify.messages.extensions.config
class AddBlockedKeywordDialog(val activity: BaseSimpleActivity, private val originalKeyword: String? = null, val callback: () -> Unit) {
init {
val binding = DialogAddBlockedKeywordBinding.inflate(activity.layoutInflater).apply {
if (originalKeyword != null) {
addBlockedKeywordEdittext.setText(originalKeyword)
}
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok, null)
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
.apply {
activity.setupDialogStuff(binding.root, this) { alertDialog ->
alertDialog.showKeyboard(binding.addBlockedKeywordEdittext)
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val newBlockedKeyword = binding.addBlockedKeywordEdittext.value
if (originalKeyword != null && newBlockedKeyword != originalKeyword) {
activity.config.removeBlockedKeyword(originalKeyword)
}
if (newBlockedKeyword.isNotEmpty()) {
activity.config.addBlockedKeyword(newBlockedKeyword)
}
callback()
alertDialog.dismiss()
}
}
}
}
}

View file

@ -0,0 +1,37 @@
package org.fossify.messages.dialogs
import android.app.Activity
import androidx.appcompat.app.AlertDialog
import org.fossify.commons.extensions.beGoneIf
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.messages.databinding.DialogDeleteConfirmationBinding
class DeleteConfirmationDialog(
private val activity: Activity,
private val message: String,
private val showSkipRecycleBinOption: Boolean,
private val callback: (skipRecycleBin: Boolean) -> Unit
) {
private var dialog: AlertDialog? = null
val binding = DialogDeleteConfirmationBinding.inflate(activity.layoutInflater)
init {
binding.deleteRememberTitle.text = message
binding.skipTheRecycleBinCheckbox.beGoneIf(!showSkipRecycleBinOption)
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.yes) { _, _ -> dialogConfirmed() }
.setNegativeButton(org.fossify.commons.R.string.no, null)
.apply {
activity.setupDialogStuff(binding.root, this) { alertDialog ->
dialog = alertDialog
}
}
}
private fun dialogConfirmed() {
dialog?.dismiss()
callback(binding.skipTheRecycleBinCheckbox.isChecked)
}
}

View file

@ -0,0 +1,47 @@
package org.fossify.messages.dialogs
import androidx.appcompat.app.AlertDialog
import org.fossify.commons.extensions.*
import org.fossify.messages.R
import org.fossify.messages.activities.SimpleActivity
import org.fossify.messages.databinding.DialogExportMessagesBinding
import org.fossify.messages.extensions.config
class ExportMessagesDialog(
private val activity: SimpleActivity,
private val callback: (fileName: String) -> Unit,
) {
private val config = activity.config
init {
val binding = DialogExportMessagesBinding.inflate(activity.layoutInflater).apply {
exportSmsCheckbox.isChecked = config.exportSms
exportMmsCheckbox.isChecked = config.exportMms
exportMessagesFilename.setText(
activity.getString(R.string.messages) + "_" + activity.getCurrentFormattedDateTime()
)
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok, null)
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
.apply {
activity.setupDialogStuff(binding.root, this, R.string.export_messages) { alertDialog ->
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
config.exportSms = binding.exportSmsCheckbox.isChecked
config.exportMms = binding.exportMmsCheckbox.isChecked
val filename = binding.exportMessagesFilename.value
when {
filename.isEmpty() -> activity.toast(org.fossify.commons.R.string.empty_name)
filename.isAValidFilename() -> {
callback(filename)
alertDialog.dismiss()
}
else -> activity.toast(org.fossify.commons.R.string.invalid_name)
}
}
}
}
}
}

View file

@ -0,0 +1,70 @@
package org.fossify.messages.dialogs
import androidx.appcompat.app.AlertDialog
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.commons.extensions.toast
import org.fossify.commons.helpers.ensureBackgroundThread
import org.fossify.messages.R
import org.fossify.messages.activities.SimpleActivity
import org.fossify.messages.databinding.DialogImportMessagesBinding
import org.fossify.messages.extensions.config
import org.fossify.messages.helpers.MessagesImporter
import org.fossify.messages.models.ImportResult
import org.fossify.messages.models.MessagesBackup
class ImportMessagesDialog(
private val activity: SimpleActivity,
private val messages: List<MessagesBackup>,
) {
private val config = activity.config
init {
var ignoreClicks = false
val binding = DialogImportMessagesBinding.inflate(activity.layoutInflater).apply {
importSmsCheckbox.isChecked = config.importSms
importMmsCheckbox.isChecked = config.importMms
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok, null)
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
.apply {
activity.setupDialogStuff(binding.root, this, R.string.import_messages) { alertDialog ->
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
if (ignoreClicks) {
return@setOnClickListener
}
if (!binding.importSmsCheckbox.isChecked && !binding.importMmsCheckbox.isChecked) {
activity.toast(R.string.no_option_selected)
return@setOnClickListener
}
ignoreClicks = true
activity.toast(org.fossify.commons.R.string.importing)
config.importSms = binding.importSmsCheckbox.isChecked
config.importMms = binding.importMmsCheckbox.isChecked
ensureBackgroundThread {
MessagesImporter(activity).restoreMessages(messages) {
handleParseResult(it)
alertDialog.dismiss()
}
}
}
}
}
}
private fun handleParseResult(result: ImportResult) {
activity.toast(
when (result) {
ImportResult.IMPORT_OK -> org.fossify.commons.R.string.importing_successful
ImportResult.IMPORT_PARTIAL -> org.fossify.commons.R.string.importing_some_entries_failed
ImportResult.IMPORT_FAIL -> org.fossify.commons.R.string.importing_failed
else -> org.fossify.commons.R.string.no_items_found
}
)
}
}

View file

@ -0,0 +1,20 @@
package org.fossify.messages.dialogs
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.messages.databinding.DialogInvalidNumberBinding
class InvalidNumberDialog(val activity: BaseSimpleActivity, val text: String) {
init {
val binding = DialogInvalidNumberBinding.inflate(activity.layoutInflater).apply {
dialogInvalidNumberDesc.text = text
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok) { _, _ -> { } }
.apply {
activity.setupDialogStuff(binding.root, this)
}
}
}

View file

@ -0,0 +1,148 @@
package org.fossify.messages.dialogs
import android.view.*
import android.widget.PopupMenu
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.adapters.MyRecyclerViewAdapter
import org.fossify.commons.extensions.copyToClipboard
import org.fossify.commons.extensions.getPopupMenuTheme
import org.fossify.commons.extensions.getProperTextColor
import org.fossify.commons.extensions.setupViewBackground
import org.fossify.commons.interfaces.RefreshRecyclerViewListener
import org.fossify.commons.views.MyRecyclerView
import org.fossify.messages.R
import org.fossify.messages.databinding.ItemManageBlockedKeywordBinding
import org.fossify.messages.extensions.config
class ManageBlockedKeywordsAdapter(
activity: BaseSimpleActivity, var blockedKeywords: ArrayList<String>, val listener: RefreshRecyclerViewListener?,
recyclerView: MyRecyclerView, itemClick: (Any) -> Unit
) : MyRecyclerViewAdapter(activity, recyclerView, itemClick) {
init {
setupDragListener(true)
}
override fun getActionMenuId() = R.menu.cab_blocked_keywords
override fun prepareActionMode(menu: Menu) {
menu.apply {
findItem(R.id.cab_copy_keyword).isVisible = isOneItemSelected()
}
}
override fun actionItemPressed(id: Int) {
if (selectedKeys.isEmpty()) {
return
}
when (id) {
R.id.cab_copy_keyword -> copyKeywordToClipboard()
R.id.cab_delete -> deleteSelection()
}
}
override fun getSelectableItemCount() = blockedKeywords.size
override fun getIsItemSelectable(position: Int) = true
override fun getItemSelectionKey(position: Int) = blockedKeywords.getOrNull(position)?.hashCode()
override fun getItemKeyPosition(key: Int) = blockedKeywords.indexOfFirst { it.hashCode() == key }
override fun onActionModeCreated() {}
override fun onActionModeDestroyed() {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemManageBlockedKeywordBinding.inflate(layoutInflater, parent, false)
return createViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val blockedKeyword = blockedKeywords[position]
holder.bindView(blockedKeyword, allowSingleClick = true, allowLongClick = true) { itemView, _ ->
setupView(itemView, blockedKeyword)
}
bindViewHolder(holder)
}
override fun getItemCount() = blockedKeywords.size
private fun getSelectedItems() = blockedKeywords.filter { selectedKeys.contains(it.hashCode()) }
private fun setupView(view: View, blockedKeyword: String) {
ItemManageBlockedKeywordBinding.bind(view).apply {
root.setupViewBackground(activity)
manageBlockedKeywordHolder.isSelected = selectedKeys.contains(blockedKeyword.hashCode())
manageBlockedKeywordTitle.apply {
text = blockedKeyword
setTextColor(textColor)
}
overflowMenuIcon.drawable.apply {
mutate()
setTint(activity.getProperTextColor())
}
overflowMenuIcon.setOnClickListener {
showPopupMenu(overflowMenuAnchor, blockedKeyword)
}
}
}
private fun showPopupMenu(view: View, blockedKeyword: String) {
finishActMode()
val theme = activity.getPopupMenuTheme()
val contextTheme = ContextThemeWrapper(activity, theme)
PopupMenu(contextTheme, view, Gravity.END).apply {
inflate(getActionMenuId())
setOnMenuItemClickListener { item ->
val blockedKeywordId = blockedKeyword.hashCode()
when (item.itemId) {
R.id.cab_copy_keyword -> {
executeItemMenuOperation(blockedKeywordId) {
copyKeywordToClipboard()
}
}
R.id.cab_delete -> {
executeItemMenuOperation(blockedKeywordId) {
deleteSelection()
}
}
}
true
}
show()
}
}
private fun executeItemMenuOperation(blockedKeywordId: Int, callback: () -> Unit) {
selectedKeys.add(blockedKeywordId)
callback()
selectedKeys.remove(blockedKeywordId)
}
private fun copyKeywordToClipboard() {
val selectedKeyword = getSelectedItems().firstOrNull() ?: return
activity.copyToClipboard(selectedKeyword)
finishActMode()
}
private fun deleteSelection() {
val deleteBlockedKeywords = HashSet<String>(selectedKeys.size)
val positions = getSelectedItemPositions()
getSelectedItems().forEach {
deleteBlockedKeywords.add(it)
activity.config.removeBlockedKeyword(it)
}
blockedKeywords.removeAll(deleteBlockedKeywords)
removeSelectedItems(positions)
if (blockedKeywords.isEmpty()) {
listener?.refreshItems()
}
}
}

View file

@ -0,0 +1,76 @@
package org.fossify.messages.dialogs
import android.annotation.SuppressLint
import android.telephony.SubscriptionInfo
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.dialogs.BasePropertiesDialog
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.getTimeFormat
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.messages.R
import org.fossify.messages.extensions.config
import org.fossify.messages.extensions.subscriptionManagerCompat
import org.fossify.messages.models.Message
import org.joda.time.DateTime
class MessageDetailsDialog(val activity: BaseSimpleActivity, val message: Message) : BasePropertiesDialog(activity) {
init {
@SuppressLint("MissingPermission")
val availableSIMs = activity.subscriptionManagerCompat().activeSubscriptionInfoList
addProperty(message.getSenderOrReceiverLabel(), message.getSenderOrReceiverPhoneNumbers())
if (availableSIMs.count() > 1) {
addProperty(R.string.message_details_sim, message.getSIM(availableSIMs))
}
addProperty(message.getSentOrReceivedAtLabel(), message.getSentOrReceivedAt())
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok) { _, _ -> }
.apply {
activity.setupDialogStuff(mDialogView.root, this, R.string.message_details)
}
}
private fun Message.getSenderOrReceiverLabel(): Int {
return if (isReceivedMessage()) {
R.string.message_details_sender
} else {
R.string.message_details_receiver
}
}
private fun Message.getSenderOrReceiverPhoneNumbers(): String {
return if (isReceivedMessage()) {
formatContactInfo(senderName, senderPhoneNumber)
} else {
participants.joinToString(", ") {
formatContactInfo(it.name, it.phoneNumbers.first().value)
}
}
}
private fun formatContactInfo(name: String, phoneNumber: String): String {
return if (name != phoneNumber) {
"$name ($phoneNumber)"
} else {
phoneNumber
}
}
private fun Message.getSIM(availableSIMs: List<SubscriptionInfo>): String {
return availableSIMs.firstOrNull { it.subscriptionId == subscriptionId }?.displayName?.toString()
?: activity.getString(org.fossify.commons.R.string.unknown)
}
private fun Message.getSentOrReceivedAtLabel(): Int {
return if (isReceivedMessage()) {
R.string.message_details_received_at
} else {
R.string.message_details_sent_at
}
}
private fun Message.getSentOrReceivedAt(): String {
return DateTime(date * 1000L).toString("${activity.config.dateFormat} ${activity.getTimeFormat()}")
}
}

View file

@ -0,0 +1,54 @@
package org.fossify.messages.dialogs
import android.app.Activity
import android.content.DialogInterface.BUTTON_POSITIVE
import androidx.appcompat.app.AlertDialog
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.commons.extensions.showKeyboard
import org.fossify.commons.extensions.toast
import org.fossify.messages.R
import org.fossify.messages.databinding.DialogRenameConversationBinding
import org.fossify.messages.models.Conversation
class RenameConversationDialog(
private val activity: Activity,
private val conversation: Conversation,
private val callback: (name: String) -> Unit,
) {
private var dialog: AlertDialog? = null
init {
val binding = DialogRenameConversationBinding.inflate(activity.layoutInflater).apply {
renameConvEditText.apply {
if (conversation.usesCustomTitle) {
setText(conversation.title)
}
hint = conversation.title
}
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok, null)
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
.apply {
activity.setupDialogStuff(binding.root, this, R.string.rename_conversation) { alertDialog ->
dialog = alertDialog
alertDialog.showKeyboard(binding.renameConvEditText)
alertDialog.getButton(BUTTON_POSITIVE).apply {
setOnClickListener {
val newTitle = binding.renameConvEditText.text.toString()
if (newTitle.isEmpty()) {
activity.toast(org.fossify.commons.R.string.empty_name)
return@setOnClickListener
}
callback(newTitle)
alertDialog.dismiss()
}
}
}
}
}
}

View file

@ -0,0 +1,193 @@
package org.fossify.messages.dialogs
import android.app.DatePickerDialog
import android.app.DatePickerDialog.OnDateSetListener
import android.app.TimePickerDialog
import android.app.TimePickerDialog.OnTimeSetListener
import android.text.format.DateFormat
import androidx.appcompat.app.AlertDialog
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.extensions.*
import org.fossify.messages.R
import org.fossify.messages.databinding.ScheduleMessageDialogBinding
import org.fossify.messages.extensions.config
import org.fossify.messages.extensions.roundToClosestMultipleOf
import org.joda.time.DateTime
import java.util.Calendar
class ScheduleMessageDialog(
private val activity: BaseSimpleActivity,
private var dateTime: DateTime? = null,
private val callback: (dateTime: DateTime?) -> Unit
) {
private val binding = ScheduleMessageDialogBinding.inflate(activity.layoutInflater)
private val textColor = activity.getProperTextColor()
private var previewDialog: AlertDialog? = null
private var previewShown = false
private var isNewMessage = dateTime == null
private val calendar = Calendar.getInstance()
init {
arrayOf(binding.subtitle, binding.editTime, binding.editDate).forEach {
it.setTextColor(textColor)
}
arrayOf(binding.dateImage, binding.timeImage).forEach {
it.applyColorFilter(textColor)
}
binding.editDate.setOnClickListener { showDatePicker() }
binding.editTime.setOnClickListener { showTimePicker() }
val targetDateTime = dateTime ?: DateTime.now().plusHours(1)
updateTexts(targetDateTime)
if (isNewMessage) {
showDatePicker()
} else {
showPreview()
}
}
private fun updateTexts(dateTime: DateTime) {
val dateFormat = activity.config.dateFormat
val timeFormat = activity.getTimeFormat()
binding.editDate.text = dateTime.toString(dateFormat)
binding.editTime.text = dateTime.toString(timeFormat)
}
private fun showPreview() {
if (previewShown) {
return
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok, null)
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
.apply {
previewShown = true
activity.setupDialogStuff(binding.root, this, R.string.schedule_message) { dialog ->
previewDialog = dialog
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
if (validateDateTime()) {
callback(dateTime)
dialog.dismiss()
}
}
dialog.setOnDismissListener {
previewShown = false
previewDialog = null
}
}
}
}
private fun showDatePicker() {
val year = dateTime?.year ?: calendar.get(Calendar.YEAR)
val monthOfYear = dateTime?.monthOfYear?.minus(1) ?: calendar.get(Calendar.MONTH)
val dayOfMonth = dateTime?.dayOfMonth ?: calendar.get(Calendar.DAY_OF_MONTH)
val dateSetListener = OnDateSetListener { _, y, m, d -> dateSet(y, m, d) }
DatePickerDialog(
activity, activity.getDatePickerDialogTheme(), dateSetListener, year, monthOfYear, dayOfMonth
).apply {
datePicker.minDate = System.currentTimeMillis()
show()
getButton(AlertDialog.BUTTON_NEGATIVE).apply {
text = activity.getString(org.fossify.commons.R.string.cancel)
setOnClickListener {
dismiss()
}
}
}
}
private fun showTimePicker() {
val hourOfDay = dateTime?.hourOfDay ?: getNextHour()
val minute = dateTime?.minuteOfHour ?: getNextMinute()
if (activity.config.isUsingSystemTheme) {
val timeFormat = if (DateFormat.is24HourFormat(activity)) {
TimeFormat.CLOCK_24H
} else {
TimeFormat.CLOCK_12H
}
val timePicker = MaterialTimePicker.Builder()
.setTimeFormat(timeFormat)
.setHour(hourOfDay)
.setMinute(minute)
.build()
timePicker.addOnPositiveButtonClickListener {
timeSet(timePicker.hour, timePicker.minute)
}
timePicker.show(activity.supportFragmentManager, "")
} else {
val timeSetListener = OnTimeSetListener { _, hours, minutes -> timeSet(hours, minutes) }
TimePickerDialog(
activity, activity.getDatePickerDialogTheme(), timeSetListener, hourOfDay, minute, DateFormat.is24HourFormat(activity)
).apply {
show()
getButton(AlertDialog.BUTTON_NEGATIVE).apply {
text = activity.getString(org.fossify.commons.R.string.cancel)
setOnClickListener {
dismiss()
}
}
}
}
}
private fun dateSet(year: Int, monthOfYear: Int, dayOfMonth: Int) {
if (isNewMessage) {
showTimePicker()
}
dateTime = DateTime.now()
.withDate(year, monthOfYear + 1, dayOfMonth)
.run {
if (dateTime != null) {
withTime(dateTime!!.hourOfDay, dateTime!!.minuteOfHour, 0, 0)
} else {
withTime(getNextHour(), getNextMinute(), 0, 0)
}
}
if (!isNewMessage) {
validateDateTime()
}
isNewMessage = false
updateTexts(dateTime!!)
}
private fun timeSet(hourOfDay: Int, minute: Int) {
dateTime = dateTime?.withHourOfDay(hourOfDay)?.withMinuteOfHour(minute)
if (validateDateTime()) {
updateTexts(dateTime!!)
showPreview()
} else {
showTimePicker()
}
}
private fun validateDateTime(): Boolean {
return if (dateTime?.isAfterNow == false) {
activity.toast(R.string.must_pick_time_in_the_future)
false
} else {
true
}
}
private fun getNextHour() = (calendar.get(Calendar.HOUR_OF_DAY) + 1).coerceIn(0, 23)
private fun getNextMinute() = (calendar.get(Calendar.MINUTE) + 5).roundToClosestMultipleOf(5).coerceIn(0, 59)
}

View file

@ -0,0 +1,21 @@
package org.fossify.messages.dialogs
import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.messages.databinding.DialogSelectTextBinding
// helper dialog for selecting just a part of a message, not copying the whole into clipboard
class SelectTextDialog(val activity: BaseSimpleActivity, val text: String) {
init {
val binding = DialogSelectTextBinding.inflate(activity.layoutInflater).apply {
dialogSelectTextValue.text = text
}
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok) { _, _ -> { } }
.apply {
activity.setupDialogStuff(binding.root, this)
}
}
}