forked from GitHub-Mirror/riotX-android
Direct messages: try to handle selecting/deselecting users (WIP)
This commit is contained in:
parent
03974c8bdf
commit
125eacb20b
@ -28,7 +28,7 @@ object MatrixPatterns {
|
||||
// regex pattern to find matrix user ids in a string.
|
||||
// See https://matrix.org/speculator/spec/HEAD/appendices.html#historical-user-ids
|
||||
private const val MATRIX_USER_IDENTIFIER_REGEX = "@[A-Z0-9\\x21-\\x39\\x3B-\\x7F]+$DOMAIN_REGEX"
|
||||
private val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
val PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER = MATRIX_USER_IDENTIFIER_REGEX.toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
// regex pattern to find room ids in a string.
|
||||
private const val MATRIX_ROOM_IDENTIFIER_REGEX = "![A-Z0-9]+$DOMAIN_REGEX"
|
||||
|
@ -18,6 +18,7 @@ package im.vector.riotx.core.extensions
|
||||
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import im.vector.riotx.core.utils.FirstThrottler
|
||||
import im.vector.riotx.core.utils.EventObserver
|
||||
@ -44,3 +45,7 @@ inline fun <T> LiveData<LiveEvent<T>>.observeEventFirstThrottle(owner: Lifecycle
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun <T> MutableLiveData<LiveEvent<T>>.postLiveEvent(content: T) {
|
||||
this.postValue(LiveEvent(content))
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package im.vector.riotx.core.mvrx
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
|
||||
abstract class NavigationViewModel<NavigationClass> : ViewModel() {
|
||||
@ -29,6 +30,6 @@ abstract class NavigationViewModel<NavigationClass> : ViewModel() {
|
||||
|
||||
|
||||
fun goTo(navigation: NavigationClass) {
|
||||
_navigateTo.postValue(LiveEvent(navigation))
|
||||
_navigateTo.postLiveEvent(navigation)
|
||||
}
|
||||
}
|
@ -16,20 +16,36 @@
|
||||
|
||||
package im.vector.riotx.core.platform
|
||||
|
||||
import com.airbnb.mvrx.BaseMvRxViewModel
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.*
|
||||
import im.vector.matrix.android.api.util.CancelableBag
|
||||
import im.vector.riotx.BuildConfig
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.Disposable
|
||||
|
||||
abstract class VectorViewModel<S : MvRxState>(initialState: S)
|
||||
: BaseMvRxViewModel<S>(initialState, false) {
|
||||
|
||||
protected val cancelableBag = CancelableBag()
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
cancelableBag.cancel()
|
||||
/**
|
||||
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
|
||||
* so you can use this in a switchMap or a flatMap
|
||||
*/
|
||||
fun <T> Single<T>.toAsync(stateReducer: S.(Async<T>) -> S): Single<Async<T>> {
|
||||
setState { stateReducer(Loading()) }
|
||||
return this.map { Success(it) as Async<T> }
|
||||
.onErrorReturn { Fail(it) }
|
||||
.doOnSuccess { setState { stateReducer(it) } }
|
||||
}
|
||||
|
||||
/**
|
||||
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
|
||||
* so you can use this in a switchMap or a flatMap
|
||||
*/
|
||||
fun <T> Observable<T>.toAsync(stateReducer: S.(Async<T>) -> S): Observable<Async<T>> {
|
||||
setState { stateReducer(Loading()) }
|
||||
return this.map { Success(it) as Async<T> }
|
||||
.onErrorReturn { Fail(it) }
|
||||
.doOnNext { setState { stateReducer(it) } }
|
||||
}
|
||||
|
||||
}
|
@ -19,13 +19,9 @@
|
||||
package im.vector.riotx.features.home.createdirect
|
||||
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import com.airbnb.epoxy.VisibilityState
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.android.internal.util.firstLetterOfDisplayName
|
||||
import im.vector.riotx.core.epoxy.errorWithRetryItem
|
||||
@ -60,7 +56,7 @@ class CreateDirectRoomController @Inject constructor(private val avatarRenderer:
|
||||
}
|
||||
when (asyncUsers) {
|
||||
is Incomplete -> renderLoading()
|
||||
is Success -> renderUsers(asyncUsers(), currentState.selectedUsers)
|
||||
is Success -> renderUsers(asyncUsers(), currentState.selectedUsers.map { it.userId })
|
||||
is Fail -> renderFailure(asyncUsers.error)
|
||||
}
|
||||
}
|
||||
@ -79,10 +75,10 @@ class CreateDirectRoomController @Inject constructor(private val avatarRenderer:
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderUsers(users: List<User>, selectedUsers: Set<User>) {
|
||||
private fun renderUsers(users: List<User>, selectedUsers: List<String>) {
|
||||
var lastFirstLetter: String? = null
|
||||
users.forEach { user ->
|
||||
val isSelected = selectedUsers.contains(user)
|
||||
val isSelected = selectedUsers.contains(user.userId)
|
||||
val currentFirstLetter = user.displayName.firstLetterOfDisplayName()
|
||||
val showLetter = currentFirstLetter.isNotEmpty() && lastFirstLetter != currentFirstLetter
|
||||
lastFirstLetter = currentFirstLetter
|
||||
|
@ -25,6 +25,7 @@ import com.jakewharton.rxbinding3.widget.textChanges
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.hideKeyboard
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import kotlinx.android.synthetic.main.fragment_create_direct_room_directory_users.*
|
||||
import javax.inject.Inject
|
||||
@ -82,6 +83,7 @@ class CreateDirectRoomDirectoryUsersFragment : VectorBaseFragment(), CreateDirec
|
||||
}
|
||||
|
||||
override fun onItemClick(user: User) {
|
||||
view?.hideKeyboard()
|
||||
viewModel.handle(CreateDirectRoomActions.SelectUser(user))
|
||||
navigationViewModel.goTo(CreateDirectRoomActivity.Navigation.Previous)
|
||||
}
|
||||
|
@ -19,21 +19,24 @@
|
||||
package im.vector.riotx.features.home.createdirect
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Spannable
|
||||
import android.view.MenuItem
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.jakewharton.rxbinding3.widget.beforeTextChangeEvents
|
||||
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.riotx.R
|
||||
import im.vector.riotx.core.di.ScreenComponent
|
||||
import im.vector.riotx.core.extensions.hideKeyboard
|
||||
import im.vector.riotx.core.extensions.observeEvent
|
||||
import im.vector.riotx.core.glide.GlideApp
|
||||
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
|
||||
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_public_rooms.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomController.Callback {
|
||||
@ -45,6 +48,7 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
||||
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
|
||||
|
||||
@Inject lateinit var directRoomController: CreateDirectRoomController
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
private lateinit var navigationViewModel: CreateDirectRoomNavigationViewModel
|
||||
|
||||
override fun injectWith(injector: ScreenComponent) {
|
||||
@ -59,6 +63,10 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
||||
setupFilterView()
|
||||
setupAddByMatrixIdView()
|
||||
setupCloseView()
|
||||
viewModel.selectUserEvent.observeEvent(this) {
|
||||
updateFilterViewWith(it)
|
||||
|
||||
}
|
||||
viewModel.subscribe(this) { renderState(it) }
|
||||
}
|
||||
|
||||
@ -90,16 +98,43 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
||||
|
||||
private fun setupFilterView() {
|
||||
createDirectRoomFilter
|
||||
.queryTextChanges()
|
||||
.subscribe {
|
||||
val action = if (it.isNullOrEmpty()) {
|
||||
.textChanges()
|
||||
.subscribe { text ->
|
||||
val userMatches = MatrixPatterns.PATTERN_CONTAIN_MATRIX_USER_IDENTIFIER.findAll(text)
|
||||
val lastUserMatch = userMatches.lastOrNull()
|
||||
val filterValue = if (lastUserMatch == null) {
|
||||
text
|
||||
} else {
|
||||
text.substring(startIndex = lastUserMatch.range.endInclusive + 1)
|
||||
}.trim()
|
||||
|
||||
val action = if (filterValue.isBlank()) {
|
||||
CreateDirectRoomActions.ClearFilterKnownUsers
|
||||
} else {
|
||||
CreateDirectRoomActions.FilterKnownUsers(it.toString())
|
||||
CreateDirectRoomActions.FilterKnownUsers(filterValue.toString())
|
||||
}
|
||||
viewModel.handle(action)
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
createDirectRoomFilter
|
||||
.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()
|
||||
}
|
||||
|
||||
private fun setupCloseView() {
|
||||
@ -109,11 +144,37 @@ class CreateDirectRoomFragment : VectorBaseFragment(), CreateDirectRoomControlle
|
||||
}
|
||||
|
||||
private fun renderState(state: CreateDirectRoomViewState) {
|
||||
|
||||
directRoomController.setData(state)
|
||||
}
|
||||
|
||||
private fun updateFilterViewWith(data: SelectUserAction) = withState(viewModel) { state ->
|
||||
if (state.selectedUsers.isEmpty()) {
|
||||
createDirectRoomFilter.text = null
|
||||
} else {
|
||||
val editable = createDirectRoomFilter.editableText
|
||||
val user = data.user
|
||||
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, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemClick(user: User) {
|
||||
view?.hideKeyboard()
|
||||
viewModel.handle(CreateDirectRoomActions.SelectUser(user))
|
||||
}
|
||||
}
|
@ -28,9 +28,7 @@ import com.amulyakhare.textdrawable.TextDrawable
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.home.getColorFromUserId
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_create_direct_room_user)
|
||||
abstract class CreateDirectRoomUserItem : VectorEpoxyModel<CreateDirectRoomUserItem.Holder>() {
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
package im.vector.riotx.features.home.createdirect
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import arrow.core.Option
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.airbnb.mvrx.*
|
||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
@ -29,7 +29,9 @@ import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import java.util.concurrent.TimeUnit
|
||||
@ -37,6 +39,11 @@ import java.util.concurrent.TimeUnit
|
||||
private typealias KnowUsersFilter = String
|
||||
private typealias DirectoryUsersSearch = String
|
||||
|
||||
data class SelectUserAction(
|
||||
val user: User,
|
||||
val isAdded: Boolean
|
||||
)
|
||||
|
||||
class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||
initialState: CreateDirectRoomViewState,
|
||||
private val session: Session)
|
||||
@ -50,6 +57,10 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||
private val knownUsersFilter = BehaviorRelay.createDefault<Option<KnowUsersFilter>>(Option.empty())
|
||||
private val directoryUsersSearch = BehaviorRelay.create<DirectoryUsersSearch>()
|
||||
|
||||
private val _selectUserEvent = MutableLiveData<LiveEvent<SelectUserAction>>()
|
||||
val selectUserEvent: LiveData<LiveEvent<SelectUserAction>>
|
||||
get() = _selectUserEvent
|
||||
|
||||
companion object : MvRxViewModelFactory<CreateDirectRoomViewModel, CreateDirectRoomViewState> {
|
||||
|
||||
@JvmStatic
|
||||
@ -78,7 +89,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||
private fun createRoomAndInviteSelectedUsers() = withState { currentState ->
|
||||
val isDirect = currentState.selectedUsers.size == 1
|
||||
val roomParams = CreateRoomParams().apply {
|
||||
invitedUserIds = ArrayList(currentState.selectedUsers.map { user -> user.userId })
|
||||
invitedUserIds = ArrayList(currentState.selectedUsers.map { it.userId })
|
||||
if (isDirect) {
|
||||
setDirectMessage()
|
||||
}
|
||||
@ -92,33 +103,42 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||
}
|
||||
|
||||
private fun handleRemoveSelectedUser(action: CreateDirectRoomActions.RemoveSelectedUser) = withState {
|
||||
val selectedUsers = it.selectedUsers.minusElement(action.user)
|
||||
val selectedUsers = it.selectedUsers.minus(action.user)
|
||||
setState { copy(selectedUsers = selectedUsers) }
|
||||
_selectUserEvent.postLiveEvent(SelectUserAction(action.user, false))
|
||||
}
|
||||
|
||||
private fun handleSelectUser(action: CreateDirectRoomActions.SelectUser) = withState {
|
||||
val selectedUsers = if (it.selectedUsers.contains(action.user)) {
|
||||
it.selectedUsers.minusElement(action.user)
|
||||
//Reset the filter asap
|
||||
knownUsersFilter.accept(Option.empty())
|
||||
directoryUsersSearch.accept("")
|
||||
|
||||
val isAddOperation: Boolean
|
||||
val selectedUsers: Set<User>
|
||||
if (it.selectedUsers.contains(action.user)) {
|
||||
selectedUsers = it.selectedUsers.minus(action.user)
|
||||
isAddOperation = false
|
||||
} else {
|
||||
it.selectedUsers.plus(action.user)
|
||||
selectedUsers = it.selectedUsers.plus(action.user)
|
||||
isAddOperation = true
|
||||
}
|
||||
setState { copy(selectedUsers = selectedUsers) }
|
||||
_selectUserEvent.postLiveEvent(SelectUserAction(action.user, isAddOperation))
|
||||
}
|
||||
|
||||
private fun observeDirectoryUsers() {
|
||||
directoryUsersSearch
|
||||
.throttleLast(300, TimeUnit.MILLISECONDS)
|
||||
.throttleLast(500, TimeUnit.MILLISECONDS)
|
||||
.switchMapSingle { search ->
|
||||
session.rx()
|
||||
.searchUsersDirectory(search, 50, emptySet())
|
||||
.map { users ->
|
||||
users.sortedBy { it.displayName }
|
||||
}
|
||||
.toAsync { copy(directoryUsers = it) }
|
||||
}
|
||||
.execute { async ->
|
||||
copy(directoryUsers = async)
|
||||
}
|
||||
|
||||
.subscribe()
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeKnownUsers() {
|
||||
@ -133,7 +153,7 @@ class CreateDirectRoomViewModel @AssistedInject constructor(@Assisted
|
||||
} else {
|
||||
users.filter {
|
||||
it.displayName?.contains(filterValue, ignoreCase = true) ?: false
|
||||
|| it.userId.contains(filterValue, ignoreCase = true)
|
||||
|| it.userId.contains(filterValue, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
@ -67,7 +68,7 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
|
||||
private fun observeSelectionState() {
|
||||
selectSubscribe(GroupListViewState::selectedGroup) {
|
||||
if (it != null) {
|
||||
_openGroupLiveData.postValue(LiveEvent(it))
|
||||
_openGroupLiveData.postLiveEvent(it)
|
||||
val optionGroup = Option.fromNullable(it)
|
||||
selectedGroupHolder.post(optionGroup)
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.internal.crypto.attachments.toElementToDecrypt
|
||||
import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.intent.getFilenameFromUri
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||
@ -168,62 +169,62 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
is ParsedCommand.ErrorNotACommand -> {
|
||||
// Send the text message to the room
|
||||
room.sendTextMessage(action.text, autoMarkdown = action.autoMarkdown)
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent)
|
||||
}
|
||||
is ParsedCommand.ErrorSyntax -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandError(slashCommandResult.command)))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandError(slashCommandResult.command))
|
||||
}
|
||||
is ParsedCommand.ErrorEmptySlashCommand -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown("/")))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandUnknown("/"))
|
||||
}
|
||||
is ParsedCommand.ErrorUnknownSlashCommand -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand)))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand))
|
||||
}
|
||||
is ParsedCommand.Invite -> {
|
||||
handleInviteSlashCommand(slashCommandResult)
|
||||
}
|
||||
is ParsedCommand.SetUserPowerLevel -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.ClearScalarToken -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.SetMarkdown -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.UnbanUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.BanUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.KickUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.JoinRoom -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.PartRoom -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
is ParsedCommand.SendEmote -> {
|
||||
room.sendTextMessage(slashCommandResult.message, msgType = MessageType.MSGTYPE_EMOTE)
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled)
|
||||
}
|
||||
is ParsedCommand.ChangeTopic -> {
|
||||
handleChangeTopicSlashCommand(slashCommandResult)
|
||||
}
|
||||
is ParsedCommand.ChangeDisplayName -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandNotImplemented)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,7 +256,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
sendMode = SendMode.REGULAR
|
||||
)
|
||||
}
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent)
|
||||
}
|
||||
is SendMode.QUOTE -> {
|
||||
val messageContent: MessageContent? =
|
||||
@ -280,7 +281,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
sendMode = SendMode.REGULAR
|
||||
)
|
||||
}
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent)
|
||||
}
|
||||
is SendMode.REPLY -> {
|
||||
state.sendMode.timelineEvent.let {
|
||||
@ -290,7 +291,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
sendMode = SendMode.REGULAR
|
||||
)
|
||||
}
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.MessageSent)
|
||||
}
|
||||
|
||||
}
|
||||
@ -319,29 +320,29 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
}
|
||||
|
||||
private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled)
|
||||
|
||||
room.updateTopic(changeTopic.topic, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultOk))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultOk)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultError(failure)))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultError(failure))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandHandled)
|
||||
|
||||
room.invite(invite.userId, object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultOk))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultOk)
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultError(failure)))
|
||||
_sendMessageResultLiveData.postLiveEvent(SendMessageResult.SlashCommandResultError(failure))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -453,19 +454,19 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
action.messageFileContent.encryptedFileInfo?.toElementToDecrypt(),
|
||||
object : MatrixCallback<File> {
|
||||
override fun onSuccess(data: File) {
|
||||
_downloadedFileEvent.postValue(LiveEvent(DownloadFileState(
|
||||
_downloadedFileEvent.postLiveEvent(DownloadFileState(
|
||||
action.messageFileContent.getMimeType(),
|
||||
data,
|
||||
null
|
||||
)))
|
||||
))
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
_downloadedFileEvent.postValue(LiveEvent(DownloadFileState(
|
||||
_downloadedFileEvent.postLiveEvent(DownloadFileState(
|
||||
action.messageFileContent.getMimeType(),
|
||||
null,
|
||||
failure
|
||||
)))
|
||||
))
|
||||
}
|
||||
})
|
||||
|
||||
@ -494,7 +495,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
}
|
||||
}
|
||||
|
||||
_navigateToEvent.postValue(LiveEvent(targetEventId))
|
||||
_navigateToEvent.postLiveEvent(targetEventId)
|
||||
} else {
|
||||
// change timeline
|
||||
timeline.dispose()
|
||||
@ -519,7 +520,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||
}
|
||||
}
|
||||
|
||||
_navigateToEvent.postValue(LiveEvent(targetEventId))
|
||||
_navigateToEvent.postLiveEvent(targetEventId)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
import im.vector.riotx.features.home.HomeRoomListObservableStore
|
||||
@ -142,7 +143,7 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// Notify the user
|
||||
_invitationAnswerErrorLiveData.postValue(LiveEvent(failure))
|
||||
_invitationAnswerErrorLiveData.postLiveEvent(failure)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
@ -178,7 +179,7 @@ class RoomListViewModel @AssistedInject constructor(@Assisted initialState: Room
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// Notify the user
|
||||
_invitationAnswerErrorLiveData.postValue(LiveEvent(failure))
|
||||
_invitationAnswerErrorLiveData.postLiveEvent(failure)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
|
@ -31,6 +31,7 @@ import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRooms
|
||||
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotx.core.extensions.postLiveEvent
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import im.vector.riotx.core.utils.LiveEvent
|
||||
import timber.log.Timber
|
||||
@ -207,7 +208,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(@Assisted initialState:
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
// Notify the user
|
||||
_joinRoomErrorLiveData.postValue(LiveEvent(failure))
|
||||
_joinRoomErrorLiveData.postLiveEvent(failure)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
|
@ -71,16 +71,13 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/createDirectRoomToolbar">
|
||||
|
||||
<androidx.appcompat.widget.SearchView
|
||||
<EditText
|
||||
android:id="@+id/createDirectRoomFilter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text|textMultiLine"
|
||||
app:closeIcon="@drawable/ic_x_green"
|
||||
app:iconifiedByDefault="false"
|
||||
app:queryBackground="@android:color/transparent"
|
||||
app:queryHint="@string/room_directory_search_hint"
|
||||
app:searchIcon="@drawable/ic_filter" />
|
||||
android:maxHeight="80dp"
|
||||
android:importantForAutofill="no"
|
||||
android:hint="@string/room_directory_search_hint"/>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user