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() 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 package im.vector.riotredesign.features.home.room.list


import android.os.Bundle import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Incomplete
import com.airbnb.mvrx.Success 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.failure.Failure
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.R 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.RiotFragment
import im.vector.riotredesign.core.platform.StateView import im.vector.riotredesign.core.platform.StateView
import im.vector.riotredesign.features.home.HomeNavigator import im.vector.riotredesign.features.home.HomeNavigator
@ -38,6 +43,7 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
roomController = RoomSummaryController(this) roomController = RoomSummaryController(this)
stateView.contentView = epoxyRecyclerView stateView.contentView = epoxyRecyclerView
epoxyRecyclerView.setController(roomController) epoxyRecyclerView.setController(roomController)
setupFilterView()
homeViewModel.subscribe { renderState(it) } homeViewModel.subscribe { renderState(it) }
} }


@ -70,6 +76,21 @@ class RoomListFragment : RiotFragment(), RoomSummaryController.Callback {
stateView.state = StateView.State.Error(message) 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) { override fun onRoomSelected(room: RoomSummary) {
homeViewModel.accept(RoomListActions.SelectRoom(room)) homeViewModel.accept(RoomListActions.SelectRoom(room))
homeNavigator.openRoomDetail(room.roomId, null) homeNavigator.openRoomDetail(room.roomId, null)

View File

@ -3,6 +3,7 @@ package im.vector.riotredesign.features.home.room.list
import arrow.core.Option import arrow.core.Option
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
import com.jakewharton.rxrelay2.BehaviorRelay
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.group.model.GroupSummary 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.group.SelectedGroupHolder
import im.vector.riotredesign.features.home.room.VisibleRoomHolder import im.vector.riotredesign.features.home.room.VisibleRoomHolder
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction import io.reactivex.functions.Function3
import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.subscribeBy
import org.koin.android.ext.android.get import org.koin.android.ext.android.get


typealias RoomListFilterName = CharSequence

class RoomListViewModel(initialState: RoomListViewState, class RoomListViewModel(initialState: RoomListViewState,
private val session: Session, private val session: Session,
private val selectedGroupHolder: SelectedGroupHolder, private val selectedGroupHolder: SelectedGroupHolder,
@ -35,6 +38,9 @@ class RoomListViewModel(initialState: RoomListViewState,
} }
} }



private val roomListFilter = BehaviorRelay.createDefault<Option<RoomListFilterName>>(Option.empty())

init { init {
observeRoomSummaries() observeRoomSummaries()
observeVisibleRoom() observeVisibleRoom()
@ -43,6 +49,7 @@ class RoomListViewModel(initialState: RoomListViewState,
fun accept(action: RoomListActions) { fun accept(action: RoomListActions) {
when (action) { 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() { private fun observeVisibleRoom() {
visibleRoomHolder.visibleRoom() visibleRoomHolder.visibleRoom()
.subscribeBy { .subscribeBy {
@ -63,13 +75,22 @@ class RoomListViewModel(initialState: RoomListViewState,
} }


private fun observeRoomSummaries() { private fun observeRoomSummaries() {
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, RoomSummaries>( Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, Option<RoomListFilterName>, RoomSummaries>(
session.rx().liveRoomSummaries(), session.rx().liveRoomSummaries(),
selectedGroupHolder.selectedGroup(), selectedGroupHolder.selectedGroup(),
BiFunction { rooms, selectedGroupOption -> roomListFilter,
val selectedGroup = selectedGroupOption.orNull() 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 { it.isDirect }
.filter { .filter {
if (selectedGroup == null) { if (selectedGroup == null) {
@ -81,7 +102,7 @@ class RoomListViewModel(initialState: RoomListViewState,
} }
} }


val filteredGroupRooms = rooms val filteredGroupRooms = filteredRooms
.filter { !it.isDirect } .filter { !it.isDirect }
.filter { .filter {
selectedGroup?.roomIds?.contains(it.roomId) ?: true 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:id="@+id/filterRoomView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:background="@drawable/bg_search_edit_text" android:background="@drawable/bg_search_edit_text"
android:drawableLeft="@drawable/ic_search_white" android:drawableLeft="@drawable/ic_search_white"
android:drawablePadding="8dp" android:drawablePadding="8dp"
android:drawableTint="#9fa9ba" android:drawableTint="#9fa9ba"
android:hint="Filter by name..." android:hint="Filter by name..."
android:lines="1"
android:paddingLeft="8dp" android:paddingLeft="8dp"
app:layout_constraintBottom_toTopOf="@+id/stateView" app:layout_constraintBottom_toTopOf="@+id/stateView"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -30,8 +31,8 @@
android:id="@+id/stateView" android:id="@+id/stateView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginBottom="0dp"
android:layout_marginEnd="0dp" android:layout_marginEnd="0dp"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"