SlashCommand: handle user invitation

This commit is contained in:
Benoit Marty 2019-04-09 14:35:18 +02:00
parent eae8f993e6
commit 81ddb8c5fb
11 changed files with 129 additions and 19 deletions

View file

@ -22,7 +22,6 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.read.ReadService
import im.vector.matrix.android.api.session.room.send.SendService
import im.vector.matrix.android.api.session.room.timeline.TimelineService
import im.vector.matrix.android.api.util.Cancelable
/**
* This interface defines methods to interact within a room.

View file

@ -19,6 +19,7 @@
package im.vector.matrix.android.api.session.room.members
import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.api.util.Cancelable
@ -48,5 +49,9 @@ interface RoomMembersService {
*/
fun getRoomMemberIdsLive(): LiveData<List<String>>
/**
* Invite a user in the room
*/
fun invite(userId: String, callback: MatrixCallback<Unit>)
}

View file

@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
import im.vector.matrix.android.api.session.room.model.create.CreateRoomResponse
import im.vector.matrix.android.internal.network.NetworkConstants
import im.vector.matrix.android.internal.session.room.invite.InviteBody
import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
import im.vector.matrix.android.internal.session.room.send.SendResponse
import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
@ -120,5 +121,14 @@ internal interface RoomAPI {
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/read_markers")
fun sendReadMarker(@Path("roomId") roomId: String, @Body markers: Map<String, String>): Call<Unit>
/**
* Invite a user to the given room.
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#post-matrix-client-r0-rooms-roomid-invite
*
* @param roomId the room id
* @param body a object that just contains a user id
*/
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/invite")
fun invite(@Path("roomId") roomId: String, @Body body: InviteBody): Call<Unit>
}

View file

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.room
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.internal.session.room.invite.InviteTask
import im.vector.matrix.android.internal.session.room.members.DefaultRoomMembersService
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor
@ -32,6 +33,7 @@ import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFact
import im.vector.matrix.android.internal.task.TaskExecutor
internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask,
private val inviteTask: InviteTask,
private val monarchy: Monarchy,
private val paginationTask: PaginationTask,
private val contextOfEventTask: GetContextOfEventTask,
@ -44,7 +46,7 @@ internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask,
val timelineEventFactory = TimelineEventFactory(roomMemberExtractor)
val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask)
val sendService = DefaultSendService(roomId, eventFactory, monarchy)
val roomMembersService = DefaultRoomMembersService(roomId, monarchy, loadRoomMembersTask, taskExecutor)
val roomMembersService = DefaultRoomMembersService(roomId, monarchy, loadRoomMembersTask, inviteTask, taskExecutor)
val readService = DefaultReadService(roomId, monarchy, setReadMarkersTask, taskExecutor)
return DefaultRoom(

View file

@ -19,6 +19,8 @@ package im.vector.matrix.android.internal.session.room
import im.vector.matrix.android.internal.session.DefaultSession
import im.vector.matrix.android.internal.session.room.create.CreateRoomTask
import im.vector.matrix.android.internal.session.room.create.DefaultCreateRoomTask
import im.vector.matrix.android.internal.session.room.invite.DefaultInviteTask
import im.vector.matrix.android.internal.session.room.invite.InviteTask
import im.vector.matrix.android.internal.session.room.members.DefaultLoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask
@ -63,12 +65,16 @@ class RoomModule {
}
scope(DefaultSession.SCOPE) {
RoomFactory(get(), get(), get(), get(), get(), get(), get())
RoomFactory(get(), get(), get(), get(), get(), get(), get(), get())
}
scope(DefaultSession.SCOPE) {
DefaultCreateRoomTask(get(), get()) as CreateRoomTask
}
scope(DefaultSession.SCOPE) {
DefaultInviteTask(get()) as InviteTask
}
}
}

View file

