mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-16 20:10:04 +03:00
Merge pull request #5959 from vector-im/feature/aris/threads_post_release_ui_improvements
Feature/aris/threads post release improvements
This commit is contained in:
commit
424fb5556d
17 changed files with 135 additions and 25 deletions
1
changelog.d/5959.bugfix
Normal file
1
changelog.d/5959.bugfix
Normal file
|
@ -0,0 +1 @@
|
|||
Multiple threads improvement (mainly UI)
|
|
@ -144,4 +144,9 @@
|
|||
<color name="shield_color_black">#17191C</color>
|
||||
<color name="shield_color_warning">#FF4B55</color>
|
||||
|
||||
<!-- Badge Colors -->
|
||||
<attr name="vctr_badge_color_border" format="color" />
|
||||
<color name="vctr_badge_color_border_light">@color/palette_white</color>
|
||||
<color name="vctr_badge_color_border_dark">@color/palette_black_950</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
<dimen name="menu_item_icon_size">24dp</dimen>
|
||||
<dimen name="menu_item_size">48dp</dimen>
|
||||
<dimen name="menu_item_ripple_size">48dp</dimen>
|
||||
<dimen name="menu_item_width_small">38dp</dimen>
|
||||
<dimen name="menu_item_width_small">34dp</dimen>
|
||||
|
||||
<!-- Composer -->
|
||||
<dimen name="composer_min_height">56dp</dimen>
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<item name="vctr_toolbar_background">@color/element_system_dark</item>
|
||||
<item name="vctr_message_bubble_inbound">@color/vctr_message_bubble_inbound_dark</item>
|
||||
<item name="vctr_message_bubble_outbound">@color/vctr_message_bubble_outbound_dark</item>
|
||||
<item name="vctr_badge_color_border">@color/vctr_badge_color_border_dark</item>
|
||||
|
||||
<!-- room message colors -->
|
||||
<item name="vctr_notice_secondary">#61708B</item>
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
<item name="vctr_toolbar_background">@color/element_background_light</item>
|
||||
<item name="vctr_message_bubble_inbound">@color/vctr_message_bubble_inbound_light</item>
|
||||
<item name="vctr_message_bubble_outbound">@color/vctr_message_bubble_outbound_light</item>
|
||||
<item name="vctr_badge_color_border">@color/vctr_badge_color_border_light</item>
|
||||
|
||||
<!-- room message colors -->
|
||||
<item name="vctr_notice_secondary">#61708B</item>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ abstract class SearchResultItem : VectorEpoxyModel<SearchResultItem.Holder>() {
|
|||
@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<SearchResultItem.Holder>() {
|
|||
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<SearchResultItem.Holder>() {
|
|||
val memberNameView by bind<TextView>(R.id.messageMemberNameView)
|
||||
val timeView by bind<TextView>(R.id.messageTimeView)
|
||||
val contentView by bind<TextView>(R.id.messageContentView)
|
||||
val threadSummaryConstraintLayout by bind<ConstraintLayout>(R.id.searchThreadSummaryConstraintLayout)
|
||||
val threadSummaryContainer by bind<ConstraintLayout>(R.id.searchThreadSummaryContainer)
|
||||
val threadSummaryCounterTextView by bind<TextView>(R.id.messageThreadSummaryCounterTextView)
|
||||
val threadSummaryAvatarImageView by bind<ImageView>(R.id.messageThreadSummaryAvatarImageView)
|
||||
val threadSummaryInfoTextView by bind<TextView>(R.id.messageThreadSummaryInfoTextView)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<View>(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
|
||||
)
|
||||
|
|
29
vector/src/main/res/drawable/thread_filter_badge.xml
Normal file
29
vector/src/main/res/drawable/thread_filter_badge.xml
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item>
|
||||
<shape
|
||||
android:shape="oval">
|
||||
<size
|
||||
android:width="10dp"
|
||||
android:height="10dp" />
|
||||
<padding
|
||||
android:bottom="3dp"
|
||||
android:left="3dp"
|
||||
android:right="3dp"
|
||||
android:top="3dp" />
|
||||
<stroke
|
||||
android:color="?vctr_badge_color_border"
|
||||
android:width="3dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<size
|
||||
android:width="10dp"
|
||||
android:height="10dp" />
|
||||
<solid android:color="?colorPrimary" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -63,7 +63,7 @@
|
|||
tools:text="@sample/messages.json/data/message" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/searchThreadSummaryConstraintLayout"
|
||||
android:id="@+id/searchThreadSummaryContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constrainedWidth="true"
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
android:maxWidth="496dp"
|
||||
android:minWidth="144dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/threadSummaryTitleTextView"
|
||||
app:layout_constraintTop_toBottomOf="@id/threadSummaryRootMessageTextView"
|
||||
|
@ -108,4 +108,4 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@id/threadSummaryConstraintLayout"
|
||||
app:layout_constraintTop_toBottomOf="@id/threadSummaryConstraintLayout" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
38
vector/src/main/res/layout/view_thread_list_filter.xml
Normal file
38
vector/src/main/res/layout/view_thread_list_filter.xml
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="@dimen/menu_item_size"
|
||||
android:layout_height="@dimen/menu_item_size">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="@dimen/menu_item_ripple_size"
|
||||
android:layout_height="@dimen/menu_item_ripple_size"
|
||||
android:layout_gravity="center"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/menu_item_icon_size"
|
||||
android:layout_height="@dimen/menu_item_icon_size"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_filter"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<View
|
||||
android:id="@+id/threadListFilterBadge"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_marginEnd="3dp"
|
||||
android:layout_gravity="top|end"
|
||||
android:background="@drawable/thread_filter_badge"
|
||||
android:visibility="visible"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -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"
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
|
||||
<item
|
||||
android:id="@+id/menu_thread_list_filter"
|
||||
android:icon="@drawable/ic_filter"
|
||||
android:title="@string/room_threads_filter"
|
||||
app:actionLayout="@layout/view_thread_list_filter"
|
||||
app:iconTint="?vctr_content_secondary"
|
||||
app:showAsAction="ifRoom" />
|
||||
app:showAsAction="always"
|
||||
tools:visible="true" />
|
||||
|
||||
</menu>
|
||||
</menu>
|
||||
|
|
Loading…
Add table
Reference in a new issue