From 61ff68b532f7653377f29c262f1f07f18b0f58ed Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 11:49:10 +1000 Subject: [PATCH 01/26] add search bottom bar ui --- .../conversation/v2/ConversationActivityV2.kt | 10 +- .../v2/menus/ConversationMenuHelper.kt | 58 ++++++++- .../conversation/v2/search/SearchBottomBar.kt | 64 ++++++++++ .../conversation/v2/search/SearchViewModel.kt | 114 ++++++++++++++++++ .../res/layout/activity_conversation_v2.xml | 7 ++ .../res/layout/view_search_bottom_bar.xml | 68 +++++++++++ 6 files changed, 317 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt create mode 100644 app/src/main/res/layout/view_search_bottom_bar.xml diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 30fefabc4c..89953bcc04 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -39,7 +39,6 @@ import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher -import org.thoughtcrime.securesms.conversation.ConversationActivity import org.thoughtcrime.securesms.conversation.v2.dialogs.* import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate @@ -291,7 +290,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } override fun onPrepareOptionsMenu(menu: Menu): Boolean { - ConversationMenuHelper.onPrepareOptionsMenu(menu, menuInflater, thread, this) { onOptionsItemSelected(it) } + ConversationMenuHelper.onPrepareOptionsMenu(menu, menuInflater, thread, threadID, this) { onOptionsItemSelected(it) } super.onPrepareOptionsMenu(menu) return true } @@ -750,4 +749,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe draftDB.insertDrafts(threadID, drafts) } // endregion + + // region Search + fun onSearchQueryUpdated(query: String?) { + adapter.onSearchQueryUpdated(query) + } + + // endregion } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 7dc18130d7..3e81a502e4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -6,17 +6,26 @@ import android.graphics.PorterDuffColorFilter import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.annotation.ColorInt +import androidx.appcompat.widget.SearchView +import androidx.appcompat.widget.SearchView.OnQueryTextListener +import androidx.lifecycle.ViewModelProvider +import kotlinx.android.synthetic.main.activity_conversation_v2.* +import kotlinx.android.synthetic.main.session_logo_action_bar_content.* import network.loki.messenger.R import org.session.libsession.utilities.ExpirationUtil import org.session.libsession.utilities.recipients.Recipient +import org.thoughtcrime.securesms.components.ConversationSearchBottomBar +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 +import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel import org.thoughtcrime.securesms.loki.utilities.getColorWithID object ConversationMenuHelper { - fun onPrepareOptionsMenu(menu: Menu, inflater: MenuInflater, thread: Recipient, context: Context, onOptionsItemSelected: (MenuItem) -> Unit) { + fun onPrepareOptionsMenu(menu: Menu, inflater: MenuInflater, thread: Recipient, threadId: Long, context: Context, onOptionsItemSelected: (MenuItem) -> Unit) { // Prepare menu.clear() val isOpenGroup = thread.isOpenGroupRecipient @@ -61,6 +70,51 @@ object ConversationMenuHelper { } else { inflater.inflate(R.menu.menu_conversation_unmuted, menu) } - // TODO: Implement search + // Search + val searchViewItem = menu.findItem(R.id.menu_search) + val searchView = searchViewItem.actionView as SearchView + val searchViewModel:SearchViewModel = ViewModelProvider(context as ConversationActivityV2).get(SearchViewModel::class.java) + val queryListener = object : OnQueryTextListener { + override fun onQueryTextSubmit(query: String): Boolean { + searchViewModel.onQueryUpdated(query, threadId) + context.searchBottomBar.showLoading() + context.onSearchQueryUpdated(query) + return true + } + + override fun onQueryTextChange(query: String): Boolean { + searchViewModel.onQueryUpdated(query, threadId) + context.searchBottomBar.showLoading() + context.onSearchQueryUpdated(query) + return true + } + } + searchViewItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener { + override fun onMenuItemActionExpand(item: MenuItem): Boolean { + searchView.setOnQueryTextListener(queryListener) + searchViewModel.onSearchOpened() + context.searchBottomBar.visibility = View.VISIBLE + context.searchBottomBar.setData(0, 0) + context.inputBar.visibility = View.GONE + context.supportActionBar?.setDisplayHomeAsUpEnabled(false) + for (i in 0 until menu.size()) { + if (menu.getItem(i) != searchViewItem) { + menu.getItem(i).isVisible = false + } + } + return true + } + + override fun onMenuItemActionCollapse(item: MenuItem): Boolean { + searchView.setOnQueryTextListener(null) + searchViewModel.onSearchClosed() + context.searchBottomBar.visibility = View.GONE + context.inputBar.visibility = View.VISIBLE + context.supportActionBar?.setDisplayHomeAsUpEnabled(true) + context.onSearchQueryUpdated(null) + context.invalidateOptionsMenu() + return true + } + }) } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt new file mode 100644 index 0000000000..93d24ff019 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt @@ -0,0 +1,64 @@ +package org.thoughtcrime.securesms.conversation.v2.search + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.view.View +import android.widget.LinearLayout +import android.widget.RelativeLayout +import androidx.constraintlayout.widget.ConstraintLayout +import kotlinx.android.synthetic.main.view_search_bottom_bar.view.* +import network.loki.messenger.R + + +class SearchBottomBar : LinearLayout { + private var eventListener: EventListener? = null + + // region Lifecycle + constructor(context: Context) : super(context) { initialize() } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() } + + fun initialize() { + LayoutInflater.from(context).inflate(R.layout.view_search_bottom_bar, this) + } + + fun setData(position: Int, count: Int) { + searchProgressWheel.visibility = GONE + searchUp.setOnClickListener { v: View? -> + if (eventListener != null) { + eventListener!!.onSearchMoveUpPressed() + } + } + searchDown.setOnClickListener { v: View? -> + if (eventListener != null) { + eventListener!!.onSearchMoveDownPressed() + } + } + if (count > 0) { + searchPosition.text = resources.getString(R.string.ConversationActivity_search_position, position + 1, count) + } else { + searchPosition.setText(R.string.ConversationActivity_no_results) + } + setViewEnabled(searchUp, position < count - 1) + setViewEnabled(searchDown, position > 0) + } + + fun showLoading() { + searchProgressWheel.visibility = VISIBLE + } + + private fun setViewEnabled(view: View, enabled: Boolean) { + view.isEnabled = enabled + view.alpha = if (enabled) 1f else 0.25f + } + + fun setEventListener(eventListener: EventListener?) { + this.eventListener = eventListener + } + + interface EventListener { + fun onSearchMoveUpPressed() + fun onSearchMoveDownPressed() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt new file mode 100644 index 0000000000..f1d7c8a610 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt @@ -0,0 +1,114 @@ +package org.thoughtcrime.securesms.conversation.v2.search + +import android.app.Application +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.LiveData +import org.session.libsession.utilities.Debouncer +import org.session.libsession.utilities.Util.runOnMain +import org.session.libsession.utilities.concurrent.SignalExecutors +import org.thoughtcrime.securesms.contacts.ContactAccessor +import org.thoughtcrime.securesms.database.CursorList +import org.thoughtcrime.securesms.database.DatabaseFactory +import org.thoughtcrime.securesms.search.SearchRepository +import org.thoughtcrime.securesms.search.model.MessageResult +import org.thoughtcrime.securesms.util.CloseableLiveData +import java.io.Closeable + + +class SearchViewModel(application: Application) : AndroidViewModel(application) { + private val searchRepository: SearchRepository + private val result: CloseableLiveData + private val debouncer: Debouncer + private var firstSearch = false + private var searchOpen = false + private var activeQuery: String? = null + private var activeThreadId: Long = 0 + val searchResults: LiveData + get() = result + + fun onQueryUpdated(query: String, threadId: Long) { + if (firstSearch && query.length < 2) { + result.postValue(SearchResult(CursorList.emptyList(), 0)) + return + } + if (query == activeQuery) { + return + } + updateQuery(query, threadId) + } + + fun onMissingResult() { + if (activeQuery != null) { + updateQuery(activeQuery!!, activeThreadId) + } + } + + fun onMoveUp() { + debouncer.clear() + val messages = result.value!!.getResults() as CursorList + val position = Math.min(result.value!!.position + 1, messages.size - 1) + result.setValue(SearchResult(messages, position), false) + } + + fun onMoveDown() { + debouncer.clear() + val messages = result.value!!.getResults() as CursorList + val position = Math.max(result.value!!.position - 1, 0) + result.setValue(SearchResult(messages, position), false) + } + + fun onSearchOpened() { + searchOpen = true + firstSearch = true + } + + fun onSearchClosed() { + searchOpen = false + debouncer.clear() + result.close() + } + + override fun onCleared() { + super.onCleared() + result.close() + } + + private fun updateQuery(query: String, threadId: Long) { + activeQuery = query + activeThreadId = threadId + debouncer.publish { + firstSearch = false + searchRepository.query(query, threadId) { messages: CursorList -> + runOnMain { + if (searchOpen && query == activeQuery) { + result.setValue(SearchResult(messages, 0)) + } else { + messages.close() + } + } + } + } + } + + class SearchResult(private val results: CursorList, val position: Int) : Closeable { + + fun getResults(): List { + return results + } + + override fun close() { + results.close() + } + } + + init { + val context = application.applicationContext + result = CloseableLiveData() + debouncer = Debouncer(500) + searchRepository = SearchRepository(context, + DatabaseFactory.getSearchDatabase(context), + DatabaseFactory.getThreadDatabase(context), + ContactAccessor.getInstance(), + SignalExecutors.SERIAL) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_conversation_v2.xml b/app/src/main/res/layout/activity_conversation_v2.xml index 66d71f5cce..079c932e99 100644 --- a/app/src/main/res/layout/activity_conversation_v2.xml +++ b/app/src/main/res/layout/activity_conversation_v2.xml @@ -34,6 +34,13 @@ android:layout_height="wrap_content" android:layout_alignParentBottom="true" /> + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From f4d3a7359e35ebfc0fb7ad9b834388cb00073601 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 11:49:45 +1000 Subject: [PATCH 02/26] highlight the search result --- .../conversation/v2/ConversationAdapter.kt | 8 ++++++- .../v2/messages/LinkPreviewView.kt | 4 ++-- .../v2/messages/VisibleMessageContentView.kt | 22 ++++++++++--------- .../v2/messages/VisibleMessageView.kt | 4 ++-- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 63306b0c4f..690fd5acea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -19,6 +19,7 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr : CursorRecyclerViewAdapter(context, cursor) { private val messageDB = DatabaseFactory.getMmsSmsDatabase(context) var selectedItems = mutableSetOf() + private var searchQuery: String? = null sealed class ViewType(val rawValue: Int) { object Visible : ViewType(0) @@ -67,7 +68,7 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr view.snIsSelected = isSelected view.messageTimestampTextView.isVisible = isSelected val position = viewHolder.adapterPosition - view.bind(message, getMessageBefore(position, cursor), getMessageAfter(position, cursor), glide) + view.bind(message, getMessageBefore(position, cursor), getMessageAfter(position, cursor), glide, searchQuery) view.onPress = { onItemPress(message, viewHolder.adapterPosition, view) } view.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) } view.onLongPress = { onItemLongPress(message, viewHolder.adapterPosition) } @@ -117,4 +118,9 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr } return null } + + fun onSearchQueryUpdated(query: String?) { + this.searchQuery = query + notifyDataSetChanged() + } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt index 00a98d1d33..d6bbdd4066 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/LinkPreviewView.kt @@ -31,7 +31,7 @@ class LinkPreviewView : LinearLayout { // endregion // region Updating - fun bind(message: MmsMessageRecord, glide: GlideRequests, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean) { + fun bind(message: MmsMessageRecord, glide: GlideRequests, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean, searchQuery: String?) { mainLinkPreviewContainer.background = background mainLinkPreviewContainer.outlineProvider = ViewOutlineProvider.BACKGROUND mainLinkPreviewContainer.clipToOutline = true @@ -50,7 +50,7 @@ class LinkPreviewView : LinearLayout { } titleTextView.setTextColor(ResourcesCompat.getColor(resources, textColorID, context.theme)) // Body - val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message) + val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message, searchQuery) mainLinkPreviewContainer.addView(bodyTextView) // Corner radii val cornerRadii = MessageBubbleUtilities.calculateRadii(context, isStartOfMessageCluster, isEndOfMessageCluster, message.isOutgoing) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index e242d6e6b5..afe50166ff 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -1,12 +1,12 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context -import android.content.res.ColorStateList import android.graphics.Color import android.graphics.drawable.Drawable +import android.text.style.BackgroundColorSpan +import android.text.style.ForegroundColorSpan import android.text.util.Linkify import android.util.AttributeSet -import android.util.Log import android.util.TypedValue import android.view.LayoutInflater import android.widget.LinearLayout @@ -19,8 +19,6 @@ import androidx.core.graphics.BlendModeCompat import androidx.core.text.toSpannable import kotlinx.android.synthetic.main.view_visible_message_content.view.* import network.loki.messenger.R -import org.session.libsession.messaging.utilities.UpdateMessageData -import org.session.libsession.messaging.utilities.UpdateMessageData.Companion.fromJSON import org.session.libsession.utilities.ThemeUtil import org.session.libsession.utilities.ViewUtil import org.session.libsession.utilities.recipients.Recipient @@ -28,8 +26,10 @@ import org.thoughtcrime.securesms.components.emoji.EmojiTextView import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.loki.utilities.* -import org.thoughtcrime.securesms.loki.utilities.MentionUtilities.highlightMentions import org.thoughtcrime.securesms.mms.GlideRequests +import org.thoughtcrime.securesms.util.SearchUtil +import org.thoughtcrime.securesms.util.SearchUtil.StyleFactory +import java.util.* import kotlin.math.roundToInt class VisibleMessageContentView : LinearLayout { @@ -47,7 +47,7 @@ class VisibleMessageContentView : LinearLayout { // region Updating fun bind(message: MessageRecord, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean, - glide: GlideRequests, maxWidth: Int, thread: Recipient) { + glide: GlideRequests, maxWidth: Int, thread: Recipient, searchQuery: String?) { // Background val background = getBackground(message.isOutgoing, isStartOfMessageCluster, isEndOfMessageCluster) val colorID = if (message.isOutgoing) R.attr.message_sent_background_color else R.attr.message_received_background_color @@ -60,7 +60,7 @@ class VisibleMessageContentView : LinearLayout { onContentClick = null if (message is MmsMessageRecord && message.linkPreviews.isNotEmpty()) { val linkPreviewView = LinkPreviewView(context) - linkPreviewView.bind(message, glide, isStartOfMessageCluster, isEndOfMessageCluster) + linkPreviewView.bind(message, glide, isStartOfMessageCluster, isEndOfMessageCluster, searchQuery) mainContainer.addView(linkPreviewView) // Body text view is inside the link preview for layout convenience } else if (message is MmsMessageRecord && message.quote != null) { @@ -73,7 +73,7 @@ class VisibleMessageContentView : LinearLayout { quoteView.bind(quote.author.toString(), quote.text, quote.attachment, thread, message.isOutgoing, maxContentWidth, message.isOpenGroupInvitation, message.threadId) mainContainer.addView(quoteView) - val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message) + val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message, searchQuery) ViewUtil.setPaddingTop(bodyTextView, 0) mainContainer.addView(bodyTextView) } else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) { @@ -96,7 +96,7 @@ class VisibleMessageContentView : LinearLayout { openGroupInvitationView.bind(message, VisibleMessageContentView.getTextColor(context, message)) mainContainer.addView(openGroupInvitationView) } else { - val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message) + val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message, searchQuery) mainContainer.addView(bodyTextView) } } @@ -124,7 +124,7 @@ class VisibleMessageContentView : LinearLayout { // region Convenience companion object { - fun getBodyTextView(context: Context, message: MessageRecord): TextView { + fun getBodyTextView(context: Context, message: MessageRecord, searchQuery: String?): TextView { val result = EmojiTextView(context) val vPadding = context.resources.getDimension(R.dimen.small_spacing).toInt() val hPadding = toPx(12, context.resources) @@ -136,6 +136,8 @@ class VisibleMessageContentView : LinearLayout { var body = message.body.toSpannable() Linkify.addLinks(body, Linkify.WEB_URLS) body = MentionUtilities.highlightMentions(body, message.isOutgoing, message.threadId, context); + body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { BackgroundColorSpan(Color.WHITE) }, body, searchQuery) + body = SearchUtil.getHighlightedSpan(Locale.getDefault(), StyleFactory { ForegroundColorSpan(Color.BLACK) }, body, searchQuery) result.text = body return result } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 3d665c5cbd..9cd29c9d46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -74,7 +74,7 @@ class VisibleMessageView : LinearLayout { // endregion // region Updating - fun bind(message: MessageRecord, previous: MessageRecord?, next: MessageRecord?, glide: GlideRequests) { + fun bind(message: MessageRecord, previous: MessageRecord?, next: MessageRecord?, glide: GlideRequests, searchQuery: String?) { val sender = message.individualRecipient val senderSessionID = sender.address.serialize() val threadID = message.threadId @@ -142,7 +142,7 @@ class VisibleMessageView : LinearLayout { var maxWidth = screenWidth - messageContentContainerLayoutParams.leftMargin - messageContentContainerLayoutParams.rightMargin if (profilePictureContainer.visibility != View.GONE) { maxWidth -= profilePictureContainer.width } // Populate content view - messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread) + messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread, searchQuery) } private fun setMessageSpacing(isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean) { From 6b4acd023213fb65b65b82bf6eaa253e92a1e030 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 11:51:04 +1000 Subject: [PATCH 03/26] clean --- .../securesms/conversation/v2/menus/ConversationMenuHelper.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 3e81a502e4..4c3a72a9ed 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -96,7 +96,6 @@ object ConversationMenuHelper { context.searchBottomBar.visibility = View.VISIBLE context.searchBottomBar.setData(0, 0) context.inputBar.visibility = View.GONE - context.supportActionBar?.setDisplayHomeAsUpEnabled(false) for (i in 0 until menu.size()) { if (menu.getItem(i) != searchViewItem) { menu.getItem(i).isVisible = false @@ -110,7 +109,6 @@ object ConversationMenuHelper { searchViewModel.onSearchClosed() context.searchBottomBar.visibility = View.GONE context.inputBar.visibility = View.VISIBLE - context.supportActionBar?.setDisplayHomeAsUpEnabled(true) context.onSearchQueryUpdated(null) context.invalidateOptionsMenu() return true From c294262ff313c322a6eeda6dcaa68fa5cd1f8e2f Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 14:00:30 +1000 Subject: [PATCH 04/26] fix spinner --- app/src/main/res/layout/view_search_bottom_bar.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout/view_search_bottom_bar.xml b/app/src/main/res/layout/view_search_bottom_bar.xml index b334fd485e..e794e75205 100644 --- a/app/src/main/res/layout/view_search_bottom_bar.xml +++ b/app/src/main/res/layout/view_search_bottom_bar.xml @@ -1,7 +1,7 @@ - From 628477f2fd8d7a691114e5c6ebb13e2e48852f08 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 14:00:47 +1000 Subject: [PATCH 05/26] link event listener --- .../conversation/v2/ConversationActivityV2.kt | 34 ++++++++++++++++++- .../v2/menus/ConversationMenuHelper.kt | 3 +- .../conversation/v2/search/SearchBottomBar.kt | 2 -- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 89953bcc04..27b7f6a92a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -13,6 +13,8 @@ import android.util.TypedValue import android.view.* import android.widget.RelativeLayout import androidx.core.view.isVisible +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders import androidx.loader.app.LoaderManager import androidx.loader.content.Loader @@ -47,6 +49,8 @@ import org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCand import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView +import org.thoughtcrime.securesms.conversation.v2.search.SearchBottomBar +import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DraftDatabase import org.thoughtcrime.securesms.database.DraftDatabase.Drafts @@ -70,8 +74,9 @@ import kotlin.math.* // price we pay is a bit of back and forth between the input bar and the conversation activity. class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate, - InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener { + InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, SearchBottomBar.EventListener { private val screenWidth = Resources.getSystem().displayMetrics.widthPixels + private var searchViewModel: SearchViewModel? = null private var linkPreviewViewModel: LinkPreviewViewModel? = null private var threadID: Long = -1 private var actionMode: ActionMode? = null @@ -151,6 +156,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe getLatestOpenGroupInfoIfNeeded() setUpBlockedBanner() setUpLinkPreviewObserver() + searchBottomBar.setEventListener(this) + setUpSearchResultObserver() scrollToFirstUnreadMessageIfNeeded() markAllAsRead() } @@ -751,9 +758,34 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // endregion // region Search + private fun setUpSearchResultObserver() { + val searchViewModel = ViewModelProvider(this).get(SearchViewModel::class.java) + this.searchViewModel = searchViewModel + searchViewModel.searchResults.observe(this, Observer { result: SearchViewModel.SearchResult? -> + if (result == null) return@Observer + if (result.getResults().isNotEmpty()) { + conversationRecyclerView.scrollToPosition(result.position) + val messageResult = result.getResults()[result.position] +// fragment.jumpToMessage(messageResult.messageRecipient.address, messageResult.receivedTimestampMs, Runnable { searchViewModel.onMissingResult() }) + } + this.searchBottomBar.setData(result.position, result.getResults().size) + }) + } + + fun getSearchViewModel(): SearchViewModel? { + return this.searchViewModel + } + fun onSearchQueryUpdated(query: String?) { adapter.onSearchQueryUpdated(query) } + override fun onSearchMoveUpPressed() { + this.searchViewModel?.onMoveUp() + } + + override fun onSearchMoveDownPressed() { + this.searchViewModel?.onMoveDown() + } // endregion } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 4c3a72a9ed..226206d9d3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -18,7 +18,6 @@ import kotlinx.android.synthetic.main.session_logo_action_bar_content.* import network.loki.messenger.R import org.session.libsession.utilities.ExpirationUtil import org.session.libsession.utilities.recipients.Recipient -import org.thoughtcrime.securesms.components.ConversationSearchBottomBar import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.conversation.v2.search.SearchViewModel import org.thoughtcrime.securesms.loki.utilities.getColorWithID @@ -73,7 +72,7 @@ object ConversationMenuHelper { // Search val searchViewItem = menu.findItem(R.id.menu_search) val searchView = searchViewItem.actionView as SearchView - val searchViewModel:SearchViewModel = ViewModelProvider(context as ConversationActivityV2).get(SearchViewModel::class.java) + val searchViewModel = (context as ConversationActivityV2).getSearchViewModel()!! val queryListener = object : OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { searchViewModel.onQueryUpdated(query, threadId) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt index 93d24ff019..9565e6e107 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt @@ -5,8 +5,6 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout -import android.widget.RelativeLayout -import androidx.constraintlayout.widget.ConstraintLayout import kotlinx.android.synthetic.main.view_search_bottom_bar.view.* import network.loki.messenger.R From 1e787660a8f5a7822b5d3a04f741df0c1d61de45 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 14:38:51 +1000 Subject: [PATCH 06/26] clean --- .../securesms/conversation/v2/search/SearchViewModel.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt index f1d7c8a610..ac95af2fa1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt @@ -27,10 +27,6 @@ class SearchViewModel(application: Application) : AndroidViewModel(application) get() = result fun onQueryUpdated(query: String, threadId: Long) { - if (firstSearch && query.length < 2) { - result.postValue(SearchResult(CursorList.emptyList(), 0)) - return - } if (query == activeQuery) { return } From 52305368bb9979fb366006c1359d291b762a5f58 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Tue, 29 Jun 2021 15:35:53 +1000 Subject: [PATCH 07/26] scroll to the position of a search result --- .../conversation/v2/ConversationActivityV2.kt | 23 ++++++++++++++++--- .../conversation/v2/search/SearchBottomBar.kt | 2 +- .../res/layout/view_search_bottom_bar.xml | 3 ++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 27b7f6a92a..36cd9d98dd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -37,10 +37,13 @@ import org.session.libsession.messaging.messages.signal.OutgoingTextMessage import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.sending_receiving.MessageSender +import org.session.libsession.utilities.Address import org.session.libsession.utilities.TextSecurePreferences +import org.session.libsession.utilities.concurrent.SimpleTask import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher +import org.thoughtcrime.securesms.conversation.ConversationFragment import org.thoughtcrime.securesms.conversation.v2.dialogs.* import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate @@ -764,9 +767,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe searchViewModel.searchResults.observe(this, Observer { result: SearchViewModel.SearchResult? -> if (result == null) return@Observer if (result.getResults().isNotEmpty()) { - conversationRecyclerView.scrollToPosition(result.position) - val messageResult = result.getResults()[result.position] -// fragment.jumpToMessage(messageResult.messageRecipient.address, messageResult.receivedTimestampMs, Runnable { searchViewModel.onMissingResult() }) + result.getResults()[result.position]?.let { + jumpToMessage(it.messageRecipient.address, it.receivedTimestampMs, Runnable { searchViewModel.onMissingResult() }) + } } this.searchBottomBar.setData(result.position, result.getResults().size) }) @@ -787,5 +790,19 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe override fun onSearchMoveDownPressed() { this.searchViewModel?.onMoveDown() } + + private fun jumpToMessage(author: Address, timestamp: Long, onMessageNotFound: Runnable?) { + SimpleTask.run(lifecycle, { + DatabaseFactory.getMmsSmsDatabase(this).getMessagePositionInConversation(threadID, timestamp, author) + }) { p: Int -> moveToMessagePosition(p, onMessageNotFound) } + } + + private fun moveToMessagePosition(position: Int, onMessageNotFound: Runnable?) { + if (position >= 0) { + conversationRecyclerView.scrollToPosition(position) + } else { + onMessageNotFound?.run() + } + } // endregion } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt index 9565e6e107..da8df0045a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchBottomBar.kt @@ -36,7 +36,7 @@ class SearchBottomBar : LinearLayout { if (count > 0) { searchPosition.text = resources.getString(R.string.ConversationActivity_search_position, position + 1, count) } else { - searchPosition.setText(R.string.ConversationActivity_no_results) + searchPosition.text = "" } setViewEnabled(searchUp, position < count - 1) setViewEnabled(searchDown, position > 0) diff --git a/app/src/main/res/layout/view_search_bottom_bar.xml b/app/src/main/res/layout/view_search_bottom_bar.xml index e794e75205..bb0395d28e 100644 --- a/app/src/main/res/layout/view_search_bottom_bar.xml +++ b/app/src/main/res/layout/view_search_bottom_bar.xml @@ -52,7 +52,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" - android:text="37 of 73" /> + android:text="37 of 73" + android:textStyle="bold"/> Date: Tue, 29 Jun 2021 16:20:55 +1000 Subject: [PATCH 08/26] fix spinning forever --- .../securesms/conversation/v2/menus/ConversationMenuHelper.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index e708fa1ca9..c9f41c6511 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -99,9 +99,6 @@ object ConversationMenuHelper { val searchViewModel = (context as ConversationActivityV2).getSearchViewModel()!! val queryListener = object : OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { - searchViewModel.onQueryUpdated(query, threadId) - context.searchBottomBar.showLoading() - context.onSearchQueryUpdated(query) return true } From bef74130551ec16332cb7c9f65cdcdfc07f12811 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 10:30:10 +1000 Subject: [PATCH 09/26] Scroll to message upon tapping quote & fix various bugs --- .../conversation/v2/ConversationActivityV2.kt | 32 +++++++++++++------ .../conversation/v2/ConversationAdapter.kt | 18 +++++++++-- .../v2/dialogs/JoinOpenGroupDialog.kt | 9 ++++-- .../v2/messages/ControlMessageView.kt | 3 ++ .../v2/messages/VisibleMessageContentView.kt | 14 ++++++++ .../v2/messages/VisibleMessageView.kt | 3 ++ .../main/res/layout/expiration_timer_menu.xml | 4 +-- .../main/res/layout/view_control_message.xml | 4 ++- 8 files changed, 71 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 2208265831..a16970e6c1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -3,15 +3,14 @@ package org.thoughtcrime.securesms.conversation.v2 import android.Manifest import android.animation.FloatEvaluator import android.animation.ValueAnimator -import android.content.Context import android.content.ClipData import android.content.ClipboardManager +import android.content.Context import android.content.Intent import android.content.res.Resources import android.database.Cursor import android.graphics.Rect import android.graphics.Typeface -import android.os.Bundle import android.net.Uri import android.os.* import android.text.TextUtils @@ -72,6 +71,7 @@ import org.thoughtcrime.securesms.conversation.v2.input_bar.mentions.MentionCand import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallback import org.thoughtcrime.securesms.conversation.v2.menus.ConversationActionModeCallbackDelegate import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper +import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageContentViewDelegate import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.conversation.v2.utilities.AttachmentManager import org.thoughtcrime.securesms.database.DatabaseFactory @@ -84,11 +84,11 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState -import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher -import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity.Companion.selectedContactsKey +import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher import org.thoughtcrime.securesms.loki.utilities.MentionUtilities +import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.MediaSendActivity @@ -108,7 +108,7 @@ import kotlin.math.* class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate, InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher, - ConversationActionModeCallbackDelegate { + ConversationActionModeCallbackDelegate, VisibleMessageContentViewDelegate { private val screenWidth = Resources.getSystem().displayMetrics.widthPixels private var linkPreviewViewModel: LinkPreviewViewModel? = null private var threadID: Long = -1 @@ -147,6 +147,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe }, glide ) + adapter.visibleMessageContentViewDelegate = this adapter } @@ -737,6 +738,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe this.previousText = newText } + override fun scrollToMessageIfPossible(timestamp: Long) { + val lastSeenItemPosition = adapter.getItemPositionForTimestamp(timestamp) ?: return + conversationRecyclerView.scrollToPosition(lastSeenItemPosition) + } + override fun sendMessage() { if (thread.isContactRecipient && thread.isBlocked) { BlockedDialog(thread).show(supportFragmentManager, "Blocked Dialog") @@ -905,10 +911,18 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } override fun startRecordingVoiceMessage() { - showVoiceMessageUI() - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) - audioRecorder.startRecording() - stopAudioHandler.postDelayed(stopVoiceMessageRecordingTask, 60000) // Limit voice messages to 1 minute each + if (Permissions.hasAll(this, Manifest.permission.RECORD_AUDIO)) { + showVoiceMessageUI() + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + audioRecorder.startRecording() + stopAudioHandler.postDelayed(stopVoiceMessageRecordingTask, 60000) // Limit voice messages to 1 minute each + } else { + Permissions.with(this) + .request(Manifest.permission.RECORD_AUDIO) + .withRationaleDialog(getString(R.string.ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone), R.drawable.ic_baseline_mic_48) + .withPermanentDenialDialog(getString(R.string.ConversationActivity_signal_requires_the_microphone_permission_in_order_to_send_audio_messages)) + .execute() + } } override fun sendVoiceMessage() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index c5c0d1e028..6a9273d01f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -8,6 +8,7 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView.ViewHolder import kotlinx.android.synthetic.main.view_visible_message.view.* import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView +import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageContentViewDelegate import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter import org.thoughtcrime.securesms.database.DatabaseFactory @@ -20,6 +21,7 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr : CursorRecyclerViewAdapter(context, cursor) { private val messageDB = DatabaseFactory.getMmsSmsDatabase(context) var selectedItems = mutableSetOf() + var visibleMessageContentViewDelegate: VisibleMessageContentViewDelegate? = null sealed class ViewType(val rawValue: Int) { object Visible : ViewType(0) @@ -72,6 +74,7 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr view.onPress = { rawX, rawY -> onItemPress(message, viewHolder.adapterPosition, view, Rect(rawX, rawY, rawX, rawY)) } view.onSwipeToReply = { onItemSwipeToReply(message, viewHolder.adapterPosition) } view.onLongPress = { onItemLongPress(message, viewHolder.adapterPosition) } + view.contentViewDelegate = visibleMessageContentViewDelegate } is ControlMessageViewHolder -> viewHolder.view.bind(message) } @@ -113,8 +116,19 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr if (lastSeenTimestamp <= 0L || cursor == null || !isActiveCursor) return null for (i in 0 until itemCount) { cursor.moveToPosition(i) - val messageRecord = messageDB.readerFor(cursor).current - if (messageRecord.isOutgoing || messageRecord.dateReceived <= lastSeenTimestamp) { return i } + val message = messageDB.readerFor(cursor).current + if (message.isOutgoing || message.dateReceived <= lastSeenTimestamp) { return i } + } + return null + } + + fun getItemPositionForTimestamp(timestamp: Long): Int? { + val cursor = this.cursor + if (timestamp <= 0L || cursor == null || !isActiveCursor) return null + for (i in 0 until itemCount) { + cursor.moveToPosition(i) + val message = messageDB.readerFor(cursor).current + if (message.dateSent == timestamp) { return i } } return null } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt index 4b89e9d80b..51d85c3651 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/JoinOpenGroupDialog.kt @@ -6,10 +6,12 @@ import android.text.SpannableStringBuilder import android.text.style.StyleSpan import android.view.LayoutInflater import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity import kotlinx.android.synthetic.main.dialog_join_open_group.view.* import network.loki.messenger.R import org.session.libsession.messaging.open_groups.OpenGroupV2 import org.session.libsession.utilities.OpenGroupUrlParser +import org.session.libsignal.utilities.ThreadUtils import org.thoughtcrime.securesms.conversation.v2.utilities.BaseDialog import org.thoughtcrime.securesms.loki.api.OpenGroupManager import org.thoughtcrime.securesms.loki.protocol.MultiDeviceProtocol @@ -33,8 +35,11 @@ class JoinOpenGroupDialog(private val name: String, private val url: String) : B private fun join() { val openGroup = OpenGroupUrlParser.parseUrl(url) - OpenGroupManager.add(openGroup.server, openGroup.room, openGroup.serverPublicKey, requireContext()) - MultiDeviceProtocol.forceSyncConfigurationNowIfNeeded(requireContext()) + val activity = requireContext() as AppCompatActivity + ThreadUtils.queue { + OpenGroupManager.add(openGroup.server, openGroup.room, openGroup.serverPublicKey, activity) + MultiDeviceProtocol.forceSyncConfigurationNowIfNeeded(activity) + } dismiss() } } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index b4f3810e16..78e926d041 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -32,6 +32,9 @@ class ControlMessageView : LinearLayout { if (message.isExpirationTimerUpdate) { iconImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_timer, context.theme)) iconImageView.visibility = View.VISIBLE + } else if (message.isMediaSavedNotification) { + iconImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_file_download_white_36dp, context.theme)) + iconImageView.visibility = View.VISIBLE } textView.text = message.getDisplayBody(context) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index 801a9c6c26..1984de8795 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -23,6 +23,7 @@ import androidx.core.graphics.BlendModeCompat import androidx.core.text.getSpans import androidx.core.text.toSpannable import androidx.core.text.util.LinkifyCompat +import kotlinx.android.synthetic.main.view_link_preview.view.* import kotlinx.android.synthetic.main.view_visible_message_content.view.* import network.loki.messenger.R import org.session.libsession.utilities.ThemeUtil @@ -41,6 +42,7 @@ import kotlin.math.roundToInt class VisibleMessageContentView : LinearLayout { var onContentClick: ((rawRect: Rect) -> Unit)? = null var onContentDoubleTap: (() -> Unit)? = null + var delegate: VisibleMessageContentViewDelegate? = null // region Lifecycle constructor(context: Context) : super(context) { initialize() } @@ -87,6 +89,13 @@ class VisibleMessageContentView : LinearLayout { val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message) ViewUtil.setPaddingTop(bodyTextView, 0) mainContainer.addView(bodyTextView) + onContentClick = { rect -> + val r = Rect() + quoteView.getGlobalVisibleRect(r) + if (r.contains(rect)) { + delegate?.scrollToMessageIfPossible(quote.id) + } + } } else if (message is MmsMessageRecord && message.slideDeck.audioSlide != null) { val voiceMessageView = VoiceMessageView(context) voiceMessageView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster) @@ -188,4 +197,9 @@ class VisibleMessageContentView : LinearLayout { } } // endregion +} + +interface VisibleMessageContentViewDelegate { + + fun scrollToMessageIfPossible(timestamp: Long) } \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 88e4ee9ced..dbcde5c1f9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -48,6 +48,7 @@ class VisibleMessageView : LinearLayout { var onPress: ((rawX: Int, rawY: Int) -> Unit)? = null var onSwipeToReply: (() -> Unit)? = null var onLongPress: (() -> Unit)? = null + var contentViewDelegate: VisibleMessageContentViewDelegate? = null companion object { const val swipeToReplyThreshold = 80.0f // dp @@ -139,6 +140,7 @@ class VisibleMessageView : LinearLayout { if (profilePictureContainer.visibility != View.GONE) { maxWidth -= profilePictureContainer.width } // Populate content view messageContentView.bind(message, isStartOfMessageCluster, isEndOfMessageCluster, glide, maxWidth, thread) + messageContentView.delegate = contentViewDelegate onDoubleTap = { messageContentView.onContentDoubleTap?.invoke() } } @@ -239,6 +241,7 @@ class VisibleMessageView : LinearLayout { } else { longPressCallback?.let { gestureHandler.removeCallbacks(it) } } + if (translationX > 0) { return } // Only allow swipes to the left // The idea here is to asymptotically approach a maximum drag distance val damping = 50.0f val sign = -1.0f diff --git a/app/src/main/res/layout/expiration_timer_menu.xml b/app/src/main/res/layout/expiration_timer_menu.xml index 9fc7a6091b..aec0b39e69 100644 --- a/app/src/main/res/layout/expiration_timer_menu.xml +++ b/app/src/main/res/layout/expiration_timer_menu.xml @@ -10,8 +10,8 @@ + android:layout_marginBottom="@dimen/small_spacing" + app:tint="@color/text" /> Date: Wed, 30 Jun 2021 10:45:31 +1000 Subject: [PATCH 10/26] React to mute & block status changes --- .../conversation/v2/ConversationActivityV2.kt | 16 ++++++++++++++-- .../v2/menus/ConversationMenuHelper.kt | 2 -- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index a16970e6c1..2ed15d27f0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -57,6 +57,7 @@ import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.MediaTypes import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient +import org.session.libsession.utilities.recipients.RecipientModifiedListener import org.session.libsignal.utilities.ListenableFuture import org.session.libsignal.utilities.ThreadUtils import org.thoughtcrime.securesms.ApplicationContext @@ -108,7 +109,7 @@ import kotlin.math.* class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDelegate, InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher, - ConversationActionModeCallbackDelegate, VisibleMessageContentViewDelegate { + ConversationActionModeCallbackDelegate, VisibleMessageContentViewDelegate, RecipientModifiedListener { private val screenWidth = Resources.getSystem().displayMetrics.widthPixels private var linkPreviewViewModel: LinkPreviewViewModel? = null private var threadID: Long = -1 @@ -187,6 +188,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe unreadCount = DatabaseFactory.getMmsSmsDatabase(this).getUnreadCount(threadID) updateUnreadCountIndicator() setUpTypingObserver() + setUpRecipientObserver() updateSubtitle() getLatestOpenGroupInfoIfNeeded() setUpBlockedBanner() @@ -314,6 +316,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } } + private fun setUpRecipientObserver() { + thread.addListener(this) + } + private fun getLatestOpenGroupInfoIfNeeded() { val openGroup = DatabaseFactory.getLokiThreadDatabase(this).getOpenGroupChat(threadID) ?: return OpenGroupAPIV2.getMemberCount(openGroup.room, openGroup.server).successUi { updateSubtitle() } @@ -367,7 +373,13 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } // endregion - // region Updating & Animation + override fun onModified(recipient: Recipient) { + if (thread.isContactRecipient) { + blockedBanner.isVisible = thread.isBlocked + } + updateSubtitle() + } + private fun markAllAsRead() { val messages = DatabaseFactory.getThreadDatabase(this).setRead(threadID, true) if (thread.isGroupRecipient) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index cbac59c280..1b1ec63d0b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -274,13 +274,11 @@ object ConversationMenuHelper { } private fun unmute(context: Context, thread: Recipient) { - thread.setMuted(0) DatabaseFactory.getRecipientDatabase(context).setMuted(thread, 0) } private fun mute(context: Context, thread: Recipient) { MuteDialog.show(context) { until: Long -> - thread.setMuted(until) DatabaseFactory.getRecipientDatabase(context).setMuted(thread, until) } } From c5b117406e974f23e5a9a0b89aebc58717c21136 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 30 Jun 2021 10:59:35 +1000 Subject: [PATCH 11/26] fix spinner shows incorrectly the second time open search screen --- .../conversation/v2/menus/ConversationMenuHelper.kt | 11 ++++++----- .../conversation/v2/search/SearchViewModel.kt | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index c9f41c6511..ec58055a1d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -17,14 +17,14 @@ import android.widget.ImageView import android.widget.TextView import android.widget.Toast import androidx.annotation.ColorInt -import androidx.appcompat.widget.SearchView -import androidx.appcompat.widget.SearchView.OnQueryTextListener -import kotlinx.android.synthetic.main.activity_conversation_v2.* import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.widget.SearchView +import androidx.appcompat.widget.SearchView.OnQueryTextListener import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat import androidx.core.graphics.drawable.IconCompat +import kotlinx.android.synthetic.main.activity_conversation_v2.* import network.loki.messenger.R import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate import org.session.libsession.messaging.sending_receiving.MessageSender @@ -33,10 +33,10 @@ import org.session.libsession.utilities.ExpirationUtil import org.session.libsession.utilities.GroupUtil.doubleDecodeGroupID import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.recipients.Recipient -import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.session.libsignal.utilities.guava.Optional import org.session.libsignal.utilities.toHexString import org.thoughtcrime.securesms.* +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity import org.thoughtcrime.securesms.loki.activities.EditClosedGroupActivity.Companion.groupIDKey @@ -163,7 +163,8 @@ object ConversationMenuHelper { } private fun search(context: Context) { - Toast.makeText(context, "Not yet implemented", Toast.LENGTH_LONG).show() // TODO: Implement + val searchViewModel = (context as ConversationActivityV2).getSearchViewModel()!! + searchViewModel.onSearchOpened() } @SuppressLint("StaticFieldLeak") diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt index ac95af2fa1..eb3dd50d98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/search/SearchViewModel.kt @@ -60,6 +60,7 @@ class SearchViewModel(application: Application) : AndroidViewModel(application) fun onSearchClosed() { searchOpen = false + activeQuery = null debouncer.clear() result.close() } From d3704a6905e33f08bcd045b9fbdc53fa56b4cd29 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 11:02:46 +1000 Subject: [PATCH 12/26] Fix typing indicator overlaying recycler view --- .../conversation/v2/ConversationActivityV2.kt | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 2ed15d27f0..9cf96f76ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -129,6 +129,12 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe private var currentMentionStartIndex = -1 private var isShowingMentionCandidatesView = false + private val isScrolledToBottom: Boolean + get() { + val position = layoutManager.findFirstCompletelyVisibleItemPosition() + return position == 0 + } + private val layoutManager: LinearLayoutManager get() { return conversationRecyclerView.layoutManager as LinearLayoutManager } @@ -302,7 +308,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe private fun setUpTypingObserver() { ApplicationContext.getInstance(this).typingStatusRepository.getTypists(threadID).observe(this) { state -> val recipients = if (state != null) state.typists else listOf() - typingIndicatorViewContainer.isVisible = recipients.isNotEmpty() + // FIXME: Also checking isScrolledToBottom is a quick fix for an issue where the + // typing indicator overlays the recycler view when scrolled up + typingIndicatorViewContainer.isVisible = recipients.isNotEmpty() && isScrolledToBottom typingIndicatorViewContainer.setTypists(recipients) inputBarHeightChanged(inputBar.height) } @@ -580,8 +588,15 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } private fun handleRecyclerViewScrolled() { - val position = layoutManager.findFirstCompletelyVisibleItemPosition() - val alpha = if (position > 0) 1.0f else 0.0f + val alpha = if (!isScrolledToBottom) 1.0f else 0.0f + // FIXME: Checking isScrolledToBottom is a quick fix for an issue where the + // typing indicator overlays the recycler view when scrolled up + val wasTypingIndicatorVisibleBefore = typingIndicatorViewContainer.isVisible + typingIndicatorViewContainer.isVisible = wasTypingIndicatorVisibleBefore && isScrolledToBottom + val isTypingIndicatorVisibleAfter = typingIndicatorViewContainer.isVisible + if (isTypingIndicatorVisibleAfter != wasTypingIndicatorVisibleBefore) { + inputBarHeightChanged(inputBar.height) + } scrollToBottomButton.alpha = alpha unreadCount = min(unreadCount, layoutManager.findFirstVisibleItemPosition()) updateUnreadCountIndicator() From 55ad96dcf71a9e6c99fa6be03afa6d76f29c0f38 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Wed, 30 Jun 2021 11:44:26 +1000 Subject: [PATCH 13/26] hide search screen when long pressing --- .../conversation/v2/ConversationActivityV2.kt | 22 +++++++++---------- .../v2/menus/ConversationMenuHelper.kt | 5 +++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 363fcab014..a6e94b294b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -3,15 +3,14 @@ package org.thoughtcrime.securesms.conversation.v2 import android.Manifest import android.animation.FloatEvaluator import android.animation.ValueAnimator -import android.content.Context import android.content.ClipData import android.content.ClipboardManager +import android.content.Context import android.content.Intent import android.content.res.Resources import android.database.Cursor import android.graphics.Rect import android.graphics.Typeface -import android.os.Bundle import android.net.Uri import android.os.* import android.text.TextUtils @@ -53,14 +52,14 @@ import org.session.libsession.messaging.messages.visible.OpenGroupInvitation import org.session.libsession.messaging.messages.visible.VisibleMessage import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.messaging.sending_receiving.MessageSender -import org.session.libsession.utilities.Address -import org.session.libsession.utilities.TextSecurePreferences -import org.session.libsession.utilities.concurrent.SimpleTask import org.session.libsession.messaging.sending_receiving.attachments.Attachment import org.session.libsession.messaging.sending_receiving.link_preview.LinkPreview import org.session.libsession.messaging.sending_receiving.quotes.QuoteModel +import org.session.libsession.utilities.Address import org.session.libsession.utilities.Address.Companion.fromSerialized import org.session.libsession.utilities.MediaTypes +import org.session.libsession.utilities.TextSecurePreferences +import org.session.libsession.utilities.concurrent.SimpleTask import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.ListenableFuture import org.session.libsignal.utilities.ThreadUtils @@ -90,11 +89,11 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel.LinkPreviewState -import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher -import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity import org.thoughtcrime.securesms.loki.activities.SelectContactsActivity.Companion.selectedContactsKey +import org.thoughtcrime.securesms.loki.utilities.ActivityDispatcher import org.thoughtcrime.securesms.loki.utilities.MentionUtilities +import org.thoughtcrime.securesms.loki.utilities.push import org.thoughtcrime.securesms.loki.utilities.toPx import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.MediaSendActivity @@ -116,7 +115,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe InputBarRecordingViewDelegate, AttachmentManager.AttachmentListener, ActivityDispatcher, ConversationActionModeCallbackDelegate, SearchBottomBar.EventListener { private val screenWidth = Resources.getSystem().displayMetrics.widthPixels - private var searchViewModel: SearchViewModel? = null private var linkPreviewViewModel: LinkPreviewViewModel? = null private var threadID: Long = -1 private var actionMode: ActionMode? = null @@ -134,6 +132,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe private var previousText: CharSequence = "" private var currentMentionStartIndex = -1 private var isShowingMentionCandidatesView = false + // Search + var searchViewModel: SearchViewModel? = null + var searchViewItem: MenuItem? = null private val layoutManager: LinearLayoutManager get() { return conversationRecyclerView.layoutManager as LinearLayoutManager } @@ -650,6 +651,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val actionMode = this.actionMode val actionModeCallback = ConversationActionModeCallback(adapter, threadID, this) actionModeCallback.delegate = this + searchViewItem?.collapseActionView() if (actionMode == null) { // Nothing should be selected if this is the case adapter.toggleSelection(message, position) this.actionMode = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { @@ -1138,10 +1140,6 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe }) } - fun getSearchViewModel(): SearchViewModel? { - return this.searchViewModel - } - fun onSearchQueryUpdated(query: String?) { adapter.onSearchQueryUpdated(query) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index ec58055a1d..23a1758656 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -95,8 +95,9 @@ object ConversationMenuHelper { // Search val searchViewItem = menu.findItem(R.id.menu_search) + (context as ConversationActivityV2).searchViewItem = searchViewItem val searchView = searchViewItem.actionView as SearchView - val searchViewModel = (context as ConversationActivityV2).getSearchViewModel()!! + val searchViewModel = context.searchViewModel!! val queryListener = object : OnQueryTextListener { override fun onQueryTextSubmit(query: String): Boolean { return true @@ -163,7 +164,7 @@ object ConversationMenuHelper { } private fun search(context: Context) { - val searchViewModel = (context as ConversationActivityV2).getSearchViewModel()!! + val searchViewModel = (context as ConversationActivityV2).searchViewModel!! searchViewModel.onSearchOpened() } From 4989bf4b8b586ad537e751268914d4e7ae97b148 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 13:15:39 +1000 Subject: [PATCH 14/26] Fix threading issue --- .../securesms/conversation/v2/ConversationActivityV2.kt | 8 +++++--- .../org/thoughtcrime/securesms/database/SmsDatabase.java | 1 - .../java/org/thoughtcrime/securesms/database/Storage.kt | 5 ++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 9cf96f76ea..9182bef1d0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -382,10 +382,12 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // endregion override fun onModified(recipient: Recipient) { - if (thread.isContactRecipient) { - blockedBanner.isVisible = thread.isBlocked + runOnUiThread { + if (thread.isContactRecipient) { + blockedBanner.isVisible = thread.isBlocked + } + updateSubtitle() } - updateSubtitle() } private fun markAllAsRead() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index d241db9862..0fda92dc56 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -411,7 +411,6 @@ public class SmsDatabase extends MessagingDatabase { notifyConversationListeners(threadId); - return Optional.of(new InsertResult(messageId, threadId)); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index 1c67eac4e3..ddf882a589 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -1,6 +1,5 @@ package org.thoughtcrime.securesms.database -import android.app.job.JobScheduler import android.content.Context import android.net.Uri import org.session.libsession.database.StorageProtocol @@ -105,7 +104,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, } else -> Optional.absent() } - val pointerAttachments = attachments.mapNotNull { + val pointers = attachments.mapNotNull { it.toSignalAttachment() } val targetAddress = if (isUserSender && !message.syncTarget.isNullOrEmpty()) { @@ -121,7 +120,7 @@ class Storage(context: Context, helper: SQLCipherOpenHelper) : Database(context, val linkPreviews: Optional> = if (linkPreview.isEmpty()) Optional.absent() else Optional.of(linkPreview.mapNotNull { it!! }) val mmsDatabase = DatabaseFactory.getMmsDatabase(context) val insertResult = if (message.sender == getUserPublicKey()) { - val mediaMessage = OutgoingMediaMessage.from(message, targetRecipient, pointerAttachments, quote.orNull(), linkPreviews.orNull()?.firstOrNull()) + val mediaMessage = OutgoingMediaMessage.from(message, targetRecipient, pointers, quote.orNull(), linkPreviews.orNull()?.firstOrNull()) mmsDatabase.insertSecureDecryptedMessageOutbox(mediaMessage, message.threadID ?: -1, message.sentTimestamp!!) } else { // It seems like we have replaced SignalServiceAttachment with SessionServiceAttachment From 907e0e497472c3d80299829ba65bfff246f93e74 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 13:25:58 +1000 Subject: [PATCH 15/26] Remove problematic movement method --- .../conversation/v2/messages/VisibleMessageContentView.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index 1984de8795..ff5422372d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -181,7 +181,6 @@ class VisibleMessageContentView : LinearLayout { body = MentionUtilities.highlightMentions(body, message.isOutgoing, message.threadId, context); result.text = body - result.movementMethod = LinkMovementMethod.getInstance() return result } From 1fbb3d3dd51f2546e6eae23c1eb855d861350b01 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 13:49:23 +1000 Subject: [PATCH 16/26] Fix message deletion threading bug --- .../conversation/v2/ConversationActivityV2.kt | 12 +++++------- .../thoughtcrime/securesms/database/MmsDatabase.java | 5 +++-- .../thoughtcrime/securesms/database/SmsDatabase.java | 4 +++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 9182bef1d0..26d871c619 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -1006,13 +1006,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } } } else { - ThreadUtils.queue { - for (message in messages) { - if (message.isMms) { - DatabaseFactory.getMmsDatabase(this@ConversationActivityV2).delete(message.id) - } else { - DatabaseFactory.getSmsDatabase(this@ConversationActivityV2).deleteMessage(message.id) - } + for (message in messages) { + if (message.isMms) { + DatabaseFactory.getMmsDatabase(this@ConversationActivityV2).delete(message.id) + } else { + DatabaseFactory.getSmsDatabase(this@ConversationActivityV2).deleteMessage(message.id) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java index ed443591f0..ce2ddba24a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java @@ -57,6 +57,7 @@ import org.session.libsession.utilities.recipients.Recipient; import org.session.libsession.utilities.recipients.RecipientFormattingException; import org.session.libsignal.utilities.JsonUtil; import org.session.libsignal.utilities.Log; +import org.session.libsignal.utilities.ThreadUtils; import org.session.libsignal.utilities.guava.Optional; import org.thoughtcrime.securesms.attachments.MmsNotificationAttachment; import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper; @@ -881,9 +882,9 @@ public class MmsDatabase extends MessagingDatabase { } public boolean delete(long messageId) { - long threadId = getThreadIdForMessage(messageId); + long threadId = getThreadIdForMessage(messageId); AttachmentDatabase attachmentDatabase = DatabaseFactory.getAttachmentDatabase(context); - attachmentDatabase.deleteAttachmentsForMessage(messageId); + ThreadUtils.queue(() -> attachmentDatabase.deleteAttachmentsForMessage(messageId)); GroupReceiptDatabase groupReceiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context); groupReceiptDatabase.deleteRowsForMessage(messageId); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 0fda92dc56..6706f5fe77 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -20,6 +20,8 @@ package org.thoughtcrime.securesms.database; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; +import android.os.Handler; +import android.os.Looper; import android.text.TextUtils; import android.util.Pair; @@ -511,7 +513,7 @@ public class SmsDatabase extends MessagingDatabase { public boolean deleteMessage(long messageId) { Log.i("MessageDatabase", "Deleting: " + messageId); SQLiteDatabase db = databaseHelper.getWritableDatabase(); - long threadId = getThreadIdForMessage(messageId); + long threadId = getThreadIdForMessage(messageId); db.delete(TABLE_NAME, ID_WHERE, new String[] {messageId+""}); boolean threadDeleted = DatabaseFactory.getThreadDatabase(context).update(threadId, false); notifyConversationListeners(threadId); From 07de201fde7e781801c33e56d04328de40b3425f Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 14:05:30 +1000 Subject: [PATCH 17/26] Hide input if the user isn't part of a group --- .../conversation/v2/ConversationActivityV2.kt | 14 ++++++++++++++ .../conversation/v2/input_bar/InputBar.kt | 15 +++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 26d871c619..d25dc2842c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -201,6 +201,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe setUpLinkPreviewObserver() scrollToFirstUnreadMessageIfNeeded() markAllAsRead() + showOrHideInputIfNeeded() } override fun onResume() { @@ -381,12 +382,25 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } // endregion + // region Animation & Updating override fun onModified(recipient: Recipient) { runOnUiThread { if (thread.isContactRecipient) { blockedBanner.isVisible = thread.isBlocked } updateSubtitle() + showOrHideInputIfNeeded() + } + } + + private fun showOrHideInputIfNeeded() { + if (thread.isClosedGroupRecipient) { + val group = DatabaseFactory.getGroupDatabase(this).getGroup(thread.address.toGroupString()).orNull() + val isActive = (group?.isActive == true) + Log.d("Test", "isActive: $isActive") + inputBar.showInput = isActive + } else { + inputBar.showInput = true } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt index 31be742776..b565f21766 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/input_bar/InputBar.kt @@ -31,6 +31,8 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li var additionalContentHeight = 0 var quote: MessageRecord? = null var linkPreview: LinkPreview? = null + var showInput: Boolean = true + set(value) { field = value; showOrHideInputIfNeeded() } var text: String get() { return inputBarEditText.text.toString() } @@ -159,6 +161,19 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li additionalContentHeight = 0 setHeight(newHeight) } + + private fun showOrHideInputIfNeeded() { + if (showInput) { + setOf( inputBarEditText, attachmentsButton ).forEach { it.isVisible = true } + microphoneButton.isVisible = text.isEmpty() + sendButton.isVisible = text.isNotEmpty() + } else { + cancelQuoteDraft() + cancelLinkPreviewDraft() + val views = setOf( inputBarEditText, attachmentsButton, microphoneButton, sendButton ) + views.forEach { it.isVisible = false } + } + } // endregion } From 91570dc0b28cfae3d171417874e62de6cbb3671f Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 14:05:53 +1000 Subject: [PATCH 18/26] Remove resolved TODO --- .../securesms/conversation/v2/menus/ConversationMenuHelper.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt index 1b1ec63d0b..1e55fca6ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/menus/ConversationMenuHelper.kt @@ -254,7 +254,6 @@ object ConversationMenuHelper { try { if (isClosedGroup) { MessageSender.leave(groupPublicKey!!, true) - // TODO: Disable input? } else { Toast.makeText(context, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show() } From 1c14755d9a273a01ffe22dd21065d38435ddf136 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 14:07:03 +1000 Subject: [PATCH 19/26] Update build number --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 26a37e8200..cf772c0a75 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -143,7 +143,7 @@ dependencies { testImplementation 'org.robolectric:shadows-multidex:4.2' } -def canonicalVersionCode = 184 +def canonicalVersionCode = 186 def canonicalVersionName = "1.11.0" def postFixSize = 10 From 24b5fca7f89a45f203c8645bf61436e2a5d4b5e2 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 14:47:35 +1000 Subject: [PATCH 20/26] Move ExpirationTimerView --- .../securesms/components/ConversationItemFooter.java | 1 + .../{ => conversation/v2}/components/ExpirationTimerView.java | 3 +-- app/src/main/res/layout/conversation_item_footer.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename app/src/main/java/org/thoughtcrime/securesms/{ => conversation/v2}/components/ExpirationTimerView.java (98%) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java index ac5ee5004c..b93ae4ab65 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ConversationItemFooter.java @@ -14,6 +14,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.thoughtcrime.securesms.ApplicationContext; +import org.thoughtcrime.securesms.conversation.v2.components.ExpirationTimerView; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.service.ExpiringMessageManager; diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ExpirationTimerView.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/ExpirationTimerView.java similarity index 98% rename from app/src/main/java/org/thoughtcrime/securesms/components/ExpirationTimerView.java rename to app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/ExpirationTimerView.java index 65cad0a274..5a04e77ac2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ExpirationTimerView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/components/ExpirationTimerView.java @@ -1,4 +1,4 @@ -package org.thoughtcrime.securesms.components; +package org.thoughtcrime.securesms.conversation.v2.components; import android.content.Context; import androidx.annotation.NonNull; @@ -118,5 +118,4 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag Util.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn)); } } - } diff --git a/app/src/main/res/layout/conversation_item_footer.xml b/app/src/main/res/layout/conversation_item_footer.xml index 740234f0e9..ab16a09304 100644 --- a/app/src/main/res/layout/conversation_item_footer.xml +++ b/app/src/main/res/layout/conversation_item_footer.xml @@ -26,7 +26,7 @@ android:textAllCaps="true" tools:text="30 mins"/> - Date: Wed, 30 Jun 2021 14:51:24 +1000 Subject: [PATCH 21/26] Fix merge --- .../conversation/v2/messages/VisibleMessageContentView.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt index 0776186266..f5f1fd1ccc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageContentView.kt @@ -89,10 +89,10 @@ class VisibleMessageContentView : LinearLayout { val bodyTextView = VisibleMessageContentView.getBodyTextView(context, message) ViewUtil.setPaddingTop(bodyTextView, 0) mainContainer.addView(bodyTextView) - onContentClick = { rect -> + onContentClick = { event -> val r = Rect() quoteView.getGlobalVisibleRect(r) - if (r.contains(rect)) { + if (r.contains(event.rawX.roundToInt(), event.rawY.roundToInt())) { delegate?.scrollToMessageIfPossible(quote.id) } } From 764a8852805063baa39e776c6e9ac330c004276a Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 14:57:53 +1000 Subject: [PATCH 22/26] Hook up new conversation screen everywhere --- .../main/java/org/thoughtcrime/securesms/ShareActivity.java | 5 +++-- .../securesms/conversation/ConversationPopupActivity.java | 5 +++-- .../securesms/loki/activities/CreateClosedGroupActivity.kt | 5 +++-- .../securesms/loki/activities/CreatePrivateChatActivity.kt | 5 +++-- .../securesms/loki/activities/JoinPublicChatActivity.kt | 5 +++-- .../thoughtcrime/securesms/loki/activities/QRCodeActivity.kt | 5 +++-- .../securesms/notifications/DefaultMessageNotifier.java | 5 +++-- .../securesms/notifications/NotificationItem.java | 5 +++-- .../thoughtcrime/securesms/util/CommunicationActions.java | 5 +++-- 9 files changed, 27 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java index a4a17b7389..4191734b0e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java @@ -39,6 +39,7 @@ import org.session.libsession.utilities.DistributionTypes; import org.thoughtcrime.securesms.components.SearchToolbar; import org.thoughtcrime.securesms.conversation.ConversationActivity; import org.session.libsession.utilities.Address; +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.loki.fragments.ContactSelectionListFragment; @@ -215,9 +216,9 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity } private void createConversation(long threadId, Address address, int distributionType) { - final Intent intent = getBaseShareIntent(ConversationActivity.class); + final Intent intent = getBaseShareIntent(ConversationActivityV2.class); intent.putExtra(ConversationActivity.ADDRESS_EXTRA, address); - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType); isPassingAlongMedia = true; diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java index f288ac5ba5..039df6879f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java @@ -14,6 +14,7 @@ import android.view.WindowManager; import org.session.libsignal.utilities.Log; import org.session.libsignal.utilities.ListenableFuture; +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2; import java.util.concurrent.ExecutionException; @@ -80,9 +81,9 @@ public class ConversationPopupActivity extends ConversationActivity { @Override public void onSuccess(Long result) { ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height); - Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivity.class); + Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivityV2.class); intent.putExtra(ConversationActivity.ADDRESS_EXTRA, getRecipient().getAddress()); - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, result); + intent.putExtra(ConversationActivityV2.THREAD_ID, result); if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { startActivity(intent, transition.toBundle()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt index f13dee1d46..d2208672d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt @@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.loki.utilities.fadeOut import org.thoughtcrime.securesms.mms.GlideApp import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.TextSecurePreferences +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 //TODO Refactor to avoid using kotlinx.android.synthetic class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderManager.LoaderCallbacks> { @@ -135,8 +136,8 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM // region Convenience private fun openConversationActivity(context: Context, threadId: Long, recipient: Recipient) { - val intent = Intent(context, ConversationActivity::class.java) - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId) + val intent = Intent(context, ConversationActivityV2::class.java) + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId) intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) context.startActivity(intent) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt index 7f75b9cc77..8b2bf5fdcc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt @@ -30,6 +30,7 @@ import org.session.libsession.utilities.recipients.Recipient import org.session.libsignal.utilities.PublicKeyValidation import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.ConversationActivity +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragmentDelegate @@ -111,12 +112,12 @@ class CreatePrivateChatActivity : PassphraseRequiredActionBarActivity(), ScanQRC private fun createPrivateChat(hexEncodedPublicKey: String) { val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false) - val intent = Intent(this, ConversationActivity::class.java) + val intent = Intent(this, ConversationActivityV2::class.java) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA)) intent.setDataAndType(getIntent().data, getIntent().type) val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient) - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread) + intent.putExtra(ConversationActivityV2.THREAD_ID, existingThread) intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT) startActivity(intent) finish() diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt index deec2bf434..609e68ca02 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt @@ -33,6 +33,7 @@ import org.session.libsignal.utilities.PublicKeyValidation import org.thoughtcrime.securesms.BaseActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.conversation.ConversationActivity +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.loki.api.OpenGroupManager import org.thoughtcrime.securesms.loki.fragments.ScanQRCodeWrapperFragment @@ -127,8 +128,8 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode // region Convenience private fun openConversationActivity(context: Context, threadId: Long, recipient: Recipient) { - val intent = Intent(context, ConversationActivity::class.java) - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId) + val intent = Intent(context, ConversationActivityV2::class.java) + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId) intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) context.startActivity(intent) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt index dd6bf3420e..4bf2b7add6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt @@ -26,6 +26,7 @@ import org.session.libsession.utilities.recipients.Recipient import org.thoughtcrime.securesms.util.FileProviderUtil import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.PublicKeyValidation +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2 import java.io.File import java.io.FileOutputStream @@ -53,12 +54,12 @@ class QRCodeActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperF fun createPrivateChatIfPossible(hexEncodedPublicKey: String) { if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, R.string.invalid_session_id, Toast.LENGTH_SHORT).show() } val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false) - val intent = Intent(this, ConversationActivity::class.java) + val intent = Intent(this, ConversationActivityV2::class.java) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA)) intent.setDataAndType(getIntent().data, getIntent().type) val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient) - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, existingThread) + intent.putExtra(ConversationActivityV2.THREAD_ID, existingThread) intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT) startActivity(intent) finish() diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index 532c953152..9cea8a79b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -49,6 +49,7 @@ import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.contactshare.ContactUtil; import org.thoughtcrime.securesms.conversation.ConversationActivity; +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MessagingDatabase.MarkedMessageInfo; import org.thoughtcrime.securesms.database.MmsSmsDatabase; @@ -115,9 +116,9 @@ public class DefaultMessageNotifier implements MessageNotifier { if (visibleThread == threadId) { sendInThreadNotification(context, recipient); } else { - Intent intent = new Intent(context, ConversationActivity.class); + Intent intent = new Intent(context, ConversationActivityV2.class); intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress()); - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.setData((Uri.parse("custom://" + System.currentTimeMillis()))); FailedNotificationBuilder builder = new FailedNotificationBuilder(context, TextSecurePreferences.getNotificationPrivacy(context), intent); diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java index e92f62aa44..4bc066df74 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import androidx.core.app.TaskStackBuilder; import org.thoughtcrime.securesms.conversation.ConversationActivity; +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2; import org.thoughtcrime.securesms.mms.SlideDeck; import org.session.libsession.utilities.recipients.Recipient; @@ -67,11 +68,11 @@ public class NotificationItem { } public PendingIntent getPendingIntent(Context context) { - Intent intent = new Intent(context, ConversationActivity.class); + Intent intent = new Intent(context, ConversationActivityV2.class); Recipient notifyRecipients = threadRecipient != null ? threadRecipient : conversationRecipient; if (notifyRecipients != null) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, notifyRecipients.getAddress()); - intent.putExtra("thread_id", threadId); + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.setData((Uri.parse("custom://"+System.currentTimeMillis()))); return TaskStackBuilder.create(context) diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java index 418de713cb..a42a18a302 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java @@ -14,6 +14,7 @@ import android.widget.Toast; import org.thoughtcrime.securesms.conversation.ConversationActivity; import network.loki.messenger.R; +import org.thoughtcrime.securesms.conversation.v2.ConversationActivityV2; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.session.libsession.utilities.recipients.Recipient; @@ -32,9 +33,9 @@ public class CommunicationActions { @Override protected void onPostExecute(Long threadId) { - Intent intent = new Intent(context, ConversationActivity.class); + Intent intent = new Intent(context, ConversationActivityV2.class); intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress()); - intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, threadId); + intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis()); if (!TextUtils.isEmpty(text)) { From fa0b6703e18bff2813ab7ea6142e22d183f056af Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 30 Jun 2021 15:40:15 +1000 Subject: [PATCH 23/26] Add message expiration timer icon --- .../v2/messages/VisibleMessageView.kt | 40 +++- .../res/layout/view_search_bottom_bar.xml | 2 +- .../main/res/layout/view_visible_message.xml | 188 ++++++++++-------- 3 files changed, 140 insertions(+), 90 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt index 23465fbe37..a617ddb781 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VisibleMessageView.kt @@ -3,22 +3,27 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context import android.content.res.Resources import android.graphics.Canvas +import android.graphics.ColorFilter import android.graphics.Rect import android.graphics.drawable.ColorDrawable +import android.os.AsyncTask import android.os.Build import android.os.Handler import android.os.Looper import android.util.AttributeSet import android.view.* import android.widget.LinearLayout +import android.widget.RelativeLayout import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat import androidx.core.view.isVisible import kotlinx.android.synthetic.main.view_visible_message.view.* -import kotlinx.android.synthetic.main.view_visible_message.view.profilePictureView import network.loki.messenger.R import org.session.libsession.messaging.contacts.Contact.ContactContext import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 import org.session.libsession.utilities.ViewUtil +import org.session.libsignal.utilities.ThreadUtils +import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.loki.utilities.getColorWithID @@ -135,6 +140,8 @@ class VisibleMessageView : LinearLayout { } else { messageStatusImageView.isVisible = false } + // Expiration timer + updateExpirationTimer(message) // Calculate max message bubble width var maxWidth = screenWidth - messageContentContainerLayoutParams.leftMargin - messageContentContainerLayoutParams.rightMargin if (profilePictureContainer.visibility != View.GONE) { maxWidth -= profilePictureContainer.width } @@ -181,6 +188,37 @@ class VisibleMessageView : LinearLayout { } } + private fun updateExpirationTimer(message: MessageRecord) { + val expirationTimerViewLayoutParams = expirationTimerView.layoutParams as RelativeLayout.LayoutParams + val ruleToAdd = if (message.isOutgoing) RelativeLayout.ALIGN_PARENT_START else RelativeLayout.ALIGN_PARENT_END + val ruleToRemove = if (message.isOutgoing) RelativeLayout.ALIGN_PARENT_END else RelativeLayout.ALIGN_PARENT_START + expirationTimerViewLayoutParams.removeRule(ruleToRemove) + expirationTimerViewLayoutParams.addRule(ruleToAdd) + expirationTimerView.layoutParams = expirationTimerViewLayoutParams + if (message.expiresIn > 0 && !message.isPending) { + expirationTimerView.setColorFilter(ResourcesCompat.getColor(resources, R.color.text, context.theme)) + expirationTimerView.isVisible = true + expirationTimerView.setPercentComplete(0.0f) + if (message.expireStarted > 0) { + expirationTimerView.setExpirationTime(message.expireStarted, message.expiresIn) + expirationTimerView.startAnimation() + if (message.expireStarted + message.expiresIn <= System.currentTimeMillis()) { + ApplicationContext.getInstance(context).expiringMessageManager.checkSchedule() + } + } else if (!message.isOutgoing && !message.isMediaPending) { + ThreadUtils.queue { + val expirationManager = ApplicationContext.getInstance(context).expiringMessageManager + val id = message.getId() + val mms = message.isMms + if (mms) DatabaseFactory.getMmsDatabase(context).markExpireStarted(id) else DatabaseFactory.getSmsDatabase(context).markExpireStarted(id) + expirationManager.scheduleDeletion(id, mms, message.expiresIn) + } + } + } else { + expirationTimerView.isVisible = false + } + } + private fun handleIsSelectedChanged() { background = if (snIsSelected) { ColorDrawable(context.resources.getColorWithID(R.color.message_selected, context.theme)) diff --git a/app/src/main/res/layout/view_search_bottom_bar.xml b/app/src/main/res/layout/view_search_bottom_bar.xml index bb0395d28e..2cb3299be1 100644 --- a/app/src/main/res/layout/view_search_bottom_bar.xml +++ b/app/src/main/res/layout/view_search_bottom_bar.xml @@ -5,7 +5,7 @@ android:id="@+id/searchBottomBarConstraintLayout" android:layout_width="match_parent" android:layout_height="@dimen/input_bar_height" - android:background="@color/compose_view_background" + android:background="@color/input_bar_background" android:orientation="vertical"> - - - + android:layout_height="wrap_content"> + android:orientation="vertical"> + + + android:orientation="horizontal" + android:gravity="bottom"> - - - - - - - - - - - - - - - - - + android:orientation="horizontal"> - + + + + + + + + + + + + + + - - + android:layout_height="wrap_content" + android:orientation="vertical"> + android:ellipsize="end" /> - + - + + + + + + + + + - \ No newline at end of file + + + \ No newline at end of file From 4cec9e684fb32ba8c8af2138a80cb5863c0a2cd7 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 1 Jul 2021 09:31:30 +1000 Subject: [PATCH 24/26] Fix crash --- .../java/org/thoughtcrime/securesms/ShareActivity.java | 2 +- .../conversation/ConversationPopupActivity.java | 2 +- .../securesms/conversation/v2/ConversationActivityV2.kt | 9 ++++++++- .../loki/activities/CreateClosedGroupActivity.kt | 2 +- .../loki/activities/CreatePrivateChatActivity.kt | 2 +- .../securesms/loki/activities/JoinPublicChatActivity.kt | 2 +- .../securesms/loki/activities/QRCodeActivity.kt | 2 +- .../securesms/notifications/DefaultMessageNotifier.java | 2 +- .../securesms/notifications/NotificationItem.java | 2 +- .../securesms/util/CommunicationActions.java | 2 +- 10 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java index 4191734b0e..8f820cba54 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ShareActivity.java @@ -217,7 +217,7 @@ public class ShareActivity extends PassphraseRequiredActionBarActivity private void createConversation(long threadId, Address address, int distributionType) { final Intent intent = getBaseShareIntent(ConversationActivityV2.class); - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, address); + intent.putExtra(ConversationActivityV2.ADDRESS, address); intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, distributionType); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java index 039df6879f..ece1bb784d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationPopupActivity.java @@ -82,7 +82,7 @@ public class ConversationPopupActivity extends ConversationActivity { public void onSuccess(Long result) { ActivityOptionsCompat transition = ActivityOptionsCompat.makeScaleUpAnimation(getWindow().getDecorView(), 0, 0, getWindow().getAttributes().width, getWindow().getAttributes().height); Intent intent = new Intent(ConversationPopupActivity.this, ConversationActivityV2.class); - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, getRecipient().getAddress()); + intent.putExtra(ConversationActivityV2.ADDRESS, getRecipient().getAddress()); intent.putExtra(ConversationActivityV2.THREAD_ID, result); if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index 42071eb823..e5148d571a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -182,6 +182,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // region Settings companion object { const val THREAD_ID = "thread_id" + const val ADDRESS = "address" const val PICK_DOCUMENT = 2 const val TAKE_PHOTO = 7 const val PICK_GIF = 10 @@ -194,7 +195,13 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { super.onCreate(savedInstanceState, isReady) setContentView(R.layout.activity_conversation_v2) - threadID = intent.getLongExtra(THREAD_ID, -1) + var threadID = intent.getLongExtra(THREAD_ID, -1L) + if (threadID == -1L) { + val address = intent.getParcelableExtra
(ADDRESS) ?: return finish() + val recipient = Recipient.from(this, address, false) + threadID = DatabaseFactory.getThreadDatabase(this).getOrCreateThreadIdFor(recipient) + } + this.threadID = threadID setUpRecyclerView() setUpToolBar() setUpInputBar() diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt index d2208672d4..df4f3ce614 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreateClosedGroupActivity.kt @@ -139,7 +139,7 @@ private fun openConversationActivity(context: Context, threadId: Long, recipient val intent = Intent(context, ConversationActivityV2::class.java) intent.putExtra(ConversationActivityV2.THREAD_ID, threadId) intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT) - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address) context.startActivity(intent) } // endregion \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt index 8b2bf5fdcc..7d429bf223 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/CreatePrivateChatActivity.kt @@ -113,7 +113,7 @@ class CreatePrivateChatActivity : PassphraseRequiredActionBarActivity(), ScanQRC private fun createPrivateChat(hexEncodedPublicKey: String) { val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false) val intent = Intent(this, ConversationActivityV2::class.java) - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address) intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA)) intent.setDataAndType(getIntent().data, getIntent().type) val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient) diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt index 609e68ca02..dc038cc0cb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/JoinPublicChatActivity.kt @@ -131,7 +131,7 @@ class JoinPublicChatActivity : PassphraseRequiredActionBarActivity(), ScanQRCode val intent = Intent(context, ConversationActivityV2::class.java) intent.putExtra(ConversationActivityV2.THREAD_ID, threadId) intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, DistributionTypes.DEFAULT) - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address) context.startActivity(intent) } // endregion diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt index 4bf2b7add6..96d175ef99 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/activities/QRCodeActivity.kt @@ -55,7 +55,7 @@ class QRCodeActivity : PassphraseRequiredActionBarActivity(), ScanQRCodeWrapperF if (!PublicKeyValidation.isValid(hexEncodedPublicKey)) { return Toast.makeText(this, R.string.invalid_session_id, Toast.LENGTH_SHORT).show() } val recipient = Recipient.from(this, Address.fromSerialized(hexEncodedPublicKey), false) val intent = Intent(this, ConversationActivityV2::class.java) - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.address) + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.address) intent.putExtra(ConversationActivity.TEXT_EXTRA, getIntent().getStringExtra(ConversationActivity.TEXT_EXTRA)) intent.setDataAndType(getIntent().data, getIntent().type) val existingThread = DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient) diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java index 9cea8a79b6..a0c1046e07 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/DefaultMessageNotifier.java @@ -117,7 +117,7 @@ public class DefaultMessageNotifier implements MessageNotifier { sendInThreadNotification(context, recipient); } else { Intent intent = new Intent(context, ConversationActivityV2.class); - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress()); + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.getAddress()); intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.setData((Uri.parse("custom://" + System.currentTimeMillis()))); diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java index 4bc066df74..c2041a84fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/NotificationItem.java @@ -70,7 +70,7 @@ public class NotificationItem { public PendingIntent getPendingIntent(Context context) { Intent intent = new Intent(context, ConversationActivityV2.class); Recipient notifyRecipients = threadRecipient != null ? threadRecipient : conversationRecipient; - if (notifyRecipients != null) intent.putExtra(ConversationActivity.ADDRESS_EXTRA, notifyRecipients.getAddress()); + if (notifyRecipients != null) intent.putExtra(ConversationActivityV2.ADDRESS, notifyRecipients.getAddress()); intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.setData((Uri.parse("custom://"+System.currentTimeMillis()))); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java index a42a18a302..e8dd7cd589 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/CommunicationActions.java @@ -34,7 +34,7 @@ public class CommunicationActions { @Override protected void onPostExecute(Long threadId) { Intent intent = new Intent(context, ConversationActivityV2.class); - intent.putExtra(ConversationActivity.ADDRESS_EXTRA, recipient.getAddress()); + intent.putExtra(ConversationActivityV2.ADDRESS, recipient.getAddress()); intent.putExtra(ConversationActivityV2.THREAD_ID, threadId); intent.putExtra(ConversationActivity.TIMING_EXTRA, System.currentTimeMillis()); From 0221784d6063787b04d511c2ba091b6ec4ba2344 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 1 Jul 2021 09:54:09 +1000 Subject: [PATCH 25/26] Fix attachment sharing --- .../conversation/v2/ConversationActivityV2.kt | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index e5148d571a..edf90a0f98 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -63,11 +63,13 @@ import org.session.libsession.utilities.concurrent.SimpleTask import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.RecipientModifiedListener import org.session.libsignal.utilities.ListenableFuture -import org.session.libsignal.utilities.ThreadUtils +import org.session.libsignal.utilities.SettableFuture +import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.audio.AudioRecorder import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher +import org.thoughtcrime.securesms.conversation.ConversationActivity import org.thoughtcrime.securesms.conversation.v2.dialogs.* import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarButton import org.thoughtcrime.securesms.conversation.v2.input_bar.InputBarDelegate @@ -181,8 +183,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe // region Settings companion object { + // Extras const val THREAD_ID = "thread_id" const val ADDRESS = "address" + // Request codes const val PICK_DOCUMENT = 2 const val TAKE_PHOTO = 7 const val PICK_GIF = 10 @@ -307,6 +311,27 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe } private fun restoreDraftIfNeeded() { + val mediaURI = intent.data + val mediaType = AttachmentManager.MediaType.from(intent.type) + if (mediaURI != null && mediaType != null) { + if (AttachmentManager.MediaType.IMAGE == mediaType || AttachmentManager.MediaType.GIF == mediaType || AttachmentManager.MediaType.VIDEO == mediaType) { + val media = Media(mediaURI, MediaUtil.getMimeType(this, mediaURI)!!, 0, 0, 0, 0, Optional.absent(), Optional.absent()) + startActivityForResult(MediaSendActivity.buildEditorIntent(this, listOf( media ), thread, ""), ConversationActivityV2.PICK_FROM_LIBRARY) + return + } else { + prepMediaForSending(mediaURI, mediaType).addListener(object : ListenableFuture.Listener { + + override fun onSuccess(result: Boolean?) { + sendAttachments(attachmentManager.buildSlideDeck().asAttachments(), null) + } + + override fun onFailure(e: ExecutionException?) { + Toast.makeText(this@ConversationActivityV2, R.string.activity_conversation_attachment_prep_failed, Toast.LENGTH_LONG).show() + } + }) + return + } + } val draftDB = DatabaseFactory.getDraftDatabase(this) val drafts = draftDB.getDrafts(threadID) draftDB.clearDrafts(threadID) From 6aa4ad1cd0aeba4b732bb02b649ecb63a99017d7 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Thu, 1 Jul 2021 10:02:02 +1000 Subject: [PATCH 26/26] Fix profile picture size issue --- .../conversation/v2/ConversationActivityV2.kt | 10 +++++++++ .../loki/views/ProfilePictureView.kt | 21 +++++-------------- .../activity_conversation_v2_action_bar.xml | 7 ++++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index edf90a0f98..088bde251f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -18,8 +18,10 @@ import android.util.Log import android.util.Pair import android.util.TypedValue import android.view.* +import android.widget.LinearLayout import android.widget.RelativeLayout import android.widget.Toast +import androidx.annotation.DimenRes import androidx.appcompat.app.AlertDialog import androidx.core.view.isVisible import androidx.lifecycle.Observer @@ -281,6 +283,14 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe actionBar.setCustomView(R.layout.activity_conversation_v2_action_bar) actionBar.setDisplayShowCustomEnabled(true) conversationTitleView.text = thread.toShortString() + @DimenRes val sizeID: Int + if (thread.isClosedGroupRecipient) { + sizeID = R.dimen.medium_profile_picture_size + } else { + sizeID = R.dimen.small_profile_picture_size + } + val size = resources.getDimension(sizeID).roundToInt() + profilePictureView.layoutParams = LinearLayout.LayoutParams(size, size) profilePictureView.glide = glide profilePictureView.update(thread, threadID) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt index 3482088dd9..b07675f5ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/views/ProfilePictureView.kt @@ -31,23 +31,12 @@ class ProfilePictureView : RelativeLayout { private val profilePicturesCache = mutableMapOf() // region Lifecycle - constructor(context: Context) : super(context) { - setUpViewHierarchy() - } + constructor(context: Context) : super(context) { initialize() } + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { initialize() } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { initialize() } + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { initialize() } - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - setUpViewHierarchy() - } - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { - setUpViewHierarchy() - } - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { - setUpViewHierarchy() - } - - private fun setUpViewHierarchy() { + private fun initialize() { val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val contentView = inflater.inflate(R.layout.view_profile_picture, null) addView(contentView) diff --git a/app/src/main/res/layout/activity_conversation_v2_action_bar.xml b/app/src/main/res/layout/activity_conversation_v2_action_bar.xml index 294e75564c..bd8374eb21 100644 --- a/app/src/main/res/layout/activity_conversation_v2_action_bar.xml +++ b/app/src/main/res/layout/activity_conversation_v2_action_bar.xml @@ -1,5 +1,6 @@ - + android:layout_width="@dimen/medium_profile_picture_size" + android:layout_height="@dimen/medium_profile_picture_size" />