diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e25bbf6b..db618e40 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -141,6 +141,12 @@ android:label="@string/contact_details" android:parentActivityName=".activities.ThreadActivity" /> + + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_conversation_details) + + threadId = intent.getLongExtra(THREAD_ID, 0L) + ensureBackgroundThread { + conversation = conversationsDB.getConversationWithThreadId(threadId) + participants = getThreadParticipants(threadId, null) + runOnUiThread { + setupTextViews() + setupParticipants() + } + } + } + + override fun onResume() { + super.onResume() + setupToolbar(conversation_details_toolbar, NavigationIcon.Arrow) + } + + private fun setupTextViews() { + val textColor = getProperTextColor() + val headingColor = textColor.adjustAlpha(HIGHER_ALPHA) + + members_heading.setTextColor(headingColor) + conversation_name_heading.setTextColor(headingColor) + conversation_name.apply { + setTextColor(textColor) + ResourcesCompat.getDrawable(resources, R.drawable.ic_edit_vector, theme)?.apply { + applyColorFilter(textColor) + setCompoundDrawablesWithIntrinsicBounds(null, null, this, null) + } + + text = conversation?.title + setOnClickListener { + RenameConversationDialog(this@ConversationDetailsActivity, conversation!!) { title -> + text = title + ensureBackgroundThread { + conversation = renameConversation(conversation!!, newTitle = title) + } + } + } + } + } + + private fun setupParticipants() { + val adapter = ContactsAdapter(this, participants, participants_recyclerview) { + val contact = it as SimpleContact + val address = contact.phoneNumbers.first().normalizedNumber + getContactFromAddress(address) { simpleContact -> + if (simpleContact != null) { + startContactDetailsIntent(simpleContact) + } + } + } + participants_recyclerview.adapter = adapter + } +} 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 c4ab1ac6..b1a072b9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/MainActivity.kt @@ -257,9 +257,14 @@ class MainActivity : SimpleActivity() { } cachedConversations.forEach { cachedConv -> - val conv = conversations.find { it.threadId == cachedConv.threadId && !Conversation.areContentsTheSame(cachedConv, it) } + val conv = conversations.find { + it.threadId == cachedConv.threadId && !Conversation.areContentsTheSame(cachedConv, it) + } if (conv != null) { - val conversation = conv.copy(date = maxOf(cachedConv.date, conv.date)) + val lastModified = maxOf(cachedConv.date, conv.date) + val usesCustomTitle = cachedConv.usesCustomTitle + val title = if (usesCustomTitle) cachedConv.title else conv.title + val conversation = conv.copy(date = lastModified, title = title, usesCustomTitle = usesCustomTitle) conversationsDB.insertOrUpdate(conversation) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt index 2a9bbb8d..72623614 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/activities/ThreadActivity.kt @@ -51,6 +51,7 @@ import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.adapters.AttachmentsAdapter import com.simplemobiletools.smsmessenger.adapters.AutoCompleteTextViewAdapter import com.simplemobiletools.smsmessenger.adapters.ThreadAdapter +import com.simplemobiletools.smsmessenger.dialogs.RenameConversationDialog import com.simplemobiletools.smsmessenger.dialogs.ScheduleMessageDialog import com.simplemobiletools.smsmessenger.extensions.* import com.simplemobiletools.smsmessenger.helpers.* @@ -80,6 +81,7 @@ class ThreadActivity : SimpleActivity() { private var refreshedSinceSent = false private var threadItems = ArrayList() private var bus: EventBus? = null + private var conversation: Conversation? = null private var participants = ArrayList() private var privateContacts = ArrayList() private var messages = ArrayList() @@ -120,6 +122,7 @@ class ThreadActivity : SimpleActivity() { handlePermission(PERMISSION_READ_PHONE_STATE) { granted -> if (granted) { setupButtons() + setupConversation() setupCachedMessages { val searchedMessageId = intent.getLongExtra(SEARCHED_MESSAGE_ID, -1L) intent.removeExtra(SEARCHED_MESSAGE_ID) @@ -151,6 +154,16 @@ class ThreadActivity : SimpleActivity() { thread_type_message.setText(smsDraft) } isActivityVisible = true + + ensureBackgroundThread { + val newConv = conversationsDB.getConversationWithThreadId(threadId) + if (newConv != null) { + conversation = newConv + runOnUiThread { + setupThreadTitle() + } + } + } } override fun onPause() { @@ -184,6 +197,8 @@ class ThreadActivity : SimpleActivity() { val firstPhoneNumber = participants.firstOrNull()?.phoneNumbers?.firstOrNull()?.value thread_toolbar.menu.apply { findItem(R.id.delete).isVisible = threadItems.isNotEmpty() + findItem(R.id.rename_conversation).isVisible = participants.size > 1 && conversation != null + findItem(R.id.conversation_details).isVisible = participants.size > 1 && conversation != null findItem(R.id.block_number).title = addLockedLabelIfNeeded(R.string.block_number) findItem(R.id.block_number).isVisible = isNougatPlus() findItem(R.id.dial_number).isVisible = participants.size == 1 @@ -205,6 +220,8 @@ class ThreadActivity : SimpleActivity() { when (menuItem.itemId) { R.id.block_number -> tryBlocking() R.id.delete -> askConfirmDelete() + R.id.rename_conversation -> renameConversation() + R.id.conversation_details -> showConversationDetails() R.id.add_number_to_contact -> addNumberToContact() R.id.dial_number -> dialNumber() R.id.manage_people -> managePeople() @@ -485,6 +502,12 @@ class ThreadActivity : SimpleActivity() { } } + private fun setupConversation() { + ensureBackgroundThread { + conversation = conversationsDB.getConversationWithThreadId(threadId) + } + } + private fun setupButtons() { updateTextColors(thread_holder) val textColor = getProperTextColor() @@ -638,9 +661,11 @@ class ThreadActivity : SimpleActivity() { } private fun setupThreadTitle() { - val threadTitle = participants.getThreadTitle() - if (threadTitle.isNotEmpty()) { - thread_toolbar.title = participants.getThreadTitle() + val title = conversation?.title + thread_toolbar.title = if (!title.isNullOrEmpty()) { + title + } else { + participants.getThreadTitle() } } @@ -827,6 +852,24 @@ class ThreadActivity : SimpleActivity() { } } + private fun renameConversation() { + RenameConversationDialog(this, conversation!!) { title -> + ensureBackgroundThread { + conversation = renameConversation(conversation!!, newTitle = title) + runOnUiThread { + setupThreadTitle() + } + } + } + } + + private fun showConversationDetails() { + Intent(this, ConversationDetailsActivity::class.java).apply { + putExtra(THREAD_ID, threadId) + startActivity(this) + } + } + @SuppressLint("MissingPermission") private fun getThreadItems(): ArrayList { val items = ArrayList() @@ -1242,31 +1285,6 @@ class ThreadActivity : SimpleActivity() { return participants } - fun startContactDetailsIntent(contact: SimpleContact) { - val simpleContacts = "com.simplemobiletools.contacts.pro" - val simpleContactsDebug = "com.simplemobiletools.contacts.pro.debug" - if (contact.rawId > 1000000 && contact.contactId > 1000000 && contact.rawId == contact.contactId && - (isPackageInstalled(simpleContacts) || isPackageInstalled(simpleContactsDebug)) - ) { - Intent().apply { - action = Intent.ACTION_VIEW - putExtra(CONTACT_ID, contact.rawId) - putExtra(IS_PRIVATE, true) - setPackage(if (isPackageInstalled(simpleContacts)) simpleContacts else simpleContactsDebug) - setDataAndType(ContactsContract.Contacts.CONTENT_LOOKUP_URI, "vnd.android.cursor.dir/person") - launchActivityIntent(this) - } - } else { - ensureBackgroundThread { - val lookupKey = SimpleContactsHelper(this).getContactLookupKey((contact).rawId.toString()) - val publicUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey) - runOnUiThread { - launchViewContactIntent(publicUri) - } - } - } - } - fun saveMMS(mimeType: String, path: String) { hideKeyboard() lastAttachmentUri = path diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt index 880d96dc..28a25a64 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ConversationsAdapter.kt @@ -24,6 +24,7 @@ import com.simplemobiletools.commons.helpers.isNougatPlus import com.simplemobiletools.commons.views.MyRecyclerView import com.simplemobiletools.smsmessenger.R import com.simplemobiletools.smsmessenger.activities.SimpleActivity +import com.simplemobiletools.smsmessenger.dialogs.RenameConversationDialog import com.simplemobiletools.smsmessenger.extensions.* import com.simplemobiletools.smsmessenger.helpers.refreshMessages import com.simplemobiletools.smsmessenger.models.Conversation @@ -60,6 +61,7 @@ class ConversationsAdapter( findItem(R.id.cab_add_number_to_contact).isVisible = isOneItemSelected() && selectedItems.firstOrNull()?.isGroupConversation == false findItem(R.id.cab_dial_number).isVisible = isOneItemSelected() && selectedItems.firstOrNull()?.isGroupConversation == false findItem(R.id.cab_copy_number).isVisible = isOneItemSelected() && selectedItems.firstOrNull()?.isGroupConversation == false + findItem(R.id.rename_conversation).isVisible = isOneItemSelected() && selectedItems.firstOrNull()?.isGroupConversation == true findItem(R.id.cab_mark_as_read).isVisible = selectedItems.any { !it.read } findItem(R.id.cab_mark_as_unread).isVisible = selectedItems.any { it.read } checkPinBtnVisibility(this) @@ -77,6 +79,7 @@ class ConversationsAdapter( R.id.cab_dial_number -> dialNumber() R.id.cab_copy_number -> copyNumberToClipboard() R.id.cab_delete -> askConfirmDelete() + R.id.rename_conversation -> renameConversation(getSelectedItems().first()) R.id.cab_mark_as_read -> markAsRead() R.id.cab_mark_as_unread -> markAsUnread() R.id.cab_pin_conversation -> pinConversation(true) @@ -211,6 +214,21 @@ class ConversationsAdapter( } } + private fun renameConversation(conversation: Conversation) { + RenameConversationDialog(activity, conversation) { + ensureBackgroundThread { + val updatedConv = activity.renameConversation(conversation, newTitle = it) + activity.runOnUiThread { + finishActMode() + currentList.toMutableList().apply { + set(indexOf(conversation), updatedConv) + updateConversations(this as ArrayList) + } + } + } + } + } + private fun markAsRead() { if (selectedKeys.isEmpty()) { return @@ -222,10 +240,7 @@ class ConversationsAdapter( activity.markThreadMessagesRead(it.threadId) } - activity.runOnUiThread { - refreshMessages() - finishActMode() - } + refreshConversations() } } @@ -240,10 +255,7 @@ class ConversationsAdapter( activity.markThreadMessagesUnread(it.threadId) } - activity.runOnUiThread { - refreshMessages() - finishActMode() - } + refreshConversations() } } @@ -271,10 +283,7 @@ class ConversationsAdapter( activity.config.removePinnedConversations(conversations) } - activity.runOnUiThread { - refreshMessages() - finishActMode() - } + refreshConversations() } private fun checkPinBtnVisibility(menu: Menu) { @@ -364,6 +373,13 @@ class ConversationsAdapter( override fun onChange(position: Int) = currentList.getOrNull(position)?.title ?: "" + private fun refreshConversations() { + activity.runOnUiThread { + refreshMessages() + finishActMode() + } + } + private fun saveRecyclerViewState() { recyclerViewState = recyclerView.layoutManager?.onSaveInstanceState() } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt index 0fa9e199..92cd84ed 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/adapters/ThreadAdapter.kt @@ -283,7 +283,7 @@ class ThreadAdapter( val contact = message.participants.first() context.getContactFromAddress(contact.phoneNumbers.first().normalizedNumber) { if (it != null) { - (activity as ThreadActivity).startContactDetailsIntent(it) + activity.startContactDetailsIntent(it) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/databases/MessagesDatabase.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/databases/MessagesDatabase.kt index 72fda67f..030d6be6 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/databases/MessagesDatabase.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/databases/MessagesDatabase.kt @@ -17,7 +17,7 @@ import com.simplemobiletools.smsmessenger.models.Conversation import com.simplemobiletools.smsmessenger.models.Message import com.simplemobiletools.smsmessenger.models.MessageAttachment -@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 5) +@Database(entities = [Conversation::class, Attachment::class, MessageAttachment::class, Message::class], version = 6) @TypeConverters(Converters::class) abstract class MessagesDatabase : RoomDatabase() { @@ -42,6 +42,7 @@ abstract class MessagesDatabase : RoomDatabase() { .addMigrations(MIGRATION_2_3) .addMigrations(MIGRATION_3_4) .addMigrations(MIGRATION_4_5) + .addMigrations(MIGRATION_5_6) .build() } } @@ -97,5 +98,13 @@ abstract class MessagesDatabase : RoomDatabase() { } } } + + private val MIGRATION_5_6 = object : Migration(5, 6) { + override fun migrate(database: SupportSQLiteDatabase) { + database.apply { + execSQL("ALTER TABLE conversations ADD COLUMN uses_custom_title INTEGER NOT NULL DEFAULT 0") + } + } + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/RenameConversationDialog.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/RenameConversationDialog.kt new file mode 100644 index 00000000..a02deb02 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/dialogs/RenameConversationDialog.kt @@ -0,0 +1,63 @@ +package com.simplemobiletools.smsmessenger.dialogs + +import android.app.Activity +import android.content.DialogInterface.BUTTON_POSITIVE +import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog +import androidx.core.widget.doAfterTextChanged +import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.smsmessenger.R +import com.simplemobiletools.smsmessenger.models.Conversation +import kotlinx.android.synthetic.main.dialog_rename_conversation.view.* + +class RenameConversationDialog( + private val activity: Activity, + private val conversation: Conversation, + private val callback: (name: String) -> Unit, +) { + + private var dialog: AlertDialog? = null + + init { + val textColor = activity.getProperTextColor() + val primaryColor = activity.getProperPrimaryColor() + val backgroundColor = activity.getProperBackgroundColor() + + val view = (activity.layoutInflater.inflate(R.layout.dialog_rename_conversation, null) as ViewGroup).apply { + rename_conv_info.setTextColor(textColor) + rename_conv_input_layout.apply { + setColors(textColor, primaryColor, backgroundColor) + setBoxCornerRadiiResources(R.dimen.medium_margin, R.dimen.medium_margin, R.dimen.medium_margin, R.dimen.medium_margin) + } + rename_conv_edit_text.apply { + setTextColor(textColor) + if (conversation.usesCustomTitle) { + setText(conversation.title) + } + hint = conversation.title + + doAfterTextChanged { + dialog?.getButton(BUTTON_POSITIVE)?.isEnabled = !it.isNullOrEmpty() + } + } + } + + activity.getAlertDialogBuilder() + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .apply { + activity.setupDialogStuff(view, this, R.string.rename_conversation) { alertDialog -> + dialog = alertDialog + alertDialog.showKeyboard(view.rename_conv_edit_text) + alertDialog.getButton(BUTTON_POSITIVE).apply { + val newTitle = view.rename_conv_edit_text.text.toString() + isEnabled = newTitle.isNotEmpty() && (newTitle != conversation.title) + setOnClickListener { + alertDialog.dismiss() + callback(view.rename_conv_edit_text.text.toString()) + } + } + } + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Activity.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Activity.kt index 8bbd408c..f4c7774a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Activity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Activity.kt @@ -4,10 +4,13 @@ import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent import android.net.Uri -import com.simplemobiletools.commons.extensions.getMimeType -import com.simplemobiletools.commons.extensions.hideKeyboard -import com.simplemobiletools.commons.extensions.showErrorToast -import com.simplemobiletools.commons.extensions.toast +import android.provider.ContactsContract +import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.CONTACT_ID +import com.simplemobiletools.commons.helpers.IS_PRIVATE +import com.simplemobiletools.commons.helpers.SimpleContactsHelper +import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.commons.models.SimpleContact import com.simplemobiletools.smsmessenger.R import java.util.* @@ -48,3 +51,28 @@ fun Activity.launchViewIntent(uri: Uri, mimetype: String, filename: String) { } } } + +fun Activity.startContactDetailsIntent(contact: SimpleContact) { + val simpleContacts = "com.simplemobiletools.contacts.pro" + val simpleContactsDebug = "com.simplemobiletools.contacts.pro.debug" + if (contact.rawId > 1000000 && contact.contactId > 1000000 && contact.rawId == contact.contactId && + (isPackageInstalled(simpleContacts) || isPackageInstalled(simpleContactsDebug)) + ) { + Intent().apply { + action = Intent.ACTION_VIEW + putExtra(CONTACT_ID, contact.rawId) + putExtra(IS_PRIVATE, true) + setPackage(if (isPackageInstalled(simpleContacts)) simpleContacts else simpleContactsDebug) + setDataAndType(ContactsContract.Contacts.CONTENT_LOOKUP_URI, "vnd.android.cursor.dir/person") + launchActivityIntent(this) + } + } else { + ensureBackgroundThread { + val lookupKey = SimpleContactsHelper(this).getContactLookupKey((contact).rawId.toString()) + val publicUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey) + runOnUiThread { + launchViewContactIntent(publicUri) + } + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt index 57c39af8..bbd6a645 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/extensions/Context.kt @@ -1014,6 +1014,16 @@ fun Context.subscriptionManagerCompat(): SubscriptionManager { } } +fun Context.renameConversation(conversation: Conversation, newTitle: String): Conversation { + val updatedConv = conversation.copy(title = newTitle, usesCustomTitle = true) + try { + conversationsDB.insertOrUpdate(updatedConv) + } catch (e: Exception) { + e.printStackTrace() + } + return updatedConv +} + fun Context.createTemporaryThread(message: Message, threadId: Long = generateRandomId()) { val simpleContactHelper = SimpleContactsHelper(this) val addresses = message.participants.getAddresses() diff --git a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt index 5da76a0f..c20d376c 100644 --- a/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt +++ b/app/src/main/kotlin/com/simplemobiletools/smsmessenger/models/Conversation.kt @@ -15,7 +15,8 @@ data class Conversation( @ColumnInfo(name = "photo_uri") var photoUri: String, @ColumnInfo(name = "is_group_conversation") var isGroupConversation: Boolean, @ColumnInfo(name = "phone_number") var phoneNumber: String, - @ColumnInfo(name = "is_scheduled") var isScheduled: Boolean = false + @ColumnInfo(name = "is_scheduled") var isScheduled: Boolean = false, + @ColumnInfo(name = "uses_custom_title") var usesCustomTitle: Boolean = false ) { companion object { diff --git a/app/src/main/res/layout/activity_conversation_details.xml b/app/src/main/res/layout/activity_conversation_details.xml new file mode 100644 index 00000000..5a219a20 --- /dev/null +++ b/app/src/main/res/layout/activity_conversation_details.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_rename_conversation.xml b/app/src/main/res/layout/dialog_rename_conversation.xml new file mode 100644 index 00000000..3016e39e --- /dev/null +++ b/app/src/main/res/layout/dialog_rename_conversation.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/menu/cab_conversations.xml b/app/src/main/res/menu/cab_conversations.xml index 6560bd24..410223ea 100644 --- a/app/src/main/res/menu/cab_conversations.xml +++ b/app/src/main/res/menu/cab_conversations.xml @@ -28,6 +28,11 @@ android:showAsAction="never" android:title="@string/copy_number_to_clipboard" app:showAsAction="never" /> + + +