forked from GitHub-Mirror/riotX-android
Direct room: finally handle selection with chips (not as Nad design)
This commit is contained in:
parent
507bc2f622
commit
5af6bf3762
@ -206,7 +206,7 @@ dependencies {
|
|||||||
|
|
||||||
// UI
|
// UI
|
||||||
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
implementation 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
|
||||||
implementation 'com.google.android.material:material:1.1.0-alpha07'
|
implementation 'com.google.android.material:material:1.1.0-alpha08'
|
||||||
implementation 'me.gujun.android:span:1.7'
|
implementation 'me.gujun.android:span:1.7'
|
||||||
implementation "ru.noties.markwon:core:$markwon_version"
|
implementation "ru.noties.markwon:core:$markwon_version"
|
||||||
implementation "ru.noties.markwon:html:$markwon_version"
|
implementation "ru.noties.markwon:html:$markwon_version"
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotx.core.platform
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.TypedArray
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ScrollView
|
||||||
|
|
||||||
|
import im.vector.riotx.R
|
||||||
|
|
||||||
|
private const val DEFAULT_MAX_HEIGHT = 200
|
||||||
|
|
||||||
|
class MaxHeightScrollView : ScrollView {
|
||||||
|
|
||||||
|
var maxHeight: Int = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
requestLayout()
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context) : super(context) {}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||||
|
if (!isInEditMode) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
|
||||||
|
if (!isInEditMode) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
if (!isInEditMode) {
|
||||||
|
init(context, attrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init(context: Context, attrs: AttributeSet?) {
|
||||||
|
if (attrs != null) {
|
||||||
|
val styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView)
|
||||||
|
maxHeight = styledAttrs.getDimensionPixelSize(R.styleable.MaxHeightScrollView_maxHeight, DEFAULT_MAX_HEIGHT)
|
||||||
|
styledAttrs.recycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
val newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)
|
||||||
|
super.onMeasure(widthMeasureSpec, newHeightMeasureSpec)
|
||||||
|
}
|
||||||
|
}
|
@ -24,11 +24,11 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.Fail
|
import com.airbnb.mvrx.Fail
|
||||||
import com.airbnb.mvrx.Loading
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.viewModel
|
import com.airbnb.mvrx.viewModel
|
||||||
import com.google.android.gms.common.GooglePlayServicesNotAvailableException
|
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ScreenComponent
|
import im.vector.riotx.core.di.ScreenComponent
|
||||||
import im.vector.riotx.core.error.ErrorFormatter
|
import im.vector.riotx.core.error.ErrorFormatter
|
||||||
@ -72,14 +72,16 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
|||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
addFragment(CreateDirectRoomFragment(), R.id.container)
|
addFragment(CreateDirectRoomFragment(), R.id.container)
|
||||||
}
|
}
|
||||||
viewModel.subscribe(this) { renderState(it) }
|
viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) {
|
||||||
|
renderCreateAndInviteState(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderState(state: CreateDirectRoomViewState) {
|
private fun renderCreateAndInviteState(state: Async<String>) {
|
||||||
when (state.createAndInviteState) {
|
when (state) {
|
||||||
is Loading -> renderCreationLoading()
|
is Loading -> renderCreationLoading()
|
||||||
is Success -> renderCreationSuccess(state.createAndInviteState())
|
is Success -> renderCreationSuccess(state())
|
||||||
is Fail -> renderCreationFailure(state.createAndInviteState.error)
|
is Fail -> renderCreationFailure(state.error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.user.model.User
|
|||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ScreenComponent
|
import im.vector.riotx.core.di.ScreenComponent
|
||||||
import im.vector.riotx.core.extensions.hideKeyboard
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
|
import im.vector.riotx.core.extensions.setupAsSearch
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_create_direct_room_directory_users.*
|
import kotlinx.android.synthetic.main.fragment_create_direct_room_directory_users.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -60,6 +61,7 @@ class CreateDirectRoomDirectoryUsersFragment : VectorBaseFragment(), CreateDirec
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupSearchByMatrixIdView() {
|
private fun setupSearchByMatrixIdView() {
|
||||||
|
createDirectRoomSearchById.setupAsSearch()
|
||||||
createDirectRoomSearchById
|
createDirectRoomSearchById
|
||||||
.textChanges()
|
.textChanges()
|
||||||
.subscribe {
|
.subscribe {
|
||||||
|
@ -19,23 +19,25 @@
|
|||||||
package im.vector.riotx.features.home.createdirect
|
package im.vector.riotx.features.home.createdirect
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Spannable
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.widget.ScrollView
|
||||||
|
import androidx.core.view.size
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import com.airbnb.mvrx.activityViewModel
|
import com.airbnb.mvrx.activityViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.jakewharton.rxbinding3.widget.beforeTextChangeEvents
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.chip.ChipGroup
|
||||||
import com.jakewharton.rxbinding3.widget.textChanges
|
import com.jakewharton.rxbinding3.widget.textChanges
|
||||||
import im.vector.matrix.android.api.MatrixPatterns
|
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ScreenComponent
|
import im.vector.riotx.core.di.ScreenComponent
|
||||||
import im.vector.riotx.core.extensions.hideKeyboard
|
import im.vector.riotx.core.extensions.hideKeyboard
|
||||||
import im.vector.riotx.core.extensions.observeEvent
|
import im.vector.riotx.core.extensions.observeEvent
|
||||||
import im.vector.riotx.core.glide.GlideApp
|
import im.vector.riotx.core.extensions.setupAsSearch
|
||||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.riotx.core.utils.DimensionUtils
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.html.PillImageSpan
|
|
||||||
import kotlinx.android.synthetic.main.fragment_create_direct_room.*
|
import kotlinx.android.synthetic.main.fragment_create_direct_room.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -64,12 +66,23 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
|||||||
setupAddByMatrixIdView()
|
setupAddByMatrixIdView()
|
||||||
setupCloseView()
|
setupCloseView()
|
||||||
viewModel.selectUserEvent.observeEvent(this) {
|
viewModel.selectUserEvent.observeEvent(this) {
|
||||||
updateFilterViewWith(it)
|
updateChipsView(it)
|
||||||
|
}
|
||||||
|
viewModel.selectSubscribe(this, CreateDirectRoomViewState::selectedUsers) {
|
||||||
|
renderSelectedUsers(it)
|
||||||
}
|
}
|
||||||
viewModel.subscribe(this) { renderState(it) }
|
viewModel.subscribe(this) { renderState(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
withState(viewModel) {
|
||||||
|
val createMenuItem = menu.findItem(R.id.action_create_direct_room)
|
||||||
|
val showMenuItem = it.selectedUsers.isNotEmpty()
|
||||||
|
createMenuItem.setVisible(showMenuItem)
|
||||||
|
}
|
||||||
|
super.onPrepareOptionsMenu(menu)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.action_create_direct_room -> {
|
R.id.action_create_direct_room -> {
|
||||||
@ -100,14 +113,7 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
|||||||
createDirectRoomFilter
|
createDirectRoomFilter
|
||||||
.textChanges()
|
.textChanges()
|
||||||
.subscribe { text ->
|
.subscribe { text ->
|
||||||
val userMatches = MatrixPatterns.PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.findAll(text)
|
val filterValue = text.trim()
|
||||||
val lastUserMatch = userMatches.lastOrNull()
|
|
||||||
val filterValue = if (lastUserMatch == null) {
|
|
||||||
text
|
|
||||||
} else {
|
|
||||||
text.substring(startIndex = lastUserMatch.range.endInclusive + 1)
|
|
||||||
}.trim()
|
|
||||||
|
|
||||||
val action = if (filterValue.isBlank()) {
|
val action = if (filterValue.isBlank()) {
|
||||||
CreateDirectRoomActions.ClearFilterKnownUsers
|
CreateDirectRoomActions.ClearFilterKnownUsers
|
||||||
} else {
|
} else {
|
||||||
@ -117,23 +123,7 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
|||||||
}
|
}
|
||||||
.disposeOnDestroy()
|
.disposeOnDestroy()
|
||||||
|
|
||||||
createDirectRoomFilter
|
createDirectRoomFilter.setupAsSearch()
|
||||||
.beforeTextChangeEvents()
|
|
||||||
.subscribe { event ->
|
|
||||||
if (event.after == 0) {
|
|
||||||
val sub = event.text.substring(0, event.start)
|
|
||||||
val startIndexOfUser = sub.lastIndexOf(" ") + 1
|
|
||||||
val user = sub.substring(startIndexOfUser)
|
|
||||||
val selectedUser = withState(viewModel) { state ->
|
|
||||||
state.selectedUsers.find { it.userId == user }
|
|
||||||
}
|
|
||||||
if (selectedUser != null) {
|
|
||||||
viewModel.handle(CreateDirectRoomActions.RemoveSelectedUser(selectedUser))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.disposeOnDestroy()
|
|
||||||
|
|
||||||
createDirectRoomFilter.requestFocus()
|
createDirectRoomFilter.requestFocus()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,32 +137,40 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
|||||||
directRoomController.setData(state)
|
directRoomController.setData(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateFilterViewWith(data: SelectUserAction) = withState(viewModel) { state ->
|
private fun updateChipsView(data: SelectUserAction) {
|
||||||
if (state.selectedUsers.isEmpty()) {
|
if (data.isAdded) {
|
||||||
createDirectRoomFilter.text = null
|
addChipToGroup(data.user, chipGroup)
|
||||||
} else {
|
} else {
|
||||||
val editable = createDirectRoomFilter.editableText
|
if (chipGroup.size > data.index) {
|
||||||
val user = data.user
|
chipGroup.removeViewAt(data.index)
|
||||||
if (data.isAdded) {
|
|
||||||
val startIndex = editable.lastIndexOf(" ") + 1
|
|
||||||
val endIndex = editable.length
|
|
||||||
editable.replace(startIndex, endIndex, "${user.userId} ")
|
|
||||||
val span = PillImageSpan(GlideApp.with(this), avatarRenderer, requireContext(), user.userId, user)
|
|
||||||
span.bind(createDirectRoomFilter)
|
|
||||||
editable.setSpan(span, startIndex, startIndex + user.userId.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
|
||||||
} else {
|
|
||||||
val startIndex = editable.indexOf(user.userId)
|
|
||||||
if (startIndex != -1) {
|
|
||||||
var endIndex = editable.indexOf(" ", startIndex) + 1
|
|
||||||
if (endIndex == 0) {
|
|
||||||
endIndex = editable.length
|
|
||||||
}
|
|
||||||
editable.replace(startIndex, endIndex, "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderSelectedUsers(selectedUsers: Set<User>) {
|
||||||
|
vectorBaseActivity.invalidateOptionsMenu()
|
||||||
|
if (selectedUsers.isNotEmpty() && chipGroup.size == 0) {
|
||||||
|
selectedUsers.forEach { addChipToGroup(it, chipGroup) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addChipToGroup(user: User, chipGroup: ChipGroup) {
|
||||||
|
val chip = Chip(requireContext())
|
||||||
|
chip.setChipBackgroundColorResource(android.R.color.transparent)
|
||||||
|
chip.chipStrokeWidth = DimensionUtils.dpToPx(1, requireContext()).toFloat()
|
||||||
|
chip.text = if (user.displayName.isNullOrBlank()) user.userId else user.displayName
|
||||||
|
chip.isClickable = true
|
||||||
|
chip.isCheckable = false
|
||||||
|
chip.isCloseIconVisible = true
|
||||||
|
chipGroup.addView(chip)
|
||||||
|
chip.setOnCloseIconClickListener {
|
||||||
|
viewModel.handle(CreateDirectRoomActions.RemoveSelectedUser(user))
|
||||||
|
}
|
||||||
|
chipGroupContainer.post {
|
||||||
|
chipGroupContainer.fullScroll(ScrollView.FOCUS_DOWN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onItemClick(user: User) {
|
override fun onItemClick(user: User) {
|
||||||
view?.hideKeyboard()
|
view?.hideKeyboard()
|
||||||
viewModel.handle(CreateDirectRoomActions.SelectUser(user))
|
viewModel.handle(CreateDirectRoomActions.SelectUser(user))
|
||||||
|
@ -40,6 +40,7 @@ abstract class CreateDirectRoomUserItem : VectorEpoxyModel<CreateDirectRoomUserI
|
|||||||
@EpoxyAttribute var clickListener: View.OnClickListener? = null
|
@EpoxyAttribute var clickListener: View.OnClickListener? = null
|
||||||
@EpoxyAttribute var selected: Boolean = false
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
holder.view.setOnClickListener(clickListener)
|
holder.view.setOnClickListener(clickListener)
|
||||||
// If name is empty, use userId as name and force it being centered
|
// If name is empty, use userId as name and force it being centered
|
||||||
@ -51,7 +52,11 @@ abstract class CreateDirectRoomUserItem : VectorEpoxyModel<CreateDirectRoomUserI
|
|||||||
holder.nameView.text = name
|
holder.nameView.text = name
|
||||||
holder.userIdView.text = userId
|
holder.userIdView.text = userId
|
||||||
}
|
}
|
||||||
if (selected) {
|
renderSelection(holder, selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun renderSelection(holder: Holder, isSelected: Boolean) {
|
||||||
|
if (isSelected) {
|
||||||
holder.avatarCheckedImageView.visibility = View.VISIBLE
|
holder.avatarCheckedImageView.visibility = View.VISIBLE
|
||||||
val backgroundColor = ContextCompat.getColor(holder.view.context, R.color.riotx_accent)
|
val backgroundColor = ContextCompat.getColor(holder.view.context, R.color.riotx_accent)
|
||||||
val backgroundDrawable = TextDrawable.builder().buildRound("", backgroundColor)
|
val backgroundDrawable = TextDrawable.builder().buildRound("", backgroundColor)
|
||||||
|
@ -41,7 +41,8 @@ private typealias DirectoryUsersSearch = String
|
|||||||
|
|
||||||
data class SelectUserAction(
|
data class SelectUserAction(
|
||||||
val user: User,
|
val user: User,
|
||||||
val isAdded: Boolean
|
val isAdded: Boolean,
|
||||||
|
val index: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||||
@ -102,28 +103,31 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
|||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleRemoveSelectedUser(action: CreateDirectRoomActions.RemoveSelectedUser) = withState {
|
private fun handleRemoveSelectedUser(action: CreateDirectRoomActions.RemoveSelectedUser) = withState { state ->
|
||||||
val selectedUsers = it.selectedUsers.minus(action.user)
|
val index = state.selectedUsers.indexOfFirst { it.userId == action.user.userId }
|
||||||
|
val selectedUsers = state.selectedUsers.minus(action.user)
|
||||||
setState { copy(selectedUsers = selectedUsers) }
|
setState { copy(selectedUsers = selectedUsers) }
|
||||||
_selectUserEvent.postLiveEvent(SelectUserAction(action.user, false))
|
_selectUserEvent.postLiveEvent(SelectUserAction(action.user, false, index))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSelectUser(action: CreateDirectRoomActions.SelectUser) = withState {
|
private fun handleSelectUser(action: CreateDirectRoomActions.SelectUser) = withState { state ->
|
||||||
//Reset the filter asap
|
//Reset the filter asap
|
||||||
knownUsersFilter.accept(Option.empty())
|
|
||||||
directoryUsersSearch.accept("")
|
directoryUsersSearch.accept("")
|
||||||
|
|
||||||
val isAddOperation: Boolean
|
val isAddOperation: Boolean
|
||||||
val selectedUsers: Set<User>
|
val selectedUsers: Set<User>
|
||||||
if (it.selectedUsers.contains(action.user)) {
|
val indexOfUser = state.selectedUsers.indexOfFirst { it.userId == action.user.userId }
|
||||||
selectedUsers = it.selectedUsers.minus(action.user)
|
val changeIndex: Int
|
||||||
isAddOperation = false
|
if (indexOfUser == -1) {
|
||||||
} else {
|
changeIndex = state.selectedUsers.size
|
||||||
selectedUsers = it.selectedUsers.plus(action.user)
|
selectedUsers = state.selectedUsers.plus(action.user)
|
||||||
isAddOperation = true
|
isAddOperation = true
|
||||||
|
} else {
|
||||||
|
changeIndex = indexOfUser
|
||||||
|
selectedUsers = state.selectedUsers.minus(action.user)
|
||||||
|
isAddOperation = false
|
||||||
}
|
}
|
||||||
setState { copy(selectedUsers = selectedUsers) }
|
setState { copy(selectedUsers = selectedUsers) }
|
||||||
_selectUserEvent.postLiveEvent(SelectUserAction(action.user, isAddOperation))
|
_selectUserEvent.postLiveEvent(SelectUserAction(action.user, isAddOperation, changeIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeDirectoryUsers() {
|
private fun observeDirectoryUsers() {
|
||||||
@ -153,7 +157,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
|||||||
} else {
|
} else {
|
||||||
users.filter {
|
users.filter {
|
||||||
it.displayName?.contains(filterValue, ignoreCase = true) ?: false
|
it.displayName?.contains(filterValue, ignoreCase = true) ?: false
|
||||||
|| it.userId.contains(filterValue, ignoreCase = true)
|
|| it.userId.contains(filterValue, ignoreCase = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,28 +58,52 @@
|
|||||||
|
|
||||||
</androidx.appcompat.widget.Toolbar>
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
<androidx.cardview.widget.CardView
|
<im.vector.riotx.core.platform.MaxHeightScrollView
|
||||||
android:id="@+id/createDirectRoomFilterContainer"
|
android:id="@+id/chipGroupContainer"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
app:cardElevation="4dp"
|
|
||||||
app:cardUseCompatPadding="true"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomToolbar">
|
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomToolbar"
|
||||||
|
app:maxHeight="80dp">
|
||||||
|
|
||||||
<EditText
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/createDirectRoomFilter"
|
android:id="@+id/chipGroup"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:maxHeight="80dp"
|
app:lineSpacing="4dp" />
|
||||||
android:importantForAutofill="no"
|
|
||||||
android:hint="@string/room_directory_search_hint"/>
|
|
||||||
|
|
||||||
</androidx.cardview.widget.CardView>
|
</im.vector.riotx.core.platform.MaxHeightScrollView>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/createDirectRoomFilter"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@string/room_directory_search_hint"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:maxHeight="80dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/chipGroupContainer" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/createDirectRoomFilterDivider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="?attr/vctr_list_divider_color"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomFilter" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/addByMatrixId"
|
android:id="@+id/addByMatrixId"
|
||||||
@ -97,7 +121,7 @@
|
|||||||
app:iconPadding="13dp"
|
app:iconPadding="13dp"
|
||||||
app:iconTint="@color/riotx_accent"
|
app:iconTint="@color/riotx_accent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/createDirectRoomFilterContainer" />
|
app:layout_constraintTop_toBottomOf="@id/createDirectRoomFilterDivider" />
|
||||||
|
|
||||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
android:id="@+id/createDirectRoomUserAvatarChecked"
|
android:id="@+id/createDirectRoomUserAvatarChecked"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
|
android:scaleType="centerInside"
|
||||||
android:src="@drawable/ic_material_done"
|
android:src="@drawable/ic_material_done"
|
||||||
android:tint="@android:color/white"
|
android:tint="@android:color/white"
|
||||||
android:visibility="visible" />
|
android:visibility="visible" />
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="MaxHeightScrollView">
|
||||||
|
<attr name="maxHeight" format="dimension" />
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
Loading…
Reference in New Issue
Block a user