forked from GitHub-Mirror/riotX-android
Autocomplete : start fetching users. Still need to adjust UI and manage selection.
This commit is contained in:
parent
aec7b73345
commit
6d3028c2d7
@ -26,6 +26,10 @@ class RxRoom(private val room: Room) {
|
|||||||
return room.roomSummary.asObservable()
|
return room.roomSummary.asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun liveRoomMemberIds(): Observable<List<String>> {
|
||||||
|
return room.getRoomMemberIdsLive().asObservable()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Room.rx(): RxRoom {
|
fun Room.rx(): RxRoom {
|
||||||
|
@ -42,11 +42,11 @@ interface RoomMembersService {
|
|||||||
fun getRoomMember(userId: String): RoomMember?
|
fun getRoomMember(userId: String): RoomMember?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all the roomMembers of the room
|
* Return all the roomMembers ids of the room
|
||||||
*
|
*
|
||||||
* @return a [LiveData] of roomMember list.
|
* @return a [LiveData] of roomMember list.
|
||||||
*/
|
*/
|
||||||
fun getRoomMembersLive(): LiveData<List<RoomMember>>
|
fun getRoomMemberIdsLive(): LiveData<List<String>>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -48,13 +48,13 @@ internal class DefaultRoomMembersService(private val roomId: String,
|
|||||||
return eventEntity?.asDomain()?.content.toModel()
|
return eventEntity?.asDomain()?.content.toModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRoomMembersLive(): LiveData<List<RoomMember>> {
|
override fun getRoomMemberIdsLive(): LiveData<List<String>> {
|
||||||
return monarchy.findAllMappedWithChanges(
|
return monarchy.findAllMappedWithChanges(
|
||||||
{
|
{
|
||||||
RoomMembers(it, roomId).queryRoomMembersEvent()
|
RoomMembers(it, roomId).queryRoomMembersEvent()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
it.asDomain().content.toModel<RoomMember>()!!
|
it.stateKey!!
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package im.vector.riotredesign.features.autocomplete.command
|
|||||||
|
|
||||||
import com.airbnb.epoxy.TypedEpoxyController
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
import im.vector.riotredesign.core.resources.StringProvider
|
import im.vector.riotredesign.core.resources.StringProvider
|
||||||
|
import im.vector.riotredesign.features.command.Command
|
||||||
|
|
||||||
class AutocompleteCommandController(private val stringProvider: StringProvider) : TypedEpoxyController<List<Command>>() {
|
class AutocompleteCommandController(private val stringProvider: StringProvider) : TypedEpoxyController<List<Command>>() {
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ import im.vector.riotredesign.R
|
|||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_command_autocomplete)
|
@EpoxyModelClass(layout = R.layout.item_autocomplete_command)
|
||||||
abstract class AutocompleteCommandItem : VectorEpoxyModel<AutocompleteCommandItem.Holder>() {
|
abstract class AutocompleteCommandItem : VectorEpoxyModel<AutocompleteCommandItem.Holder>() {
|
||||||
|
|
||||||
@EpoxyAttribute
|
@EpoxyAttribute
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.riotredesign.features.autocomplete.command
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.airbnb.epoxy.EpoxyController
|
import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.riotredesign.features.autocomplete.EpoxyViewPresenter
|
import im.vector.riotredesign.features.autocomplete.EpoxyViewPresenter
|
||||||
|
import im.vector.riotredesign.features.command.Command
|
||||||
|
|
||||||
class AutocompleteCommandPresenter(context: Context,
|
class AutocompleteCommandPresenter(context: Context,
|
||||||
private val controller: AutocompleteCommandController
|
private val controller: AutocompleteCommandController
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.autocomplete.user
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
|
||||||
|
class AutocompleteUserController() : TypedEpoxyController<List<User>>() {
|
||||||
|
|
||||||
|
override fun buildModels(data: List<User>?) {
|
||||||
|
if (data.isNullOrEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.forEach {
|
||||||
|
autocompleteUserItem {
|
||||||
|
id(it.userId)
|
||||||
|
name(it.displayName)
|
||||||
|
avatarUrl(it.avatarUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.autocomplete.user
|
||||||
|
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_autocomplete_user)
|
||||||
|
abstract class AutocompleteUserItem : VectorEpoxyModel<AutocompleteUserItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute
|
||||||
|
var name: String? = null
|
||||||
|
@EpoxyAttribute
|
||||||
|
var avatarUrl: String? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
holder.nameView.text = name
|
||||||
|
AvatarRenderer.render(avatarUrl, name, holder.avatarImageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val nameView by bind<TextView>(R.id.userAutocompleteName)
|
||||||
|
val avatarImageView by bind<ImageView>(R.id.userAutocompleteAvatar)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.autocomplete.user
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.airbnb.epoxy.EpoxyController
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.riotredesign.features.autocomplete.EpoxyViewPresenter
|
||||||
|
|
||||||
|
class AutocompleteUserPresenter(context: Context,
|
||||||
|
private val controller: AutocompleteUserController
|
||||||
|
) : EpoxyViewPresenter<User>(context) {
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
override fun providesController(): EpoxyController {
|
||||||
|
return controller
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQuery(query: CharSequence?) {
|
||||||
|
callback?.onQueryUsers(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun render(users: Async<List<User>>) {
|
||||||
|
if (users is Success) {
|
||||||
|
controller.setData(users())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onQueryUsers(query: CharSequence?)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.riotredesign.features.autocomplete.command
|
package im.vector.riotredesign.features.command
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.command
|
||||||
|
|
||||||
|
object CommandParser {
|
||||||
|
}
|
@ -20,6 +20,8 @@ import androidx.fragment.app.Fragment
|
|||||||
import im.vector.riotredesign.core.glide.GlideApp
|
import im.vector.riotredesign.core.glide.GlideApp
|
||||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandController
|
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandController
|
||||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
||||||
|
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserController
|
||||||
|
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
||||||
import im.vector.riotredesign.features.home.group.GroupSummaryController
|
import im.vector.riotredesign.features.home.group.GroupSummaryController
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.*
|
import im.vector.riotredesign.features.home.room.detail.timeline.factory.*
|
||||||
@ -81,5 +83,11 @@ class HomeModule {
|
|||||||
val commandController = AutocompleteCommandController(get())
|
val commandController = AutocompleteCommandController(get())
|
||||||
AutocompleteCommandPresenter(fragment.requireContext(), commandController)
|
AutocompleteCommandPresenter(fragment.requireContext(), commandController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scope(ROOM_DETAIL_SCOPE) { (fragment: Fragment) ->
|
||||||
|
val userController = AutocompleteUserController()
|
||||||
|
AutocompleteUserPresenter(fragment.requireContext(), userController)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -28,15 +28,20 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||||||
import com.otaliastudios.autocomplete.Autocomplete
|
import com.otaliastudios.autocomplete.Autocomplete
|
||||||
import com.otaliastudios.autocomplete.CharPolicy
|
import com.otaliastudios.autocomplete.CharPolicy
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer
|
import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer
|
||||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
||||||
import im.vector.riotredesign.features.autocomplete.command.Command
|
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
||||||
|
import im.vector.riotredesign.features.command.Command
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
import im.vector.riotredesign.features.home.HomeModule
|
import im.vector.riotredesign.features.home.HomeModule
|
||||||
import im.vector.riotredesign.features.home.HomePermalinkHandler
|
import im.vector.riotredesign.features.home.HomePermalinkHandler
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerActions
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewModel
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.composer.TextComposerViewState
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
|
import im.vector.riotredesign.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
|
||||||
import im.vector.riotredesign.features.media.MediaContentRenderer
|
import im.vector.riotredesign.features.media.MediaContentRenderer
|
||||||
@ -56,7 +61,7 @@ data class RoomDetailArgs(
|
|||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
|
|
||||||
class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callback {
|
class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callback, AutocompleteUserPresenter.Callback {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -68,8 +73,10 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val roomDetailViewModel: RoomDetailViewModel by fragmentViewModel()
|
private val roomDetailViewModel: RoomDetailViewModel by fragmentViewModel()
|
||||||
|
private val textComposerViewModel: TextComposerViewModel by fragmentViewModel()
|
||||||
private val timelineEventController: TimelineEventController by inject { parametersOf(this) }
|
private val timelineEventController: TimelineEventController by inject { parametersOf(this) }
|
||||||
private val autocompleteCommandPresenter: AutocompleteCommandPresenter by inject { parametersOf(this) }
|
private val autocompleteCommandPresenter: AutocompleteCommandPresenter by inject { parametersOf(this) }
|
||||||
|
private val autocompleteUserPresenter: AutocompleteUserPresenter by inject { parametersOf(this) }
|
||||||
private val homePermalinkHandler: HomePermalinkHandler by inject()
|
private val homePermalinkHandler: HomePermalinkHandler by inject()
|
||||||
|
|
||||||
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
|
||||||
@ -83,6 +90,7 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||||||
setupToolbar()
|
setupToolbar()
|
||||||
setupComposer()
|
setupComposer()
|
||||||
roomDetailViewModel.subscribe { renderState(it) }
|
roomDetailViewModel.subscribe { renderState(it) }
|
||||||
|
textComposerViewModel.subscribe { renderTextComposerState(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
@ -131,6 +139,14 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||||||
.with(backgroundDrawable)
|
.with(backgroundDrawable)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
autocompleteUserPresenter.callback = this
|
||||||
|
Autocomplete.on<User>(composerEditText)
|
||||||
|
.with(CharPolicy('@', false))
|
||||||
|
.with(autocompleteUserPresenter)
|
||||||
|
.with(elevation)
|
||||||
|
.with(backgroundDrawable)
|
||||||
|
.build()
|
||||||
|
|
||||||
sendButton.setOnClickListener {
|
sendButton.setOnClickListener {
|
||||||
val textMessage = composerEditText.text.toString()
|
val textMessage = composerEditText.text.toString()
|
||||||
if (textMessage.isNotBlank()) {
|
if (textMessage.isNotBlank()) {
|
||||||
@ -158,6 +174,10 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun renderTextComposerState(state: TextComposerViewState) {
|
||||||
|
autocompleteUserPresenter.render(state.asyncUsers)
|
||||||
|
}
|
||||||
|
|
||||||
// TimelineEventController.Callback ************************************************************
|
// TimelineEventController.Callback ************************************************************
|
||||||
|
|
||||||
override fun onUrlClicked(url: String) {
|
override fun onUrlClicked(url: String) {
|
||||||
@ -173,4 +193,10 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AutocompleteUserPresenter.Callback
|
||||||
|
|
||||||
|
override fun onQueryUsers(query: CharSequence?) {
|
||||||
|
textComposerViewModel.process(TextComposerActions.QueryUsers(query))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.home.room.detail.composer
|
||||||
|
|
||||||
|
sealed class TextComposerActions {
|
||||||
|
data class QueryUsers(val query: CharSequence?) : TextComposerActions()
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.home.room.detail.composer
|
||||||
|
|
||||||
|
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.session.Session
|
||||||
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.matrix.rx.rx
|
||||||
|
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.functions.BiFunction
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
typealias AutocompleteUserQuery = CharSequence
|
||||||
|
|
||||||
|
class TextComposerViewModel(initialState: TextComposerViewState,
|
||||||
|
private val session: Session
|
||||||
|
) : VectorViewModel<TextComposerViewState>(initialState) {
|
||||||
|
|
||||||
|
private val room = session.getRoom(initialState.roomId)!!
|
||||||
|
private val roomId = initialState.roomId
|
||||||
|
|
||||||
|
private val usersQueryObservable = BehaviorRelay.create<Option<AutocompleteUserQuery>>()
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<TextComposerViewModel, TextComposerViewState> {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: TextComposerViewState): TextComposerViewModel? {
|
||||||
|
val currentSession = viewModelContext.activity.get<Session>()
|
||||||
|
return TextComposerViewModel(state, currentSession)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
observeUsersQuery()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun process(action: TextComposerActions) {
|
||||||
|
when (action) {
|
||||||
|
is TextComposerActions.QueryUsers -> handleQueryUsers(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleQueryUsers(action: TextComposerActions.QueryUsers) {
|
||||||
|
val query = Option.fromNullable(action.query)
|
||||||
|
usersQueryObservable.accept(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeUsersQuery() {
|
||||||
|
Observable.combineLatest<List<String>, Option<AutocompleteUserQuery>, List<User>>(
|
||||||
|
room.rx().liveRoomMemberIds(),
|
||||||
|
usersQueryObservable.throttleLast(300, TimeUnit.MILLISECONDS),
|
||||||
|
BiFunction { roomMembers, query ->
|
||||||
|
val users = roomMembers
|
||||||
|
.mapNotNull {
|
||||||
|
session.getUser(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val filter = query.orNull()
|
||||||
|
if (filter.isNullOrBlank()) {
|
||||||
|
users
|
||||||
|
} else {
|
||||||
|
users.filter {
|
||||||
|
it.displayName?.startsWith(prefix = filter, ignoreCase = true)
|
||||||
|
?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).execute { async ->
|
||||||
|
copy(
|
||||||
|
asyncUsers = async
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.riotredesign.features.home.room.detail.composer
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.Async
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.riotredesign.features.home.room.detail.RoomDetailArgs
|
||||||
|
|
||||||
|
|
||||||
|
data class TextComposerViewState(val roomId: String,
|
||||||
|
val asyncUsers: Async<List<User>> = Uninitialized
|
||||||
|
) : MvRxState {
|
||||||
|
|
||||||
|
constructor(args: RoomDetailArgs) : this(roomId = args.roomId)
|
||||||
|
|
||||||
|
}
|
28
vector/src/main/res/layout/item_autocomplete_user.xml
Normal file
28
vector/src/main/res/layout/item_autocomplete_user.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?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="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/userAutocompleteAvatar"
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/userAutocompleteName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginLeft="12dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:text="name" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
Loading…
Reference in New Issue
Block a user