adding headers to separate sections

This commit is contained in:
Maxime Naturel 2022-02-11 11:03:20 +01:00
parent d214ef34df
commit 2beff8d4cd
7 changed files with 122 additions and 11 deletions

View File

@ -0,0 +1,39 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.autocomplete
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
@EpoxyModelClass(layout = R.layout.item_autocomplete_header_item)
abstract class AutocompleteHeaderItem : VectorEpoxyModel<AutocompleteHeaderItem.Holder>() {
@EpoxyAttribute var title: String? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.titleView.text = title
}
class Holder : VectorEpoxyHolder() {
val titleView by bind<TextView>(R.id.headerItemAutocompleteTitle)
}
}

View File

@ -30,7 +30,6 @@ import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
// TODO create a new item for sections: AutocompleteSection
@EpoxyModelClass(layout = R.layout.item_autocomplete_matrix_item) @EpoxyModelClass(layout = R.layout.item_autocomplete_matrix_item)
abstract class AutocompleteMatrixItem : VectorEpoxyModel<AutocompleteMatrixItem.Holder>() { abstract class AutocompleteMatrixItem : VectorEpoxyModel<AutocompleteMatrixItem.Holder>() {

View File

@ -20,6 +20,7 @@ import android.content.Context
import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.TypedEpoxyController
import im.vector.app.R import im.vector.app.R
import im.vector.app.features.autocomplete.AutocompleteClickListener import im.vector.app.features.autocomplete.AutocompleteClickListener
import im.vector.app.features.autocomplete.autocompleteHeaderItem
import im.vector.app.features.autocomplete.autocompleteMatrixItem import im.vector.app.features.autocomplete.autocompleteMatrixItem
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import org.matrix.android.sdk.api.util.toEveryoneInRoomMatrixItem import org.matrix.android.sdk.api.util.toEveryoneInRoomMatrixItem
@ -51,6 +52,7 @@ class AutocompleteMemberController @Inject constructor(private val context: Cont
} }
data.forEach { item -> data.forEach { item ->
when (item) { when (item) {
is AutocompleteMemberItem.Header -> buildHeaderItem(item)
is AutocompleteMemberItem.RoomMember -> buildRoomMemberItem(item) is AutocompleteMemberItem.RoomMember -> buildRoomMemberItem(item)
is AutocompleteMemberItem.Everyone -> buildEveryoneItem(item) is AutocompleteMemberItem.Everyone -> buildEveryoneItem(item)
} }
@ -61,6 +63,13 @@ class AutocompleteMemberController @Inject constructor(private val context: Cont
// HELPER METHODS // HELPER METHODS
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
private fun buildHeaderItem(header: AutocompleteMemberItem.Header) {
autocompleteHeaderItem {
id(header.id)
title(header.title)
}
}
private fun buildRoomMemberItem(roomMember: AutocompleteMemberItem.RoomMember) { private fun buildRoomMemberItem(roomMember: AutocompleteMemberItem.RoomMember) {
val host = this val host = this
autocompleteMatrixItem { autocompleteMatrixItem {

View File

@ -20,7 +20,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
sealed class AutocompleteMemberItem { sealed class AutocompleteMemberItem {
// TODO add section class data class Header(val id: String, val title: String) : AutocompleteMemberItem()
data class RoomMember(val roomMemberSummary: RoomMemberSummary) : AutocompleteMemberItem() data class RoomMember(val roomMemberSummary: RoomMemberSummary) : AutocompleteMemberItem()
data class Everyone(val roomSummary: RoomSummary) : AutocompleteMemberItem() data class Everyone(val roomSummary: RoomSummary) : AutocompleteMemberItem()
} }

View File

@ -21,6 +21,7 @@ import androidx.recyclerview.widget.RecyclerView
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.R
import im.vector.app.features.autocomplete.AutocompleteClickListener import im.vector.app.features.autocomplete.AutocompleteClickListener
import im.vector.app.features.autocomplete.RecyclerViewPresenter import im.vector.app.features.autocomplete.RecyclerViewPresenter
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
@ -36,12 +37,24 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
private val controller: AutocompleteMemberController private val controller: AutocompleteMemberController
) : RecyclerViewPresenter<AutocompleteMemberItem>(context), AutocompleteClickListener<AutocompleteMemberItem> { ) : RecyclerViewPresenter<AutocompleteMemberItem>(context), AutocompleteClickListener<AutocompleteMemberItem> {
///////////////////////////////////////////////////////////////////////////
// FIELDS
///////////////////////////////////////////////////////////////////////////
private val room by lazy { session.getRoom(roomId)!! } private val room by lazy { session.getRoom(roomId)!! }
///////////////////////////////////////////////////////////////////////////
// INIT
///////////////////////////////////////////////////////////////////////////
init { init {
controller.listener = this controller.listener = this
} }
///////////////////////////////////////////////////////////////////////////
// PUBLIC API
///////////////////////////////////////////////////////////////////////////
fun clear() { fun clear() {
controller.listener = null controller.listener = null
} }
@ -51,6 +64,10 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
fun create(roomId: String): AutocompleteMemberPresenter fun create(roomId: String): AutocompleteMemberPresenter
} }
///////////////////////////////////////////////////////////////////////////
// SPECIALIZATION
///////////////////////////////////////////////////////////////////////////
override fun instantiateAdapter(): RecyclerView.Adapter<*> { override fun instantiateAdapter(): RecyclerView.Adapter<*> {
return controller.adapter return controller.adapter
} }
@ -70,6 +87,10 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
excludeSelf = true excludeSelf = true
} }
val membersHeader = AutocompleteMemberItem.Header(
ID_HEADER_MEMBERS,
context.getString(R.string.room_message_autocomplete_users)
)
val members = room.getRoomMembers(queryParams) val members = room.getRoomMembers(queryParams)
.asSequence() .asSequence()
.sortedBy { it.displayName } .sortedBy { it.displayName }
@ -81,17 +102,35 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
val everyone = room.roomSummary() val everyone = room.roomSummary()
?.takeIf { query.isNullOrBlank() || MatrixItem.NOTIFY_EVERYONE.startsWith("@$query") } ?.takeIf { query.isNullOrBlank() || MatrixItem.NOTIFY_EVERYONE.startsWith("@$query") }
?.let { ?.let {
AutocompleteMemberItem.Everyone(it) AutocompleteMemberItem.Everyone(it)
} }
val items = mutableListOf<AutocompleteMemberItem>().apply { val items = mutableListOf<AutocompleteMemberItem>().apply {
// TODO add header sections if(members.isNotEmpty()) {
addAll(members) add(membersHeader)
everyone?.let { add(it) } addAll(members)
}
everyone?.let {
val everyoneHeader = AutocompleteMemberItem.Header(
ID_HEADER_EVERYONE,
context.getString(R.string.room_message_autocomplete_notification)
)
add(everyoneHeader)
add(it)
}
} }
controller.setData(items) controller.setData(items)
} }
///////////////////////////////////////////////////////////////////////////
// CONST
///////////////////////////////////////////////////////////////////////////
companion object {
private const val ID_HEADER_MEMBERS = "ID_HEADER_MEMBERS"
private const val ID_HEADER_EVERYONE = "ID_HEADER_EVERYONE"
}
} }
private fun Sequence<RoomMemberSummary>.disambiguate(): Sequence<RoomMemberSummary> { private fun Sequence<RoomMemberSummary>.disambiguate(): Sequence<RoomMemberSummary> {

View File

@ -133,13 +133,17 @@ class AutoCompleter @AssistedInject constructor(
.with(backgroundDrawable) .with(backgroundDrawable)
.with(object : AutocompleteCallback<AutocompleteMemberItem> { .with(object : AutocompleteCallback<AutocompleteMemberItem> {
override fun onPopupItemClicked(editable: Editable, item: AutocompleteMemberItem): Boolean { override fun onPopupItemClicked(editable: Editable, item: AutocompleteMemberItem): Boolean {
when (item) { return when (item) {
is AutocompleteMemberItem.RoomMember -> is AutocompleteMemberItem.Header -> false // do nothing header is not clickable
is AutocompleteMemberItem.RoomMember -> {
insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, item.roomMemberSummary.toMatrixItem()) insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, item.roomMemberSummary.toMatrixItem())
is AutocompleteMemberItem.Everyone -> true
}
is AutocompleteMemberItem.Everyone -> {
insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, item.roomSummary.toEveryoneInRoomMatrixItem()) insertMatrixItem(editText, editable, TRIGGER_AUTO_COMPLETE_MEMBERS, item.roomSummary.toEveryoneInRoomMatrixItem())
true
}
} }
return true
} }
override fun onPopupVisibilityChanged(shown: Boolean) { override fun onPopupVisibilityChanged(shown: Boolean) {

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:colorBackground"
android:orientation="horizontal"
android:padding="8dp"
tools:viewBindingIgnore="true">
<TextView
android:id="@+id/headerItemAutocompleteTitle"
style="@style/Widget.Vector.TextView.Subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:maxLines="1"
android:textColor="?vctr_content_secondary"
tools:text="Users" />
</LinearLayout>