Skip to content

Commit 424fb55

Browse files
Merge pull request #5959 from vector-im/feature/aris/threads_post_release_ui_improvements
Feature/aris/threads post release improvements
2 parents 3674ae7 + 324856d commit 424fb55

File tree

17 files changed

+135
-25
lines changed

17 files changed

+135
-25
lines changed

changelog.d/5959.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Multiple threads improvement (mainly UI)

library/ui-styles/src/main/res/values/colors.xml

+5
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,9 @@
144144
<color name="shield_color_black">#17191C</color>
145145
<color name="shield_color_warning">#FF4B55</color>
146146

147+
<!-- Badge Colors -->
148+
<attr name="vctr_badge_color_border" format="color" />
149+
<color name="vctr_badge_color_border_light">@color/palette_white</color>
150+
<color name="vctr_badge_color_border_dark">@color/palette_black_950</color>
151+
147152
</resources>

library/ui-styles/src/main/res/values/dimens.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<dimen name="menu_item_icon_size">24dp</dimen>
4141
<dimen name="menu_item_size">48dp</dimen>
4242
<dimen name="menu_item_ripple_size">48dp</dimen>
43-
<dimen name="menu_item_width_small">38dp</dimen>
43+
<dimen name="menu_item_width_small">34dp</dimen>
4444

4545
<!-- Composer -->
4646
<dimen name="composer_min_height">56dp</dimen>

library/ui-styles/src/main/res/values/theme_dark.xml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<item name="vctr_toolbar_background">@color/element_system_dark</item>
3131
<item name="vctr_message_bubble_inbound">@color/vctr_message_bubble_inbound_dark</item>
3232
<item name="vctr_message_bubble_outbound">@color/vctr_message_bubble_outbound_dark</item>
33+
<item name="vctr_badge_color_border">@color/vctr_badge_color_border_dark</item>
3334

3435
<!-- room message colors -->
3536
<item name="vctr_notice_secondary">#61708B</item>

library/ui-styles/src/main/res/values/theme_light.xml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<item name="vctr_toolbar_background">@color/element_background_light</item>
3131
<item name="vctr_message_bubble_inbound">@color/vctr_message_bubble_inbound_light</item>
3232
<item name="vctr_message_bubble_outbound">@color/vctr_message_bubble_outbound_light</item>
33+
<item name="vctr_badge_color_border">@color/vctr_badge_color_border_light</item>
3334

3435
<!-- room message colors -->
3536
<item name="vctr_notice_secondary">#61708B</item>

vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt

