Room list : quickly branch filter room name field

This commit is contained in:
ganfra 2019-01-21 19:39:45 +01:00
parent 32b29c47e7
commit 85608b04d1
11 changed files with 109 additions and 10 deletions

View file

@ -0,0 +1,44 @@
package im.vector.riotredesign.core.extensions
import android.text.Editable
import android.text.InputType
import android.text.TextWatcher
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import im.vector.riotredesign.R
fun EditText.setupAsSearch() {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
val clearIcon = if (editable?.isNotEmpty() == true) R.drawable.ic_clear_white else 0
setCompoundDrawablesWithIntrinsicBounds(0, 0, clearIcon, 0)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
})
maxLines = 1
inputType = InputType.TYPE_CLASS_TEXT
imeOptions = EditorInfo.IME_ACTION_SEARCH
setOnEditorActionListener { _, actionId, event ->
var consumed = false
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
hideKeyboard()
consumed = true
}
consumed
}
setOnTouchListener(View.OnTouchListener { _, event ->
if (event.action == MotionEvent.ACTION_UP) {
if (event.rawX >= (this.right - this.compoundPaddingRight)) {
text = null
return@OnTouchListener true
}
}
return@OnTouchListener false
})
}

View file

@ -0,0 +1,10 @@
package im.vector.riotredesign.core.extensions
import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
fun View.hideKeyboard() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(windowToken, 0)
}

View file

@ -8,4 +8,6 @@ sealed class RoomListActions {
object RoomDisplayed : RoomListActions()
data class FilterRooms(val roomName: CharSequence? = null) : RoomListActions()
}

View file

@ -1,9 +1,12 @@
package im.vector.riotredesign.features.home.room.list
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success
@ -11,6 +14,8 @@ import com.airbnb.mvrx.activityViewModel
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.R
import im.vector.riotredesign.core.extensions.hideKeyboard
import im.vector.riotredesign.core.extensions.setupAsSearch
import im.vector.riotredesign.core.platform.RiotFragment
import im.vector.riotredesign.core.platform.StateView
import im.vector.riotredesign.features.home.HomeNavigator
@ -38,6 +43,7 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
roomController = RoomSummaryController(this)
stateView.contentView = epoxyRecyclerView
epoxyRecyclerView.setController(roomController)
setupFilterView()
homeViewModel.subscribe { renderState(it) }
}
@ -70,6 +76,21 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
stateView.state = StateView.State.Error(message)
}
private fun setupFilterView() {
filterRoomView.setupAsSearch()
filterRoomView.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) = Unit
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
homeViewModel.accept(RoomListActions.FilterRooms(s))
}
})
}
// RoomSummaryController.Callback **************************************************************
override fun onRoomSelected(room: RoomSummary) {
homeViewModel.accept(RoomListActions.SelectRoom(room))
homeNavigator.openRoomDetail(room.roomId, null)

View file

@ -3,6 +3,7 @@ package im.vector.riotredesign.features.home.room.list
import arrow.core.Option
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.group.model.GroupSummary
@ -12,10 +13,12 @@ import im.vector.riotredesign.core.platform.RiotViewModel
import im.vector.riotredesign.features.home.group.SelectedGroupHolder
import im.vector.riotredesign.features.home.room.VisibleRoomHolder
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.functions.Function3
import io.reactivex.rxkotlin.subscribeBy
import org.koin.android.ext.android.get
typealias RoomListFilterName = CharSequence
class RoomListViewModel(initialState: RoomListViewState,
private val session: Session,
private val selectedGroupHolder: SelectedGroupHolder,
@ -35,6 +38,9 @@ class RoomListViewModel(initialState: RoomListViewState,
}
}
private val roomListFilter = BehaviorRelay.createDefault<Option<RoomListFilterName>>(Option.empty())
init {
observeRoomSummaries()
observeVisibleRoom()
@ -42,7 +48,8 @@ class RoomListViewModel(initialState: RoomListViewState,
fun accept(action: RoomListActions) {
when (action) {
is RoomListActions.SelectRoom -> handleSelectRoom(action)
is RoomListActions.SelectRoom -> handleSelectRoom(action)
is RoomListActions.FilterRooms -> handleFilterRooms(action)
}
}
@ -54,6 +61,11 @@ class RoomListViewModel(initialState: RoomListViewState,
}
}
private fun handleFilterRooms(action: RoomListActions.FilterRooms) {
val optionalFilter = Option.fromNullable(action.roomName)
roomListFilter.accept(optionalFilter)
}
private fun observeVisibleRoom() {
visibleRoomHolder.visibleRoom()
.subscribeBy {
@ -63,13 +75,22 @@ class RoomListViewModel(initialState: RoomListViewState,
}
private fun observeRoomSummaries() {
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, RoomSummaries>(
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, Option<RoomListFilterName>, RoomSummaries>(
session.rx().liveRoomSummaries(),
selectedGroupHolder.selectedGroup(),
BiFunction { rooms, selectedGroupOption ->
val selectedGroup = selectedGroupOption.orNull()
roomListFilter,
Function3 { rooms, selectedGroupOption, filterRoomOption ->
val filterRoom = filterRoomOption.orNull()
val filteredRooms = rooms.filter {
if (filterRoom.isNullOrBlank()) {
true
} else {
it.displayName.contains(other = filterRoom, ignoreCase = true)
}
}
val filteredDirectRooms = rooms
val selectedGroup = selectedGroupOption.orNull()
val filteredDirectRooms = filteredRooms
.filter { it.isDirect }
.filter {
if (selectedGroup == null) {
@ -81,7 +102,7 @@ class RoomListViewModel(initialState: RoomListViewState,
}
}
val filteredGroupRooms = rooms
val filteredGroupRooms = filteredRooms
.filter { !it.isDirect }
.filter {
selectedGroup?.roomIds?.contains(it.roomId) ?: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

View file

@ -11,15 +11,16 @@
android:id="@+id/filterRoomView"
android:layout_width="0dp"
android:layout_height="32dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_search_edit_text"
android:drawableLeft="@drawable/ic_search_white"
android:drawablePadding="8dp"
android:drawableTint="#9fa9ba"
android:hint="Filter by name..."
android:lines="1"
android:paddingLeft="8dp"
app:layout_constraintBottom_toTopOf="@+id/stateView"
app:layout_constraintEnd_toEndOf="parent"
@ -30,8 +31,8 @@
android:id="@+id/stateView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="0dp"
android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"