@ -0,0 +1,25 @@
/*
* 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.matrix.android.internal.session.room.invite
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
data class InviteBody(
@Json(name = "user_id") val userId: String
)

View file

@ -0,0 +1,40 @@
/*
* 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.matrix.android.internal.session.room.invite
import arrow.core.Try
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task
internal interface InviteTask : Task<InviteTask.Params, Unit> {
data class Params(
val roomId: String,
val userId: String
)
}
internal class DefaultInviteTask(private val roomAPI: RoomAPI) : InviteTask {
override fun execute(params: InviteTask.Params): Try<Unit> {
return executeRequest {
val body = InviteBody(params.userId)
apiCall = roomAPI.invite(params.roomId, body)
}
}
}

View file

@ -20,12 +20,14 @@ package im.vector.matrix.android.internal.session.room.members
import androidx.lifecycle.LiveData
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.members.RoomMembersService
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomMember
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.session.room.invite.InviteTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.fetchCopied
@ -33,6 +35,7 @@ import im.vector.matrix.android.internal.util.fetchCopied
internal class DefaultRoomMembersService(private val roomId: String,
private val monarchy: Monarchy,
private val loadRoomMembersTask: LoadRoomMembersTask,
private val inviteTask: InviteTask,
private val taskExecutor: TaskExecutor
) : RoomMembersService {
@ -58,4 +61,11 @@ internal class DefaultRoomMembersService(private val roomId: String,
}
)
}
override fun invite(userId: String, callback: MatrixCallback<Unit>) {
val params = InviteTask.Params(roomId, userId)
inviteTask.configureWith(params)
.dispatchTo(callback)
.executeBy(taskExecutor)
}
}

View file

@ -40,7 +40,6 @@ import im.vector.riotredesign.core.extensions.observeEvent
import im.vector.riotredesign.core.glide.GlideApp
import im.vector.riotredesign.core.platform.ToolbarConfigurable
import im.vector.riotredesign.core.platform.VectorBaseFragment
import im.vector.riotredesign.core.utils.toast
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
import im.vector.riotredesign.features.autocomplete.command.CommandAutocompletePolicy
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
@ -240,23 +239,30 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
private fun renderSendMessageResult(sendMessageResult: SendMessageResult) {
when (sendMessageResult) {
is SendMessageResult.MessageSent, is SendMessageResult.SlashCommandHandled -> {
is SendMessageResult.MessageSent,
is SendMessageResult.SlashCommandHandled -> {
// Clear composer
composerEditText.text = null
}
is SendMessageResult.SlashCommandError -> {
displayError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
}
is SendMessageResult.SlashCommandUnknown -> {
displayError(getString(R.string.unrecognized_command, sendMessageResult.command))
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
}
is SendMessageResult.SlashCommandResultOk -> {
// Ignore
}
is SendMessageResult.SlashCommandResultError -> {
displayCommandError(sendMessageResult.throwable.localizedMessage)
}
is SendMessageResult.SlashCommandNotImplemented -> {
activity!!.toast(R.string.not_implemented)
displayCommandError(getString(R.string.not_implemented))
}
}
}
private fun displayError(message: String) {
private fun displayCommandError(message: String) {
AlertDialog.Builder(activity!!)
.setTitle(R.string.command_error)
.setMessage(message)

View file

@ -100,17 +100,8 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
is ParsedCommand.ErrorUnknownSlashCommand -> {
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand)))
}
else -> {
handleValidSlashCommand(slashCommandResult)
}
}
}
private fun handleValidSlashCommand(parsedCommand: ParsedCommand) {
when (parsedCommand) {
is ParsedCommand.Invite -> {
//room.invite(parsedCommand.userId)
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
handleInviteSlashCommand(slashCommandResult)
}
else -> {
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
@ -118,6 +109,20 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
}
}
private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) {
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
room.invite(invite.userId, object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultOk))
}
override fun onFailure(failure: Throwable) {
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandResultError(failure)))
}
})
}
private fun handleEventDisplayed(action: RoomDetailActions.EventDisplayed) {
displayedEventsObservable.accept(action)
}

View file

@ -23,6 +23,8 @@ sealed class SendMessageResult {
class SlashCommandError(val command: Command) : SendMessageResult()
class SlashCommandUnknown(val command: String) : SendMessageResult()
object SlashCommandHandled : SendMessageResult()
object SlashCommandResultOk : SendMessageResult()
class SlashCommandResultError(val throwable: Throwable) : SendMessageResult()
// TODO Remove
object SlashCommandNotImplemented : SendMessageResult()
}