+9-4
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ class TimelineFragment @Inject constructor(
15291529

15301530
views.composerLayout.views.composerEmojiButton.isVisible = vectorPreferences.showEmojiKeyboard()
15311531

1532-
if (isThreadTimeLine() && timelineArgs.threadTimelineArgs?.startsThread == true) {
1532+
if (isThreadTimeLine() && timelineArgs.threadTimelineArgs?.showKeyboard == true) {
15331533
// Show keyboard when the user started a thread
15341534
views.composerLayout.views.composerEditText.showKeyboard(andRequestFocus = true)
15351535
}
@@ -2443,7 +2443,11 @@ class TimelineFragment @Inject constructor(
24432443

24442444
private fun onReplyInThreadClicked(action: EventSharedAction.ReplyInThread) {
24452445
if (vectorPreferences.areThreadMessagesEnabled()) {
2446-
navigateToThreadTimeline(action.eventId, action.startsThread)
2446+
navigateToThreadTimeline(
2447+
rootThreadEventId = action.eventId,
2448+
startsThread = action.startsThread,
2449+
showKeyboard = true
2450+
)
24472451
} else {
24482452
displayThreadsBetaOptInDialog()
24492453
}
@@ -2453,7 +2457,7 @@ class TimelineFragment @Inject constructor(
24532457
* Navigate to Threads timeline for the specified rootThreadEventId
24542458
* using the ThreadsActivity.
24552459
*/
2456-
private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false) {
2460+
private fun navigateToThreadTimeline(rootThreadEventId: String, startsThread: Boolean = false, showKeyboard: Boolean = false) {
24572461
analyticsTracker.capture(Interaction.Name.MobileRoomThreadSummaryItem.toAnalyticsInteraction())
24582462
context?.let {
24592463
val roomThreadDetailArgs = ThreadTimelineArgs(
@@ -2462,7 +2466,8 @@ class TimelineFragment @Inject constructor(
24622466
displayName = timelineViewModel.getRoomSummary()?.displayName,
24632467
avatarUrl = timelineViewModel.getRoomSummary()?.avatarUrl,
24642468
roomEncryptionTrustLevel = timelineViewModel.getRoomSummary()?.roomEncryptionTrustLevel,
2465-
rootThreadEventId = rootThreadEventId
2469+
rootThreadEventId = rootThreadEventId,
2470+
showKeyboard = showKeyboard
24662471
)
24672472
navigator.openThread(it, roomThreadDetailArgs)
24682473
}

vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt

+13-2
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,25 @@ class SearchFragment @Inject constructor(
121121
override fun onItemClicked(event: Event) =
122122
navigateToEvent(event)
123123

124+
override fun onThreadSummaryClicked(event: Event) {
125+
navigateToEvent(event, true)
126+
}
127+
124128
/**
125129
* Navigate and highlight the event. If this is a thread event,
126130
* user will be redirected to the appropriate thread room
127131
* @param event the event to navigate and highlight
132+
* @param forceNavigateToThread force navigate within the thread (ex. when user clicks on thread summary)
128133
*/
129-
private fun navigateToEvent(event: Event) {
134+
private fun navigateToEvent(event: Event, forceNavigateToThread: Boolean = false) {
130135
val roomId = event.roomId ?: return
131-
event.getRootThreadEventId()?.let {
136+
val rootThreadEventId = if (forceNavigateToThread) {
137+
event.eventId
138+
} else {
139+
event.getRootThreadEventId()
140+
}
141+
142+
rootThreadEventId?.let {
132143
val threadTimelineArgs = ThreadTimelineArgs(
133144
roomId = roomId,
134145
displayName = fragmentArgs.roomDisplayName,

vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultController.kt

+2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class SearchResultController @Inject constructor(
5858

5959
interface Listener {
6060
fun onItemClicked(event: Event)
61+
fun onThreadSummaryClicked(event: Event)
6162
fun loadMore()
6263
}
6364

@@ -134,6 +135,7 @@ class SearchResultController @Inject constructor(
134135
.threadSummaryFormatted(displayableEventFormatter.formatThreadSummary(event.threadDetails?.threadSummaryLatestEvent).toString())
135136
.areThreadMessagesEnabled(userPreferencesProvider.areThreadMessagesEnabled())
136137
.listener { listener?.onItemClicked(eventAndSender.event) }
138+
.threadSummaryListener { listener?.onThreadSummaryClicked(eventAndSender.event) }
137139
.let { result.add(it) }
138140
}
139141

vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchResultItem.kt

+6-4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
4646
@EpoxyAttribute var areThreadMessagesEnabled: Boolean = false
4747

4848
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
49+
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var threadSummaryListener: ClickListener? = null
4950

5051
override fun bind(holder: Holder) {
5152
super.bind(holder)
@@ -66,23 +67,24 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
6667
val displayName = it.threadSummarySenderInfo?.displayName
6768
val avatarUrl = it.threadSummarySenderInfo?.avatarUrl
6869
avatarRenderer.render(MatrixItem.UserItem(userId, displayName, avatarUrl), holder.threadSummaryAvatarImageView)
70+
holder.threadSummaryContainer.onClick(threadSummaryListener)
6971
} else {
7072
showFromThread(holder)
7173
}
7274
} ?: run {
73-
holder.threadSummaryConstraintLayout.isVisible = false
75+
holder.threadSummaryContainer.isVisible = false
7476
holder.fromThreadConstraintLayout.isVisible = false
7577
}
7678
}
7779
}
7880

7981
private fun showThreadSummary(holder: Holder, show: Boolean = true) {
80-
holder.threadSummaryConstraintLayout.isVisible = show
82+
holder.threadSummaryContainer.isVisible = show
8183
holder.fromThreadConstraintLayout.isVisible = !show
8284
}
8385

8486
private fun showFromThread(holder: Holder, show: Boolean = true) {
85-
holder.threadSummaryConstraintLayout.isVisible = !show
87+
holder.threadSummaryContainer.isVisible = !show
8688
holder.fromThreadConstraintLayout.isVisible = show
8789
}
8890

@@ -91,7 +93,7 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
9193
val memberNameView by bind<TextView>(R.id.messageMemberNameView)
9294
val timeView by bind<TextView>(R.id.messageTimeView)
9395
val contentView by bind<TextView>(R.id.messageContentView)
94-
val threadSummaryConstraintLayout by bind<ConstraintLayout>(R.id.searchThreadSummaryConstraintLayout)
96+
val threadSummaryContainer by bind<ConstraintLayout>(R.id.searchThreadSummaryContainer)
9597
val threadSummaryCounterTextView by bind<TextView>(R.id.messageThreadSummaryCounterTextView)
9698
val threadSummaryAvatarImageView by bind<ImageView>(R.id.messageThreadSummaryAvatarImageView)
9799
val threadSummaryInfoTextView by bind<TextView>(R.id.messageThreadSummaryInfoTextView)

vector/src/main/java/im/vector/app/features/home/room/threads/arguments/ThreadTimelineArgs.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ data class ThreadTimelineArgs(
2727
val avatarUrl: String?,
2828
val roomEncryptionTrustLevel: RoomEncryptionTrustLevel?,
2929
val rootThreadEventId: String? = null,
30-
val startsThread: Boolean = false
30+
val startsThread: Boolean = false,
31+
val showKeyboard: Boolean = false
3132
) : Parcelable

vector/src/main/java/im/vector/app/features/home/room/threads/list/views/ThreadListFragment.kt

+20-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package im.vector.app.features.home.room.threads.list.views
1919
import android.os.Bundle
2020
import android.view.LayoutInflater
2121
import android.view.Menu
22+
import android.view.MenuInflater
2223
import android.view.MenuItem
2324
import android.view.View
2425
import android.view.ViewGroup
@@ -70,6 +71,16 @@ class ThreadListFragment @Inject constructor(
7071
analyticsScreenName = MobileScreen.ScreenName.ThreadList
7172
}
7273

74+
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
75+
super.onCreateOptionsMenu(menu, inflater)
76+
77+
menu.findItem(R.id.menu_thread_list_filter)?.let { menuItem ->
78+
menuItem.actionView.setOnClickListener {
79+
onOptionsItemSelected(menuItem)
80+
}
81+
}
82+
}
83+
7384
override fun onOptionsItemSelected(item: MenuItem): Boolean {
7485
return when (item.itemId) {
7586
R.id.menu_thread_list_filter -> {
@@ -82,6 +93,9 @@ class ThreadListFragment @Inject constructor(
8293

8394
override fun onPrepareOptionsMenu(menu: Menu) {
8495
withState(threadListViewModel) { state ->
96+
val filterIcon = menu.findItem(R.id.menu_thread_list_filter).actionView
97+
val filterBadge = filterIcon.findViewById<View>(R.id.threadListFilterBadge)
98+
filterBadge.isVisible = state.shouldFilterThreads
8599
when (threadListViewModel.canHomeserverUseThreading()) {
86100
true -> menu.findItem(R.id.menu_thread_list_filter).isVisible = !state.threadSummaryList.invoke().isNullOrEmpty()
87101
false -> menu.findItem(R.id.menu_thread_list_filter).isVisible = !state.rootThreadEventList.invoke().isNullOrEmpty()
@@ -146,9 +160,9 @@ class ThreadListFragment @Inject constructor(
146160

147161
override fun onThreadSummaryClicked(threadSummary: ThreadSummary) {
148162
val roomThreadDetailArgs = ThreadTimelineArgs(
149-
roomId = threadSummary.roomId,
150-
displayName = threadSummary.rootThreadSenderInfo.displayName,
151-
avatarUrl = threadSummary.rootThreadSenderInfo.avatarUrl,
163+
roomId = threadListArgs.roomId,
164+
displayName = threadListArgs.displayName,
165+
avatarUrl = threadListArgs.avatarUrl,
152166
roomEncryptionTrustLevel = null,
153167
rootThreadEventId = threadSummary.rootEventId
154168
)
@@ -157,9 +171,9 @@ class ThreadListFragment @Inject constructor(
157171

158172
override fun onThreadListClicked(timelineEvent: TimelineEvent) {
159173
val threadTimelineArgs = ThreadTimelineArgs(
160-
roomId = timelineEvent.roomId,
161-
displayName = timelineEvent.senderInfo.displayName,
162-
avatarUrl = timelineEvent.senderInfo.avatarUrl,
174+
roomId = threadListArgs.roomId,
175+
displayName = threadListArgs.displayName,
176+
avatarUrl = threadListArgs.avatarUrl,
163177
roomEncryptionTrustLevel = null,
164178
rootThreadEventId = timelineEvent.eventId
165179
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
<item>
5+
<shape
6+
android:shape="oval">
7+
<size
8+
android:width="10dp"
9+
android:height="10dp" />
10+
<padding
11+
android:bottom="3dp"
12+
android:left="3dp"
13+
android:right="3dp"
14+
android:top="3dp" />
15+
<stroke
16+
android:color="?vctr_badge_color_border"
17+
android:width="3dp"/>
18+
</shape>
19+
</item>
20+
21+
<item>
22+
<shape android:shape="oval">
23+
<size
24+
android:width="10dp"
25+
android:height="10dp" />
26+
<solid android:color="?colorPrimary" />
27+
</shape>
28+
</item>
29+
</layer-list>

vector/src/main/res/layout/item_search_result.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
tools:text="@sample/messages.json/data/message" />
6464

6565
<androidx.constraintlayout.widget.ConstraintLayout
66-
android:id="@+id/searchThreadSummaryConstraintLayout"
66+
android:id="@+id/searchThreadSummaryContainer"
6767
android:layout_width="wrap_content"
6868
android:layout_height="wrap_content"
6969
app:layout_constrainedWidth="true"

vector/src/main/res/layout/item_thread.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
android:maxWidth="496dp"
9393
android:minWidth="144dp"
9494
android:paddingTop="8dp"
95-
android:paddingBottom="8dp"
95+
android:paddingBottom="12dp"
9696
app:layout_constraintEnd_toEndOf="parent"
9797
app:layout_constraintStart_toStartOf="@id/threadSummaryTitleTextView"
9898
app:layout_constraintTop_toBottomOf="@id/threadSummaryRootMessageTextView"
@@ -108,4 +108,4 @@
108108
app:layout_constraintEnd_toEndOf="parent"
109109
app:layout_constraintStart_toStartOf="@id/threadSummaryConstraintLayout"
110110
app:layout_constraintTop_toBottomOf="@id/threadSummaryConstraintLayout" />
111-
</androidx.constraintlayout.widget.ConstraintLayout>
111+
</androidx.constraintlayout.widget.ConstraintLayout>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="@dimen/menu_item_size"
6+
android:layout_height="@dimen/menu_item_size">
7+
8+
<FrameLayout
9+
android:layout_width="@dimen/menu_item_ripple_size"
10+
android:layout_height="@dimen/menu_item_ripple_size"
11+
android:layout_gravity="center"
12+
android:background="?attr/selectableItemBackgroundBorderless"
13+
app:layout_constraintBottom_toBottomOf="parent"
14+
app:layout_constraintEnd_toEndOf="parent"
15+
app:layout_constraintStart_toStartOf="parent"
16+
app:layout_constraintTop_toTopOf="parent">
17+
18+
<ImageView
19+
android:layout_width="@dimen/menu_item_icon_size"
20+
android:layout_height="@dimen/menu_item_icon_size"
21+
android:layout_gravity="center"
22+
android:src="@drawable/ic_filter"
23+
tools:ignore="ContentDescription" />
24+
25+
<View
26+
android:id="@+id/threadListFilterBadge"
27+
android:layout_width="10dp"
28+
android:layout_height="10dp"
29+
android:layout_marginTop="3dp"
30+
android:layout_marginEnd="3dp"
31+
android:layout_gravity="top|end"
32+
android:background="@drawable/thread_filter_badge"
33+
android:visibility="visible"
34+
tools:visibility="visible" />
35+
36+
</FrameLayout>
37+
38+
</androidx.constraintlayout.widget.ConstraintLayout>

vector/src/main/res/layout/view_thread_room_summary.xml

-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
android:layout_width="wrap_content"
2222
android:layout_height="wrap_content"
2323
android:layout_marginStart="4dp"
24-
android:minEms="1"
2524
android:textColor="?vctr_content_secondary"
2625
app:layout_constraintBottom_toBottomOf="parent"
2726
app:layout_constraintStart_toEndOf="@id/messageThreadSummaryImageView"

vector/src/main/res/menu/menu_thread_list.xml

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
<item
77
android:id="@+id/menu_thread_list_filter"
8-
android:icon="@drawable/ic_filter"
98
android:title="@string/room_threads_filter"
9+
app:actionLayout="@layout/view_thread_list_filter"
1010
app:iconTint="?vctr_content_secondary"
11-
app:showAsAction="ifRoom" />
11+
app:showAsAction="always"
12+
tools:visible="true" />
1213

13-
</menu>
14+
</menu>

0 commit comments

Comments
 (0)