diff --git a/changelog.d/5959.bugfix b/changelog.d/5959.bugfix
new file mode 100644
index 0000000000..c4d20b7f39
--- /dev/null
+++ b/changelog.d/5959.bugfix
@@ -0,0 +1 @@
+Multiple threads improvement (mainly UI)
diff --git a/library/ui-styles/src/main/res/values/colors.xml b/library/ui-styles/src/main/res/values/colors.xml
index 2104b49ab5..e72d02f51e 100644
--- a/library/ui-styles/src/main/res/values/colors.xml
+++ b/library/ui-styles/src/main/res/values/colors.xml
@@ -144,4 +144,9 @@
#17191C
#FF4B55
+
+
+ @color/palette_white
+ @color/palette_black_950
+
diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml
index 81d5a77297..826cde5eba 100644
--- a/library/ui-styles/src/main/res/values/dimens.xml
+++ b/library/ui-styles/src/main/res/values/dimens.xml
@@ -40,7 +40,7 @@
24dp
48dp
48dp
- 38dp
+ 34dp
56dp
diff --git a/library/ui-styles/src/main/res/values/theme_dark.xml b/library/ui-styles/src/main/res/values/theme_dark.xml
index eeff039b71..733f7e8eb5 100644
--- a/library/ui-styles/src/main/res/values/theme_dark.xml
+++ b/library/ui-styles/src/main/res/values/theme_dark.xml
@@ -30,6 +30,7 @@
- @color/element_system_dark
- @color/vctr_message_bubble_inbound_dark
- @color/vctr_message_bubble_outbound_dark
+ - @color/vctr_badge_color_border_dark
- #61708B
diff --git a/library/ui-styles/src/main/res/values/theme_light.xml b/library/ui-styles/src/main/res/values/theme_light.xml
index 0c363b583d..77996c8ce5 100644
--- a/library/ui-styles/src/main/res/values/theme_light.xml
+++ b/library/ui-styles/src/main/res/values/theme_light.xml
@@ -30,6 +30,7 @@
- @color/element_background_light
- @color/vctr_message_bubble_inbound_light
- @color/vctr_message_bubble_outbound_light
+ - @color/vctr_badge_color_border_light
- #61708B
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
index 2bb620623c..635b00c05d 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt
@@ -1529,7 +1529,7 @@ class TimelineFragment @Inject constructor(
views.composerLayout.views.composerEmojiButton.isVisible = vectorPreferences.showEmojiKeyboard()
- if (isThreadTimeLine() && timelineArgs.threadTimelineArgs?.startsThread == true) {
+ if (isThreadTimeLine() && timelineArgs.threadTimelineArgs?.showKeyboard == true) {
// Show keyboard when the user started a thread
views.composerLayout.views.composerEditText.showKeyboard(andRequestFocus = true)
}
@@ -2443,7 +2443,11 @@ class TimelineFragment @Inject constructor(
private fun onReplyInThreadClicked(action: EventSharedAction.ReplyInThread) {
if (vectorPreferences.areThreadMessagesEnabled()) {
- navigateToThreadTimeline(action.eventId, action.startsThread)
+ navigateToThreadTimeline(
+ rootThreadEventId = action.eventId,
+ startsThread = action.startsThread,
+ showKeyboard = true
+ )
} else {
displayThreadsBetaOptInDialog()
}
@@ -2453,7 +2457,7 @@ class TimelineFragment @Inject constructor(
* Navigate to Threads timeline for the specified rootThreadEventId
* using the ThreadsActivity.
*/
- private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false) {
+ private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false, showKeyboard: Boolean = false) {
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
context?.let {
val roomThreadDetailArgs = ThreadTimelineArgs(
@@ -2462,7 +2466,8 @@ class TimelineFragment @Inject constructor(
displayName = timelineViewModel.getRoomSummary()?.displayName,
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl,
roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel,
- rootThreadEventId = rootThreadEventId
+ rootThreadEventId = rootThreadEventId,
+ showKeyboard = showKeyboard
)
navigator.openThread(it, roomThreadDetailArgs)
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
index 1952e598a6..011258f126 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt
@@ -121,14 +121,25 @@ class SearchFragment @Inject constructor(
override fun onItemClicked(event: Event) =
navigateToEvent(event)
+ override fun onThreadSummaryClicked(event: Event) {
+ navigateToEvent(event, true)
+ }
+
/**
* Navigate and highlight the event. If this is a thread event,
* user will be redirected to the appropriate thread room
* @param event the event to navigate and highlight
+ * @param forceNavigateToThread force navigate within the thread (ex. when user clicks on thread summary)
*/
- private fun navigateToEvent(event: Event) {
+ private fun navigateToEvent(event: Event, forceNavigateToThread: Boolean = false) {
val roomId = event.roomId ?: return
- event.getRootThreadEventId()?.let {
+ val rootThreadEventId = if (forceNavigateToThread) {
+ event.eventId
+ } else {
+ event.getRootThreadEventId()
+ }
+
+ rootThreadEventId?.let {
val threadTimelineArgs = ThreadTimelineArgs(
roomId = roomId,
displayName = fragmentArgs.roomDisplayName,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt
index 913e440a20..81e4d8fd5f 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt
@@ -58,6 +58,7 @@ class SearchResultController @Inject constructor(
interface Listener {
fun onItemClicked(event: Event)
+ fun onThreadSummaryClicked(event: Event)
fun loadMore()
}
@@ -134,6 +135,7 @@ class SearchResultController @Inject constructor(
.threadSummaryFormatted(displayableEventFormatter.formatThreadSummary(event.threadDetails?.threadSummaryLatestEvent).toString())
.areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled())
.listener { listener?.onItemClicked(eventAndSender.event) }
+ .threadSummaryListener { listener?.onThreadSummaryClicked(eventAndSender.event) }
.let { result.add(it) }
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt
index 3e141ab0e9..d92dcdd3ef 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt
@@ -46,6 +46,7 @@ abstract class SearchResultItem : VectorEpoxyModel() {
@EpoxyAttribute var areThreadMessagesEnabled: Boolean = false
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
+ @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var threadSummaryListener: ClickListener? = null
override fun bind(holder: Holder) {
super.bind(holder)
@@ -66,23 +67,24 @@ abstract class SearchResultItem : VectorEpoxyModel() {
val displayName = it.threadSummarySenderInfo?.displayName
val avatarUrl = it.threadSummarySenderInfo?.avatarUrl
avatarRenderer.render(MatrixItem.UserItem(userId, displayName, avatarUrl), holder.threadSummaryAvatarImageView)
+ holder.threadSummaryContainer.onClick(threadSummaryListener)
} else {
showFromThread(holder)
}
} ?: run {
- holder.threadSummaryConstraintLayout.isVisible = false
+ holder.threadSummaryContainer.isVisible = false
holder.fromThreadConstraintLayout.isVisible = false
}
}
}
private fun showThreadSummary(holder: Holder, show: Boolean = true) {
- holder.threadSummaryConstraintLayout.isVisible = show
+ holder.threadSummaryContainer.isVisible = show
holder.fromThreadConstraintLayout.isVisible = !show
}
private fun showFromThread(holder: Holder, show: Boolean = true) {
- holder.threadSummaryConstraintLayout.isVisible = !show
+ holder.threadSummaryContainer.isVisible = !show
holder.fromThreadConstraintLayout.isVisible = show
}
@@ -91,7 +93,7 @@ abstract class SearchResultItem : VectorEpoxyModel() {
val memberNameView by bind(R.id.messageMemberNameView)
val timeView by bind(R.id.messageTimeView)
val contentView by bind(R.id.messageContentView)
- val threadSummaryConstraintLayout by bind(R.id.searchThreadSummaryConstraintLayout)
+ val threadSummaryContainer by bind(R.id.searchThreadSummaryContainer)
val threadSummaryCounterTextView by bind(R.id.messageThreadSummaryCounterTextView)
val threadSummaryAvatarImageView by bind(R.id.messageThreadSummaryAvatarImageView)
val threadSummaryInfoTextView by bind(R.id.messageThreadSummaryInfoTextView)
diff --git a/vector/src/main/java/im/vector/app/features/home/room/threads/arguments/ThreadTimelineArgs.kt b/vector/src/main/java/im/vector/app/features/home/room/threads/arguments/ThreadTimelineArgs.kt
index 19419e52de..7756c3c5a5 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/threads/arguments/ThreadTimelineArgs.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/threads/arguments/ThreadTimelineArgs.kt
@@ -27,5 +27,6 @@ data class ThreadTimelineArgs(
val avatarUrl: String?,
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel?,
val rootThreadEventId: String? = null,
- val startsThread: Boolean = false
+ val startsThread: Boolean = false,
+ val showKeyboard: Boolean = false
) : Parcelable
diff --git a/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt
index 04889f375f..8e762fda96 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt
@@ -19,6 +19,7 @@ package im.vector.app.features.home.room.threads.list.views
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
+import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
@@ -70,6 +71,16 @@ class ThreadListFragment @Inject constructor(
analyticsScreenName = MobileScreen.ScreenName.ThreadList
}
+ override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+ super.onCreateOptionsMenu(menu, inflater)
+
+ menu.findItem(R.id.menu_thread_list_filter)?.let { menuItem ->
+ menuItem.actionView.setOnClickListener {
+ onOptionsItemSelected(menuItem)
+ }
+ }
+ }
+
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_thread_list_filter -> {
@@ -82,6 +93,9 @@ class ThreadListFragment @Inject constructor(
override fun onPrepareOptionsMenu(menu: Menu) {
withState(threadListViewModel) { state ->
+ val filterIcon = menu.findItem(R.id.menu_thread_list_filter).actionView
+ val filterBadge = filterIcon.findViewById(R.id.threadListFilterBadge)
+ filterBadge.isVisible = state.shouldFilterThreads
when (threadListViewModel.canHomeserverUseThreading()) {
true -> menu.findItem(R.id.menu_thread_list_filter).isVisible = !state.threadSummaryList.invoke().isNullOrEmpty()
false -> menu.findItem(R.id.menu_thread_list_filter).isVisible = !state.rootThreadEventList.invoke().isNullOrEmpty()
@@ -146,9 +160,9 @@ class ThreadListFragment @Inject constructor(
override fun onThreadSummaryClicked(threadSummary: ThreadSummary) {
val roomThreadDetailArgs = ThreadTimelineArgs(
- roomId = threadSummary.roomId,
- displayName = threadSummary.rootThreadSenderInfo.displayName,
- avatarUrl = threadSummary.rootThreadSenderInfo.avatarUrl,
+ roomId = threadListArgs.roomId,
+ displayName = threadListArgs.displayName,
+ avatarUrl = threadListArgs.avatarUrl,
roomEncryptionTrustLevel = null,
rootThreadEventId = threadSummary.rootEventId
)
@@ -157,9 +171,9 @@ class ThreadListFragment @Inject constructor(
override fun onThreadListClicked(timelineEvent: TimelineEvent) {
val threadTimelineArgs = ThreadTimelineArgs(
- roomId = timelineEvent.roomId,
- displayName = timelineEvent.senderInfo.displayName,
- avatarUrl = timelineEvent.senderInfo.avatarUrl,
+ roomId = threadListArgs.roomId,
+ displayName = threadListArgs.displayName,
+ avatarUrl = threadListArgs.avatarUrl,
roomEncryptionTrustLevel = null,
rootThreadEventId = timelineEvent.eventId
)
diff --git a/vector/src/main/res/drawable/thread_filter_badge.xml b/vector/src/main/res/drawable/thread_filter_badge.xml
new file mode 100644
index 0000000000..c9a01197c8
--- /dev/null
+++ b/vector/src/main/res/drawable/thread_filter_badge.xml
@@ -0,0 +1,29 @@
+
+
+
+ -
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/item_search_result.xml b/vector/src/main/res/layout/item_search_result.xml
index 3264a7d230..6f6528c93b 100644
--- a/vector/src/main/res/layout/item_search_result.xml
+++ b/vector/src/main/res/layout/item_search_result.xml
@@ -63,7 +63,7 @@
tools:text="@sample/messages.json/data/message" />
-
\ No newline at end of file
+
diff --git a/vector/src/main/res/layout/view_thread_list_filter.xml b/vector/src/main/res/layout/view_thread_list_filter.xml
new file mode 100644
index 0000000000..7bdc994f43
--- /dev/null
+++ b/vector/src/main/res/layout/view_thread_list_filter.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/view_thread_room_summary.xml b/vector/src/main/res/layout/view_thread_room_summary.xml
index 6eeb62974d..e432f0fa35 100644
--- a/vector/src/main/res/layout/view_thread_room_summary.xml
+++ b/vector/src/main/res/layout/view_thread_room_summary.xml
@@ -21,7 +21,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
- android:minEms="1"
android:textColor="?vctr_content_secondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/messageThreadSummaryImageView"
diff --git a/vector/src/main/res/menu/menu_thread_list.xml b/vector/src/main/res/menu/menu_thread_list.xml
index 6da0f80112..d9fb1e7997 100644
--- a/vector/src/main/res/menu/menu_thread_list.xml
+++ b/vector/src/main/res/menu/menu_thread_list.xml
@@ -5,9 +5,10 @@
+ app:showAsAction="always"
+ tools:visible="true" />
-
\ No newline at end of file
+