forked from GitHub-Mirror/riotX-android
Merge branch 'feature/invites' into develop
This commit is contained in:
@ -27,9 +27,8 @@ sealed class RoomDetailActions {
|
||||
object IsDisplayed : RoomDetailActions()
|
||||
data class EventDisplayed(val event: TimelineEvent) : RoomDetailActions()
|
||||
data class LoadMore(val direction: Timeline.Direction) : RoomDetailActions()
|
||||
|
||||
data class SendReaction(val reaction: String, val targetEventId: String) : RoomDetailActions()
|
||||
|
||||
|
||||
object AcceptInvite : RoomDetailActions()
|
||||
object RejectInvite : RoomDetailActions()
|
||||
|
||||
}
|
@ -53,7 +53,12 @@ import com.otaliastudios.autocomplete.Autocomplete
|
||||
import com.otaliastudios.autocomplete.AutocompleteCallback
|
||||
import com.otaliastudios.autocomplete.CharPolicy
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.message.*
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageFileContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageImageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent
|
||||
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
|
||||
@ -64,7 +69,15 @@ 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.*
|
||||
import im.vector.riotredesign.core.utils.LiveEvent
|
||||
import im.vector.riotredesign.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA
|
||||
import im.vector.riotredesign.core.utils.checkPermissions
|
||||
import im.vector.riotredesign.core.utils.copyToClipboard
|
||||
import im.vector.riotredesign.core.utils.openCamera
|
||||
import im.vector.riotredesign.core.utils.shareMedia
|
||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
||||
import im.vector.riotredesign.features.autocomplete.command.CommandAutocompletePolicy
|
||||
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
||||
@ -82,6 +95,7 @@ import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageM
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData
|
||||
import im.vector.riotredesign.features.html.PillImageSpan
|
||||
import im.vector.riotredesign.features.invite.VectorInviteView
|
||||
import im.vector.riotredesign.features.media.ImageContentRenderer
|
||||
import im.vector.riotredesign.features.media.ImageMediaViewerActivity
|
||||
import im.vector.riotredesign.features.media.VideoContentRenderer
|
||||
@ -112,7 +126,8 @@ private const val REACTION_SELECT_REQUEST_CODE = 2
|
||||
class RoomDetailFragment :
|
||||
VectorBaseFragment(),
|
||||
TimelineEventController.Callback,
|
||||
AutocompleteUserPresenter.Callback {
|
||||
AutocompleteUserPresenter.Callback,
|
||||
VectorInviteView.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
@ -169,6 +184,7 @@ class RoomDetailFragment :
|
||||
setupToolbar()
|
||||
setupComposer()
|
||||
setupAttachmentButton()
|
||||
setupInviteView()
|
||||
roomDetailViewModel.subscribe { renderState(it) }
|
||||
textComposerViewModel.subscribe { renderTextComposerState(it) }
|
||||
roomDetailViewModel.sendMessageResultLiveData.observeEvent(this) { renderSendMessageResult(it) }
|
||||
@ -183,11 +199,13 @@ class RoomDetailFragment :
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
when (requestCode) {
|
||||
REQUEST_FILES_REQUEST_CODE, TAKE_IMAGE_REQUEST_CODE -> handleMediaIntent(data)
|
||||
REACTION_SELECT_REQUEST_CODE -> {
|
||||
val eventId = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_EVENT_ID) ?: return
|
||||
val reaction = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_REACTION_RESULT) ?: return
|
||||
REACTION_SELECT_REQUEST_CODE -> {
|
||||
val eventId = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_EVENT_ID)
|
||||
?: return
|
||||
val reaction = data.getStringExtra(EmojiReactionPickerActivity.EXTRA_REACTION_RESULT)
|
||||
?: return
|
||||
//TODO check if already reacted with that?
|
||||
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction,eventId))
|
||||
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction, eventId))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -342,27 +360,31 @@ class RoomDetailFragment :
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupInviteView() {
|
||||
inviteView.callback = this
|
||||
}
|
||||
|
||||
private fun onSendChoiceClicked(dialogListItem: DialogListItem) {
|
||||
Timber.v("On send choice clicked: $dialogListItem")
|
||||
when (dialogListItem) {
|
||||
is DialogListItem.SendFile -> {
|
||||
is DialogListItem.SendFile -> {
|
||||
// launchFileIntent
|
||||
}
|
||||
is DialogListItem.SendVoice -> {
|
||||
is DialogListItem.SendVoice -> {
|
||||
//launchAudioRecorderIntent()
|
||||
}
|
||||
is DialogListItem.SendSticker -> {
|
||||
is DialogListItem.SendSticker -> {
|
||||
//startStickerPickerActivity()
|
||||
}
|
||||
is DialogListItem.TakePhotoVideo ->
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
// launchCamera()
|
||||
}
|
||||
is DialogListItem.TakePhoto ->
|
||||
is DialogListItem.TakePhoto ->
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA)) {
|
||||
openCamera(requireActivity(), CAMERA_VALUE_TITLE, TAKE_IMAGE_REQUEST_CODE)
|
||||
}
|
||||
is DialogListItem.TakeVideo ->
|
||||
is DialogListItem.TakeVideo ->
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA)) {
|
||||
// launchNativeVideoRecorder()
|
||||
}
|
||||
@ -376,7 +398,17 @@ class RoomDetailFragment :
|
||||
|
||||
private fun renderState(state: RoomDetailViewState) {
|
||||
renderRoomSummary(state)
|
||||
timelineEventController.setTimeline(state.timeline)
|
||||
val summary = state.asyncRoomSummary()
|
||||
val inviter = state.inviter()
|
||||
if (summary?.membership == Membership.JOIN) {
|
||||
timelineEventController.setTimeline(state.timeline)
|
||||
inviteView.visibility = View.GONE
|
||||
} else if (summary?.membership == Membership.INVITE && inviter != null) {
|
||||
inviteView.visibility = View.VISIBLE
|
||||
inviteView.render(inviter, VectorInviteView.Mode.LARGE)
|
||||
} else {
|
||||
//TODO : close the screen
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(state: RoomDetailViewState) {
|
||||
@ -399,20 +431,20 @@ class RoomDetailFragment :
|
||||
private fun renderSendMessageResult(sendMessageResult: SendMessageResult) {
|
||||
when (sendMessageResult) {
|
||||
is SendMessageResult.MessageSent,
|
||||
is SendMessageResult.SlashCommandHandled -> {
|
||||
is SendMessageResult.SlashCommandHandled -> {
|
||||
// Clear composer
|
||||
composerEditText.text = null
|
||||
}
|
||||
is SendMessageResult.SlashCommandError -> {
|
||||
is SendMessageResult.SlashCommandError -> {
|
||||
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
|
||||
}
|
||||
is SendMessageResult.SlashCommandUnknown -> {
|
||||
is SendMessageResult.SlashCommandUnknown -> {
|
||||
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
|
||||
}
|
||||
is SendMessageResult.SlashCommandResultOk -> {
|
||||
is SendMessageResult.SlashCommandResultOk -> {
|
||||
// Ignore
|
||||
}
|
||||
is SendMessageResult.SlashCommandResultError -> {
|
||||
is SendMessageResult.SlashCommandResultError -> {
|
||||
displayCommandError(sendMessageResult.throwable.localizedMessage)
|
||||
}
|
||||
is SendMessageResult.SlashCommandNotImplemented -> {
|
||||
@ -487,7 +519,7 @@ class RoomDetailFragment :
|
||||
override fun onClickOnReactionPill(informationData: MessageInformationData, reaction: String, on: Boolean) {
|
||||
if (on) {
|
||||
//we should test the current real state of reaction on this event
|
||||
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction,informationData.eventId))
|
||||
roomDetailViewModel.process(RoomDetailActions.SendReaction(reaction, informationData.eventId))
|
||||
} else {
|
||||
//TODO it's an undo :/
|
||||
}
|
||||
@ -503,18 +535,18 @@ class RoomDetailFragment :
|
||||
it?.getContentIfNotHandled()?.let { actionData ->
|
||||
|
||||
when (actionData.actionId) {
|
||||
MessageMenuViewModel.ACTION_ADD_REACTION -> {
|
||||
MessageMenuViewModel.ACTION_ADD_REACTION -> {
|
||||
val eventId = actionData.data?.toString() ?: return
|
||||
startActivityForResult(EmojiReactionPickerActivity.intent(requireContext(), eventId), REACTION_SELECT_REQUEST_CODE)
|
||||
}
|
||||
MessageMenuViewModel.ACTION_COPY -> {
|
||||
MessageMenuViewModel.ACTION_COPY -> {
|
||||
//I need info about the current selected message :/
|
||||
copyToClipboard(requireContext(), actionData.data?.toString() ?: "", false)
|
||||
val snack = Snackbar.make(view!!, requireContext().getString(R.string.copied_to_clipboard), Snackbar.LENGTH_SHORT)
|
||||
snack.view.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.notification_accent_color))
|
||||
snack.show()
|
||||
}
|
||||
MessageMenuViewModel.ACTION_SHARE -> {
|
||||
MessageMenuViewModel.ACTION_SHARE -> {
|
||||
//TODO current data communication is too limited
|
||||
//Need to now the media type
|
||||
actionData.data?.toString()?.let {
|
||||
@ -557,12 +589,12 @@ class RoomDetailFragment :
|
||||
.setPositiveButton(R.string.ok) { dialog, id -> dialog.cancel() }
|
||||
.show()
|
||||
}
|
||||
MessageMenuViewModel.ACTION_QUICK_REACT -> {
|
||||
MessageMenuViewModel.ACTION_QUICK_REACT -> {
|
||||
(actionData.data as? Pair<String, String>)?.let { pairData ->
|
||||
roomDetailViewModel.process(RoomDetailActions.SendReaction(pairData.second, pairData.first))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
else -> {
|
||||
Toast.makeText(context, "Action ${actionData.actionId} not implemented", Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
@ -615,4 +647,13 @@ class RoomDetailFragment :
|
||||
}
|
||||
}
|
||||
|
||||
// VectorInviteView.Callback
|
||||
|
||||
override fun onAcceptInvite() {
|
||||
roomDetailViewModel.process(RoomDetailActions.AcceptInvite)
|
||||
}
|
||||
|
||||
override fun onRejectInvite() {
|
||||
roomDetailViewModel.process(RoomDetailActions.RejectInvite)
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,13 @@ package im.vector.riotredesign.features.home.room.detail
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
@ -62,6 +64,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
init {
|
||||
observeRoomSummary()
|
||||
observeEventDisplayedActions()
|
||||
observeInvitationState()
|
||||
room.loadRoomMembersIfNeeded()
|
||||
timeline.start()
|
||||
setState { copy(timeline = this@RoomDetailViewModel.timeline) }
|
||||
@ -69,12 +72,14 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
|
||||
fun process(action: RoomDetailActions) {
|
||||
when (action) {
|
||||
is RoomDetailActions.SendMessage -> handleSendMessage(action)
|
||||
is RoomDetailActions.IsDisplayed -> handleIsDisplayed()
|
||||
is RoomDetailActions.SendMedia -> handleSendMedia(action)
|
||||
is RoomDetailActions.SendMessage -> handleSendMessage(action)
|
||||
is RoomDetailActions.IsDisplayed -> handleIsDisplayed()
|
||||
is RoomDetailActions.SendMedia -> handleSendMedia(action)
|
||||
is RoomDetailActions.EventDisplayed -> handleEventDisplayed(action)
|
||||
is RoomDetailActions.LoadMore -> handleLoadMore(action)
|
||||
is RoomDetailActions.SendReaction -> handleSendReaction(action)
|
||||
is RoomDetailActions.LoadMore -> handleLoadMore(action)
|
||||
is RoomDetailActions.SendReaction -> handleSendReaction(action)
|
||||
is RoomDetailActions.AcceptInvite -> handleAcceptInvite()
|
||||
is RoomDetailActions.RejectInvite -> handleRejectInvite()
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,63 +94,63 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
val slashCommandResult = CommandParser.parseSplashCommand(action.text)
|
||||
|
||||
when (slashCommandResult) {
|
||||
is ParsedCommand.ErrorNotACommand -> {
|
||||
is ParsedCommand.ErrorNotACommand -> {
|
||||
// Send the text message to the room
|
||||
room.sendTextMessage(action.text)
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent))
|
||||
}
|
||||
is ParsedCommand.ErrorSyntax -> {
|
||||
is ParsedCommand.ErrorSyntax -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandError(slashCommandResult.command)))
|
||||
}
|
||||
is ParsedCommand.ErrorEmptySlashCommand -> {
|
||||
is ParsedCommand.ErrorEmptySlashCommand -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown("/")))
|
||||
}
|
||||
is ParsedCommand.ErrorUnknownSlashCommand -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand)))
|
||||
}
|
||||
is ParsedCommand.Invite -> {
|
||||
is ParsedCommand.Invite -> {
|
||||
handleInviteSlashCommand(slashCommandResult)
|
||||
}
|
||||
is ParsedCommand.SetUserPowerLevel -> {
|
||||
is ParsedCommand.SetUserPowerLevel -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.ClearScalarToken -> {
|
||||
is ParsedCommand.ClearScalarToken -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.SetMarkdown -> {
|
||||
is ParsedCommand.SetMarkdown -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.UnbanUser -> {
|
||||
is ParsedCommand.UnbanUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.BanUser -> {
|
||||
is ParsedCommand.BanUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.KickUser -> {
|
||||
is ParsedCommand.KickUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.JoinRoom -> {
|
||||
is ParsedCommand.JoinRoom -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.PartRoom -> {
|
||||
is ParsedCommand.PartRoom -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.SendEmote -> {
|
||||
is ParsedCommand.SendEmote -> {
|
||||
room.sendTextMessage(slashCommandResult.message, msgType = MessageType.MSGTYPE_EMOTE)
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
|
||||
}
|
||||
is ParsedCommand.ChangeTopic -> {
|
||||
is ParsedCommand.ChangeTopic -> {
|
||||
handleChangeTopicSlashCommand(slashCommandResult)
|
||||
}
|
||||
is ParsedCommand.ChangeDisplayName -> {
|
||||
is ParsedCommand.ChangeDisplayName -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
@ -182,7 +187,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
|
||||
|
||||
private fun handleSendReaction(action: RoomDetailActions.SendReaction) {
|
||||
room.sendReaction(action.reaction,action.targetEventId)
|
||||
room.sendReaction(action.reaction, action.targetEventId)
|
||||
}
|
||||
|
||||
private fun handleSendMedia(action: RoomDetailActions.SendMedia) {
|
||||
@ -214,6 +219,14 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
timeline.paginate(action.direction, PAGINATION_COUNT)
|
||||
}
|
||||
|
||||
private fun handleRejectInvite() {
|
||||
room.leave(object : MatrixCallback<Unit> {})
|
||||
}
|
||||
|
||||
private fun handleAcceptInvite() {
|
||||
room.join(object : MatrixCallback<Unit> {})
|
||||
}
|
||||
|
||||
private fun observeEventDisplayedActions() {
|
||||
// We are buffering scroll events for one second
|
||||
// and keep the most recent one to set the read receipt on.
|
||||
@ -236,6 +249,18 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeInvitationState() {
|
||||
asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary ->
|
||||
if (summary.membership == Membership.INVITE) {
|
||||
summary.lastMessage?.sender?.let { senderId ->
|
||||
session.getUser(senderId)
|
||||
}?.also {
|
||||
setState { copy(inviter = Success(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
timeline.dispose()
|
||||
super.onCleared()
|
||||
|
@ -22,11 +22,13 @@ import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
|
||||
data class RoomDetailViewState(
|
||||
val roomId: String,
|
||||
val eventId: String?,
|
||||
val timeline: Timeline? = null,
|
||||
val inviter: Async<User> = Uninitialized,
|
||||
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val asyncTimelineData: Async<TimelineData> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
@ -24,6 +24,7 @@ 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.group.model.GroupSummary
|
||||
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.matrix.rx.rx
|
||||
@ -153,6 +154,7 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||
}
|
||||
|
||||
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
||||
val invites = ArrayList<RoomSummary>()
|
||||
val favourites = ArrayList<RoomSummary>()
|
||||
val directChats = ArrayList<RoomSummary>()
|
||||
val groupRooms = ArrayList<RoomSummary>()
|
||||
@ -160,8 +162,10 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||
val serverNotices = ArrayList<RoomSummary>()
|
||||
|
||||
for (room in rooms) {
|
||||
if (room.membership.isLeft()) continue
|
||||
val tags = room.tags.map { it.name }
|
||||
when {
|
||||
room.membership == Membership.INVITE -> invites.add(room)
|
||||
tags.contains(RoomTag.ROOM_TAG_SERVER_NOTICE) -> serverNotices.add(room)
|
||||
tags.contains(RoomTag.ROOM_TAG_FAVOURITE) -> favourites.add(room)
|
||||
tags.contains(RoomTag.ROOM_TAG_LOW_PRIORITY) -> lowPriorities.add(room)
|
||||
@ -171,6 +175,7 @@ class RoomListViewModel(initialState: RoomListViewState,
|
||||
}
|
||||
|
||||
return RoomSummaries().apply {
|
||||
put(RoomCategory.INVITE, invites.sortedWith(roomSummaryComparator))
|
||||
put(RoomCategory.FAVOURITE, favourites.sortedWith(roomSummaryComparator))
|
||||
put(RoomCategory.DIRECT, directChats.sortedWith(roomSummaryComparator))
|
||||
put(RoomCategory.GROUP, groupRooms.sortedWith(roomSummaryComparator))
|
||||
|
@ -26,15 +26,17 @@ import im.vector.riotredesign.R
|
||||
data class RoomListViewState(
|
||||
val asyncRooms: Async<RoomSummaries> = Uninitialized,
|
||||
val visibleRoomId: String? = null,
|
||||
val isInviteExpanded: Boolean = true,
|
||||
val isFavouriteRoomsExpanded: Boolean = true,
|
||||
val isDirectRoomsExpanded: Boolean = false,
|
||||
val isGroupRoomsExpanded: Boolean = false,
|
||||
val isLowPriorityRoomsExpanded: Boolean = false,
|
||||
val isServerNoticeRoomsExpanded: Boolean = false
|
||||
val isDirectRoomsExpanded: Boolean = true,
|
||||
val isGroupRoomsExpanded: Boolean = true,
|
||||
val isLowPriorityRoomsExpanded: Boolean = true,
|
||||
val isServerNoticeRoomsExpanded: Boolean = true
|
||||
) : MvRxState {
|
||||
|
||||
fun isCategoryExpanded(roomCategory: RoomCategory): Boolean {
|
||||
return when (roomCategory) {
|
||||
RoomCategory.INVITE -> isInviteExpanded
|
||||
RoomCategory.FAVOURITE -> isFavouriteRoomsExpanded
|
||||
RoomCategory.DIRECT -> isDirectRoomsExpanded
|
||||
RoomCategory.GROUP -> isGroupRoomsExpanded
|
||||
@ -45,6 +47,7 @@ data class RoomListViewState(
|
||||
|
||||
fun toggle(roomCategory: RoomCategory): RoomListViewState {
|
||||
return when (roomCategory) {
|
||||
RoomCategory.INVITE -> copy(isInviteExpanded = !isInviteExpanded)
|
||||
RoomCategory.FAVOURITE -> copy(isFavouriteRoomsExpanded = !isFavouriteRoomsExpanded)
|
||||
RoomCategory.DIRECT -> copy(isDirectRoomsExpanded = !isDirectRoomsExpanded)
|
||||
RoomCategory.GROUP -> copy(isGroupRoomsExpanded = !isGroupRoomsExpanded)
|
||||
@ -57,6 +60,7 @@ data class RoomListViewState(
|
||||
typealias RoomSummaries = LinkedHashMap<RoomCategory, List<RoomSummary>>
|
||||
|
||||
enum class RoomCategory(@StringRes val titleRes: Int) {
|
||||
INVITE(R.string.invitations_header),
|
||||
FAVOURITE(R.string.bottom_action_favourites),
|
||||
DIRECT(R.string.bottom_action_people),
|
||||
GROUP(R.string.bottom_action_rooms),
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.invite
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
import kotlinx.android.synthetic.main.vector_invite_view.view.*
|
||||
|
||||
class VectorInviteView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
|
||||
: ConstraintLayout(context, attrs, defStyle) {
|
||||
|
||||
interface Callback {
|
||||
fun onAcceptInvite()
|
||||
fun onRejectInvite()
|
||||
}
|
||||
|
||||
enum class Mode {
|
||||
LARGE,
|
||||
SMALL
|
||||
}
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.vector_invite_view, this)
|
||||
setBackgroundColor(Color.WHITE)
|
||||
inviteRejectView.setOnClickListener { callback?.onRejectInvite() }
|
||||
inviteAcceptView.setOnClickListener { callback?.onAcceptInvite() }
|
||||
}
|
||||
|
||||
fun render(sender: User, mode: Mode = Mode.LARGE) {
|
||||
if (mode == Mode.LARGE) {
|
||||
updateLayoutParams { height = ConstraintLayout.LayoutParams.MATCH_CONSTRAINT }
|
||||
AvatarRenderer.render(sender.avatarUrl, sender.userId, sender.displayName, inviteAvatarView)
|
||||
inviteIdentifierView.text = sender.userId
|
||||
inviteNameView.text = sender.displayName
|
||||
inviteLabelView.text = context.getString(R.string.send_you_invite)
|
||||
} else {
|
||||
updateLayoutParams { height = ConstraintLayout.LayoutParams.WRAP_CONTENT }
|
||||
inviteAvatarView.visibility = View.GONE
|
||||
inviteIdentifierView.visibility = View.GONE
|
||||
inviteNameView.visibility = View.GONE
|
||||
inviteLabelView.text = context.getString(R.string.invited_by, sender.userId)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user