From a4ee521ee0c6de2852ed07ecd86ab8b6f326e7f0 Mon Sep 17 00:00:00 2001 From: bemusementpark Date: Thu, 4 Jul 2024 14:48:31 +0930 Subject: [PATCH] Fix Search --- .../securesms/home/HomeActivity.kt | 106 ++++-------------- .../home/search/GlobalSearchAdapter.kt | 13 +-- .../home/search/GlobalSearchAdapterUtils.kt | 60 +++++----- .../pickname/PickDisplayNameActivity.kt | 6 +- .../securesms/util/ActivityUtilities.kt | 2 +- .../session/libsession/utilities/IdUtil.kt | 2 +- 6 files changed, 65 insertions(+), 124 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt index 2e795213fe..b03838ce7b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt @@ -8,30 +8,9 @@ import android.content.Context import android.content.Intent import android.os.Build import android.os.Bundle +import android.provider.Telephony.Mms.Addr import android.widget.Toast import androidx.activity.viewModels -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredWidth -import androidx.compose.foundation.layout.width -import androidx.compose.material.Icon -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter -import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf import androidx.core.view.isInvisible import androidx.core.view.isVisible @@ -56,11 +35,9 @@ import org.session.libsession.messaging.jobs.JobQueue import org.session.libsession.messaging.sending_receiving.MessageSender import org.session.libsession.snode.SnodeAPI import org.session.libsession.utilities.Address -import org.session.libsession.utilities.AppTextSecurePreferences import org.session.libsession.utilities.GroupUtil import org.session.libsession.utilities.ProfilePictureModifiedEvent import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsession.utilities.groupByNotNull import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.Log import org.session.libsignal.utilities.ThreadUtils @@ -87,25 +64,12 @@ import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideRequests import org.thoughtcrime.securesms.notifications.PushRegistry -import org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity import org.thoughtcrime.securesms.permissions.Permissions import org.thoughtcrime.securesms.preferences.SettingsActivity +import org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity import org.thoughtcrime.securesms.showMuteDialog import org.thoughtcrime.securesms.showSessionDialog -import org.thoughtcrime.securesms.ui.Divider -import org.thoughtcrime.securesms.ui.LocalDimensions -import org.thoughtcrime.securesms.ui.color.LocalColors -import org.thoughtcrime.securesms.ui.color.Colors -import org.thoughtcrime.securesms.ui.PreviewTheme -import org.thoughtcrime.securesms.ui.SessionColorsParameterProvider -import org.thoughtcrime.securesms.ui.SessionShieldIcon -import org.thoughtcrime.securesms.ui.base -import org.thoughtcrime.securesms.ui.components.SlimOutlineButton -import org.thoughtcrime.securesms.ui.contentDescription -import org.thoughtcrime.securesms.ui.h4 -import org.thoughtcrime.securesms.ui.h8 import org.thoughtcrime.securesms.ui.setThemedContent -import org.thoughtcrime.securesms.ui.small import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import org.thoughtcrime.securesms.util.IP2Country import org.thoughtcrime.securesms.util.disableClipping @@ -147,41 +111,27 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), private val globalSearchAdapter = GlobalSearchAdapter { model -> when (model) { - is GlobalSearchAdapter.Model.Message -> { - val threadId = model.messageResult.threadId - val timestamp = model.messageResult.sentTimestampMs - val author = model.messageResult.messageRecipient.address - - val intent = Intent(this, ConversationActivityV2::class.java) - intent.putExtra(ConversationActivityV2.THREAD_ID, threadId) - intent.putExtra(ConversationActivityV2.SCROLL_MESSAGE_ID, timestamp) - intent.putExtra(ConversationActivityV2.SCROLL_MESSAGE_AUTHOR, author) - push(intent) - } - is GlobalSearchAdapter.Model.SavedMessages -> { - val intent = Intent(this, ConversationActivityV2::class.java) - intent.putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(model.currentUserPublicKey)) - push(intent) - } - is GlobalSearchAdapter.Model.Contact -> { - val address = model.contact.accountID - - val intent = Intent(this, ConversationActivityV2::class.java) - intent.putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(address)) - push(intent) - } - is GlobalSearchAdapter.Model.GroupConversation -> { - val groupAddress = Address.fromSerialized(model.groupRecord.encodedId) - val threadId = threadDb.getThreadIdIfExistsFor(Recipient.from(this, groupAddress, false)) - if (threadId >= 0) { - val intent = Intent(this, ConversationActivityV2::class.java) - intent.putExtra(ConversationActivityV2.THREAD_ID, threadId) - push(intent) + is GlobalSearchAdapter.Model.Message -> push { + model.messageResult.run { + putExtra(ConversationActivityV2.THREAD_ID, threadId) + putExtra(ConversationActivityV2.SCROLL_MESSAGE_ID, sentTimestampMs) + putExtra(ConversationActivityV2.SCROLL_MESSAGE_AUTHOR, messageRecipient.address) } } - else -> { - Log.d("Loki", "callback with model: $model") + is GlobalSearchAdapter.Model.SavedMessages -> push { + putExtra(ConversationActivityV2.ADDRESS, Address.fromSerialized(model.currentUserPublicKey)) } + is GlobalSearchAdapter.Model.Contact -> push { + putExtra(ConversationActivityV2.ADDRESS, model.contact.accountID.let(Address::fromSerialized)) + } + is GlobalSearchAdapter.Model.GroupConversation -> model.groupRecord.encodedId + .let { Recipient.from(this, Address.fromSerialized(it), false) } + .let(threadDb::getThreadIdIfExistsFor) + .takeIf { it >= 0 } + ?.let { + push { putExtra(ConversationActivityV2.THREAD_ID, it) } + } + else -> Log.d("Loki", "callback with model: $model") } } @@ -321,24 +271,14 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), .flatMap { (key, contacts) -> listOf( GlobalSearchAdapter.Model.SubHeader(key) - ) + contacts.sortedBy { it.name ?: it.value.accountID }.map { it.value }.map(GlobalSearchAdapter.Model::Contact) + ) + contacts.sortedBy { it.name ?: it.value.accountID }.map { it.value }.map { GlobalSearchAdapter.Model.Contact(it, it.accountID == publicKey) } } } else { - val currentUserPublicKey = publicKey - val contactAndGroupList = result.contacts.map(GlobalSearchAdapter.Model::Contact) + + val contactAndGroupList = result.contacts.map { GlobalSearchAdapter.Model.Contact(it, it.accountID == publicKey) } + result.threads.map(GlobalSearchAdapter.Model::GroupConversation) val contactResults = contactAndGroupList.toMutableList() - if (contactResults.isEmpty()) { - contactResults.add(GlobalSearchAdapter.Model.SavedMessages(currentUserPublicKey)) - } - - val userIndex = contactResults.indexOfFirst { it is GlobalSearchAdapter.Model.Contact && it.contact.accountID == currentUserPublicKey } - if (userIndex >= 0) { - contactResults[userIndex] = GlobalSearchAdapter.Model.SavedMessages(currentUserPublicKey) - } - if (contactResults.isNotEmpty()) { contactResults.add(0, GlobalSearchAdapter.Model.Header(R.string.conversations)) } @@ -348,7 +288,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(), .associateWith { mmsSmsDatabase.getUnreadCount(it) } val messageResults: MutableList = result.messages - .map { GlobalSearchAdapter.Model.Message(it, unreadThreadMap[it.threadId] ?: 0) } + .map { GlobalSearchAdapter.Model.Message(it, unreadThreadMap[it.threadId] ?: 0, it.conversationRecipient.isLocalNumber) } .toMutableList() if (messageResults.isNotEmpty()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapter.kt index 4bcf00b72d..c7db4fc8b7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapter.kt @@ -17,7 +17,7 @@ import org.thoughtcrime.securesms.ui.GetString import java.security.InvalidParameterException import org.session.libsession.messaging.contacts.Contact as ContactModel -class GlobalSearchAdapter (private val modelCallback: (Model)->Unit): RecyclerView.Adapter() { +class GlobalSearchAdapter(private val modelCallback: (Model)->Unit): RecyclerView.Adapter() { companion object { const val HEADER_VIEW_TYPE = 0 @@ -122,15 +122,8 @@ class GlobalSearchAdapter (private val modelCallback: (Model)->Unit): RecyclerVi } binding.root.setOnClickListener { modelCallback(model) } } - } - data class MessageModel( - val threadRecipient: Recipient, - val messageRecipient: Recipient, - val messageSnippet: String - ) - sealed class Model { data class Header(val title: GetString): Model() { constructor(@StringRes title: Int): this(GetString(title)) @@ -141,8 +134,8 @@ class GlobalSearchAdapter (private val modelCallback: (Model)->Unit): RecyclerVi constructor(title: String): this(GetString(title)) } data class SavedMessages(val currentUserPublicKey: String): Model() - data class Contact(val contact: ContactModel): Model() + data class Contact(val contact: ContactModel, val isSelf: Boolean): Model() data class GroupConversation(val groupRecord: GroupRecord): Model() - data class Message(val messageResult: MessageResult, val unread: Int): Model() + data class Message(val messageResult: MessageResult, val unread: Int, val isSelf: Boolean): Model() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapterUtils.kt b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapterUtils.kt index f45ffbef57..d390776d1c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapterUtils.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/home/search/GlobalSearchAdapterUtils.kt @@ -65,7 +65,7 @@ fun ContentView.bindQuery(query: String, model: GlobalSearchAdapter.Model) { )) binding.searchResultSubtitle.text = textSpannable binding.searchResultSubtitle.isVisible = true - binding.searchResultTitle.text = model.messageResult.conversationRecipient.toShortString() + binding.searchResultTitle.text = model.messageResult.conversationRecipient.getSearchName() } is GroupConversation -> { binding.searchResultTitle.text = getHighlight( @@ -74,8 +74,7 @@ fun ContentView.bindQuery(query: String, model: GlobalSearchAdapter.Model) { ) val membersString = model.groupRecord.members.joinToString { address -> - val recipient = Recipient.from(binding.root.context, address, false) - recipient.name ?: "${address.serialize().take(4)}...${address.serialize().takeLast(4)}" + Recipient.from(binding.root.context, address, false).getSearchName() } binding.searchResultSubtitle.text = getHighlight(query, membersString) } @@ -106,16 +105,16 @@ fun ContentView.bindModel(query: String?, model: GroupConversation) { } } -fun ContentView.bindModel(query: String?, model: ContactModel) { - binding.searchResultProfilePicture.isVisible = true - binding.searchResultSubtitle.isVisible = false - binding.searchResultTimestamp.isVisible = false - binding.searchResultSubtitle.text = null - val recipient = - Recipient.from(binding.root.context, Address.fromSerialized(model.contact.accountID), false) - binding.searchResultProfilePicture.update(recipient) - val nameString = model.contact.getSearchName() - binding.searchResultTitle.text = getHighlight(query, nameString) +fun ContentView.bindModel(query: String?, model: ContactModel) = binding.run { + searchResultProfilePicture.isVisible = true + searchResultSubtitle.isVisible = false + searchResultTimestamp.isVisible = false + searchResultSubtitle.text = null + val recipient = Recipient.from(root.context, Address.fromSerialized(model.contact.accountID), false) + searchResultProfilePicture.update(recipient) + val nameString = if (model.isSelf) root.context.getString(R.string.note_to_self) + else model.contact.getSearchName() + searchResultTitle.text = getHighlight(query, nameString) } fun ContentView.bindModel(model: SavedMessages) { @@ -126,32 +125,39 @@ fun ContentView.bindModel(model: SavedMessages) { binding.searchResultProfilePicture.isVisible = true } -fun ContentView.bindModel(query: String?, model: Message) { - binding.searchResultProfilePicture.isVisible = true - binding.searchResultTimestamp.isVisible = true +fun ContentView.bindModel(query: String?, model: Message) = binding.apply { + searchResultProfilePicture.isVisible = true + searchResultTimestamp.isVisible = true // val hasUnreads = model.unread > 0 -// binding.unreadCountIndicator.isVisible = hasUnreads +// unreadCountIndicator.isVisible = hasUnreads // if (hasUnreads) { -// binding.unreadCountTextView.text = model.unread.toString() +// unreadCountTextView.text = model.unread.toString() // } - binding.searchResultTimestamp.text = DateUtils.getDisplayFormattedTimeSpanString(binding.root.context, Locale.getDefault(), model.messageResult.sentTimestampMs) - binding.searchResultProfilePicture.update(model.messageResult.conversationRecipient) + searchResultTimestamp.text = DateUtils.getDisplayFormattedTimeSpanString(root.context, Locale.getDefault(), model.messageResult.sentTimestampMs) + searchResultProfilePicture.update(model.messageResult.conversationRecipient) val textSpannable = SpannableStringBuilder() if (model.messageResult.conversationRecipient != model.messageResult.messageRecipient) { // group chat, bind - val text = "${model.messageResult.messageRecipient.getSearchName()}: " + val text = "${model.messageResult.messageRecipient.toShortString()}: " textSpannable.append(text) } textSpannable.append(getHighlight( query, model.messageResult.bodySnippet )) - binding.searchResultSubtitle.text = textSpannable - binding.searchResultTitle.text = model.messageResult.conversationRecipient.toShortString() - binding.searchResultSubtitle.isVisible = true + searchResultSubtitle.text = textSpannable + searchResultTitle.text = if (model.isSelf) root.context.getString(R.string.note_to_self) + else model.messageResult.conversationRecipient.getSearchName() + searchResultSubtitle.isVisible = true } -fun Recipient.getSearchName(): String = name ?: address.serialize().let(::truncateIdForDisplay) +fun Recipient.getSearchName(): String = + name?.takeIf { it.isNotEmpty() && !it.looksLikeAccountId } + ?: address.serialize().let(::truncateIdForDisplay) -fun Contact.getSearchName(): String = nickname?.takeIf { it.isNotEmpty() } - ?: name?.takeIf { it.isNotEmpty() } ?: truncateIdForDisplay(accountID) +fun Contact.getSearchName(): String = + nickname?.takeIf { it.isNotEmpty() && !it.looksLikeAccountId } + ?: name?.takeIf { it.isNotEmpty() && !it.looksLikeAccountId } + ?: truncateIdForDisplay(accountID) + +private val String.looksLikeAccountId: Boolean get() = length > 60 && all { it.isDigit() || it.isLetter() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/onboarding/pickname/PickDisplayNameActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/onboarding/pickname/PickDisplayNameActivity.kt index da0c80fcb6..62f209454e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/onboarding/pickname/PickDisplayNameActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/onboarding/pickname/PickDisplayNameActivity.kt @@ -57,10 +57,12 @@ class PickDisplayNameActivity : BaseActionBarActivity() { viewModel.states.collectAsState().value, viewModel::onChange, viewModel::onContinue, - viewModel::dismissDialog - ) { viewModel.dismissDialog(); finish() } + viewModel::dismissDialog, + quit = { viewModel.dismissDialog(); finish() } + ) } + @Deprecated("Deprecated in Java") override fun onBackPressed() { if (viewModel.onBackPressed()) return diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ActivityUtilities.kt b/app/src/main/java/org/thoughtcrime/securesms/util/ActivityUtilities.kt index d285ad7a39..c3b7eaca96 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/ActivityUtilities.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/ActivityUtilities.kt @@ -108,5 +108,5 @@ data class ThemeState ( ) inline fun Activity.show() = Intent(this, T::class.java).also(::startActivity).let { overridePendingTransition(R.anim.slide_from_bottom, R.anim.fade_scale_out) } -inline fun Activity.push() = Intent(this, T::class.java).also(::startActivity).let { overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out) } +inline fun Activity.push(modify: Intent.() -> Unit = {}) = Intent(this, T::class.java).also(modify).also(::startActivity).let { overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out) } inline fun Context.start(modify: Intent.() -> Unit = {}) = Intent(this, T::class.java).also(modify).apply { addFlags(FLAG_ACTIVITY_SINGLE_TOP) }.let(::startActivity) diff --git a/libsession/src/main/java/org/session/libsession/utilities/IdUtil.kt b/libsession/src/main/java/org/session/libsession/utilities/IdUtil.kt index ccaa31c2f9..1902b6e0ab 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/IdUtil.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/IdUtil.kt @@ -1,4 +1,4 @@ package org.session.libsession.utilities fun truncateIdForDisplay(id: String): String = - id.takeIf { it.length > 8 }?.apply{ "${take(4)}…${takeLast(4)}" } ?: id + id.takeIf { it.length > 8 }?.run{ "${take(4)}…${takeLast(4)}" } ?: id