diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt index 9d2edd74..339b435b 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/RoomDataHelper.kt @@ -22,7 +22,6 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toContent import im.vector.matrix.android.api.session.room.model.Membership -import im.vector.matrix.android.api.session.room.model.MyMembership import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.model.message.MessageTextContent import im.vector.matrix.android.api.session.room.model.message.MessageType @@ -78,7 +77,7 @@ object RoomDataHelper { fun fakeInitialSync(monarchy: Monarchy, roomId: String) { monarchy.runTransactionSync { realm -> val roomEntity = realm.createObject(roomId) - roomEntity.membership = MyMembership.JOINED + roomEntity.membership = Membership.JOIN val eventList = createFakeListOfEvents(10) val chunkEntity = realm.createObject().apply { nextToken = null diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt index 3f7d27e3..ba1095f5 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/TimelineTest.kt @@ -21,7 +21,7 @@ import im.vector.matrix.android.InstrumentedTest import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.session.room.EventRelationExtractor -import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor +import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt index c2e69d33..2061a296 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/Room.kt @@ -17,7 +17,7 @@ package im.vector.matrix.android.api.session.room import androidx.lifecycle.LiveData -import im.vector.matrix.android.api.session.room.members.RoomMembersService +import im.vector.matrix.android.api.session.room.members.MembershipService 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 @@ -27,7 +27,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineService /** * This interface defines methods to interact within a room. */ -interface Room : TimelineService, SendService, ReadService, RoomMembersService, StateService { +interface Room : TimelineService, SendService, ReadService, MembershipService, StateService { /** * The roomId of this room diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt similarity index 84% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt index 930afd7a..59054dc1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/RoomMembersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/members/MembershipService.kt @@ -24,9 +24,9 @@ import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.util.Cancelable /** - * This interface defines methods to retrieve room members of a room. It's implemented at the room level. + * This interface defines methods to handling membership. It's implemented at the room level. */ -interface RoomMembersService { +interface MembershipService { /** * This methods load all room members if it was done yet. @@ -54,4 +54,15 @@ interface RoomMembersService { */ fun invite(userId: String, callback: MatrixCallback) + /** + * Join the room + */ + fun join(callback: MatrixCallback) + + /** + * Leave the room. + * + */ + fun leave(callback: MatrixCallback) + } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt index 09d7a7de..d87bb9b3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/Membership.kt @@ -19,10 +19,12 @@ package im.vector.matrix.android.api.session.room.model import com.squareup.moshi.Json /** - * Represents the membership of a user on a room. Linked to a [RoomMember] + * Represents the membership of a user on a room */ enum class Membership(val value: String) { + NONE("none"), + @Json(name = "invite") INVITE("invite"), @@ -38,4 +40,8 @@ enum class Membership(val value: String) { @Json(name = "ban") BAN("ban"); + fun isLeft(): Boolean { + return this == KNOCK || this == LEAVE || this == BAN + } + } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/MyMembership.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/MyMembership.kt deleted file mode 100644 index cd9c3932..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/MyMembership.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.api.session.room.model - -/** - * Represents the membership of the current auth user on a room. - */ -enum class MyMembership { - JOINED, - LEFT, - INVITED, - NONE -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt index 429d7882..f6de3589 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/RoomSummary.kt @@ -31,7 +31,8 @@ data class RoomSummary( val isDirect: Boolean = false, val lastMessage: Event? = null, val otherMemberIds: List = emptyList(), - var notificationCount: Int = 0, - var highlightCount: Int = 0, - var tags: List = emptyList() + val notificationCount: Int = 0, + val highlightCount: Int = 0, + val tags: List = emptyList(), + val membership: Membership = Membership.NONE ) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt index 28470455..e666d2de 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt @@ -86,10 +86,9 @@ internal fun ChunkEntity.add(roomId: String, isUnlinked: Boolean = false) { assertIsManaged() - if (event.eventId.isNullOrEmpty() || this.events.fastContains(event.eventId)) { + if (event.eventId != null && events.fastContains(event.eventId)) { return } - var currentDisplayIndex = lastDisplayIndex(direction, 0) if (direction == PaginationDirection.FORWARDS) { currentDisplayIndex += 1 diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt index 0d6405f8..3c21437e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/EventMapper.kt @@ -20,7 +20,7 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.UnsignedData import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.di.MoshiProvider - +import java.util.* internal object EventMapper { @@ -29,7 +29,7 @@ internal object EventMapper { val uds = if (event.unsignedData == null) null else MoshiProvider.providesMoshi().adapter(UnsignedData::class.java).toJson(event.unsignedData) val eventEntity = EventEntity() - eventEntity.eventId = event.eventId ?: "" + eventEntity.eventId = event.eventId ?: UUID.randomUUID().toString() eventEntity.roomId = event.roomId ?: roomId eventEntity.content = ContentMapper.map(event.content) val resolvedPrevContent = event.prevContent ?: event.unsignedData?.prevContent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt index 9243d1de..03035128 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/RoomSummaryMapper.kt @@ -37,7 +37,8 @@ internal object RoomSummaryMapper { otherMemberIds = roomSummaryEntity.otherMemberIds.toList(), highlightCount = roomSummaryEntity.highlightCount, notificationCount = roomSummaryEntity.notificationCount, - tags = tags + tags = tags, + membership = roomSummaryEntity.membership ) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt index 3c35bf7d..35733d5f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.database.model -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmObject import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey @@ -26,10 +26,10 @@ internal open class GroupEntity(@PrimaryKey var groupId: String = "" ) : RealmObject() { - private var membershipStr: String = MyMembership.NONE.name + private var membershipStr: String = Membership.NONE.name @delegate:Ignore - var membership: MyMembership by Delegates.observable(MyMembership.valueOf(membershipStr)) { _, _, newValue -> + var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue -> membershipStr = newValue.name } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt index 6c61d0de..2341e492 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomEntity.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.database.model -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.Ignore @@ -30,10 +30,10 @@ internal open class RoomEntity(@PrimaryKey var roomId: String = "", var areAllMembersLoaded: Boolean = false ) : RealmObject() { - private var membershipStr: String = MyMembership.NONE.name + private var membershipStr: String = Membership.NONE.name @delegate:Ignore - var membership: MyMembership by Delegates.observable(MyMembership.valueOf(membershipStr)) { _, _, newValue -> + var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue -> membershipStr = newValue.name } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt index 9f9c66f0..32f27adb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/RoomSummaryEntity.kt @@ -16,9 +16,12 @@ package im.vector.matrix.android.internal.database.model +import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmList import io.realm.RealmObject +import io.realm.annotations.Ignore import io.realm.annotations.PrimaryKey +import kotlin.properties.Delegates internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var displayName: String? = "", @@ -35,6 +38,13 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "", var tags: RealmList = RealmList() ) : RealmObject() { + private var membershipStr: String = Membership.NONE.name + + @delegate:Ignore + var membership: Membership by Delegates.observable(Membership.valueOf(membershipStr)) { _, _, newValue -> + membershipStr = newValue.name + } + companion object } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt index 692ecc1d..3d27a56b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.database.query -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.model.GroupEntityFields import io.realm.Realm @@ -27,7 +27,7 @@ internal fun GroupEntity.Companion.where(realm: Realm, roomId: String): RealmQue return realm.where().equalTo(GroupEntityFields.GROUP_ID, roomId) } -internal fun GroupEntity.Companion.where(realm: Realm, membership: MyMembership? = null): RealmQuery { +internal fun GroupEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery { val query = realm.where() if (membership != null) { query.equalTo(GroupEntityFields.MEMBERSHIP_STR, membership.name) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomEntityQueries.kt index 211421ef..031cb93e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/RoomEntityQueries.kt @@ -16,7 +16,7 @@ package im.vector.matrix.android.internal.database.query -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.RoomEntityFields @@ -28,7 +28,7 @@ internal fun RoomEntity.Companion.where(realm: Realm, roomId: String): RealmQuer return realm.where().equalTo(RoomEntityFields.ROOM_ID, roomId) } -internal fun RoomEntity.Companion.where(realm: Realm, membership: MyMembership? = null): RealmQuery { +internal fun RoomEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery { val query = realm.where() if (membership != null) { query.equalTo(RoomEntityFields.MEMBERSHIP_STR, membership.name) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 9ae7351c..b9889b73 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -37,8 +37,8 @@ import im.vector.matrix.android.internal.session.room.DefaultRoomService import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater import im.vector.matrix.android.internal.session.room.RoomAvatarResolver import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater -import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver -import im.vector.matrix.android.internal.session.room.members.RoomMemberDisplayNameResolver +import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver +import im.vector.matrix.android.internal.session.room.membership.RoomMemberDisplayNameResolver import im.vector.matrix.android.internal.session.room.prune.EventsPruner import im.vector.matrix.android.internal.session.signout.DefaultSignOutService import im.vector.matrix.android.internal.session.user.DefaultUserService diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt index 6c2ab00f..c767e5c6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt @@ -20,7 +20,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.room.Room -import im.vector.matrix.android.api.session.room.members.RoomMembersService +import im.vector.matrix.android.api.session.room.members.MembershipService 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 @@ -39,13 +39,13 @@ internal class DefaultRoom( private val sendService: SendService, private val stateService: StateService, private val readService: ReadService, - private val roomMembersService: RoomMembersService + private val roomMembersService: MembershipService ) : Room, - TimelineService by timelineService, - SendService by sendService, - StateService by stateService, - ReadService by readService, - RoomMembersService by roomMembersService { + TimelineService by timelineService, + SendService by sendService, + StateService by stateService, + ReadService by readService, + MembershipService by roomMembersService { override val roomSummary: LiveData by lazy { val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm -> diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt index e24a6e06..23e74c74 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAPI.kt @@ -18,17 +18,21 @@ package im.vector.matrix.android.internal.session.room import im.vector.matrix.android.api.session.events.model.Content import im.vector.matrix.android.api.session.events.model.Event -import im.vector.matrix.android.api.session.room.model.annotation.ReactionContent 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.membership.RoomMembersResponse +import im.vector.matrix.android.internal.session.room.membership.joining.InviteBody import im.vector.matrix.android.internal.session.room.send.SendResponse import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse import retrofit2.Call -import retrofit2.http.* +import retrofit2.http.Body +import retrofit2.http.GET +import retrofit2.http.POST +import retrofit2.http.PUT +import retrofit2.http.Path +import retrofit2.http.Query internal interface RoomAPI { @@ -173,4 +177,24 @@ internal interface RoomAPI { @Path("eventType") eventType: String, @Body content: Content? ): Call + + /** + * Join the given room. + * + * @param roomId the room id + * @param params the request body + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/join") + fun join(@Path("roomId") roomId: String, + @Body params: Map): Call + + /** + * Leave the given room. + * + * @param roomId the room id + * @param params the request body + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/leave") + fun leave(@Path("roomId") roomId: String, + @Body params: Map): Call } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt index c6786508..c26f0596 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt @@ -20,14 +20,14 @@ import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomAvatarContent import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.session.room.members.RoomMembers +import im.vector.matrix.android.internal.session.room.membership.RoomMembers internal class RoomAvatarResolver(private val monarchy: Monarchy, private val credentials: Credentials) { @@ -48,7 +48,7 @@ internal class RoomAvatarResolver(private val monarchy: Monarchy, } val roomMembers = RoomMembers(realm, roomId) val members = roomMembers.getLoaded() - if (roomEntity?.membership == MyMembership.INVITED) { + if (roomEntity?.membership == Membership.INVITE) { if (members.size == 1) { res = members.entries.first().value.avatarUrl } else if (members.size > 1) { @@ -57,9 +57,9 @@ internal class RoomAvatarResolver(private val monarchy: Monarchy, } } else { // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) - if (roomMembers.getNumberOfJoinedMembers() == 1 && members.isNotEmpty()) { + if (members.size == 1) { res = members.entries.first().value.avatarUrl - } else if (roomMembers.getNumberOfMembers() == 2 && members.size > 1) { + } else if (members.size == 2) { val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull() res = firstOtherMember?.avatarUrl } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt index 7bf9d964..78d8ae8c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt @@ -18,10 +18,12 @@ 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.SenderRoomMemberExtractor +import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService +import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask +import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor +import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask +import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask +import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask import im.vector.matrix.android.internal.session.room.read.DefaultReadService import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask import im.vector.matrix.android.internal.session.room.send.DefaultSendService @@ -34,24 +36,26 @@ import im.vector.matrix.android.internal.session.room.timeline.PaginationTask import im.vector.matrix.android.internal.session.room.timeline.TimelineEventFactory import im.vector.matrix.android.internal.task.TaskExecutor -internal class RoomFactory(private val loadRoomMembersTask: LoadRoomMembersTask, +internal class RoomFactory(private val monarchy: Monarchy, + private val eventFactory: LocalEchoEventFactory, + private val taskExecutor: TaskExecutor, + private val loadRoomMembersTask: LoadRoomMembersTask, private val inviteTask: InviteTask, private val sendStateTask: SendStateTask, - private val monarchy: Monarchy, private val paginationTask: PaginationTask, private val contextOfEventTask: GetContextOfEventTask, private val setReadMarkersTask: SetReadMarkersTask, - private val eventFactory: LocalEchoEventFactory, - private val taskExecutor: TaskExecutor) { + private val joinRoomTask: JoinRoomTask, + private val leaveRoomTask: LeaveRoomTask) { fun instantiate(roomId: String): Room { val roomMemberExtractor = SenderRoomMemberExtractor(roomId) val timelineEventFactory = TimelineEventFactory(roomMemberExtractor, EventRelationExtractor()) - val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, contextOfEventTask, timelineEventFactory, paginationTask) + val timelineService = DefaultTimelineService(roomId, monarchy, taskExecutor, timelineEventFactory, contextOfEventTask, paginationTask) val sendService = DefaultSendService(roomId, eventFactory, monarchy) - val stateService = DefaultStateService(roomId, sendStateTask, taskExecutor) - val roomMembersService = DefaultRoomMembersService(roomId, monarchy, loadRoomMembersTask, inviteTask, taskExecutor) - val readService = DefaultReadService(roomId, monarchy, setReadMarkersTask, taskExecutor) + val stateService = DefaultStateService(roomId, taskExecutor, sendStateTask) + val roomMembersService = DefaultMembershipService(roomId, monarchy, taskExecutor, loadRoomMembersTask, inviteTask, joinRoomTask, leaveRoomTask) + val readService = DefaultReadService(roomId, monarchy, taskExecutor, setReadMarkersTask) return DefaultRoom( roomId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index 07e8c6c1..a7fa3f4c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -19,10 +19,14 @@ 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.membership.DefaultLoadRoomMembersTask +import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask +import im.vector.matrix.android.internal.session.room.membership.joining.DefaultInviteTask +import im.vector.matrix.android.internal.session.room.membership.joining.DefaultJoinRoomTask +import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask +import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask +import im.vector.matrix.android.internal.session.room.membership.leaving.DefaultLeaveRoomTask +import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask import im.vector.matrix.android.internal.session.room.read.DefaultSetReadMarkersTask import im.vector.matrix.android.internal.session.room.read.SetReadMarkersTask import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory @@ -71,7 +75,7 @@ class RoomModule { } scope(DefaultSession.SCOPE) { - RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get()) + RoomFactory(get(), get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) } scope(DefaultSession.SCOPE) { @@ -82,6 +86,14 @@ class RoomModule { DefaultInviteTask(get()) as InviteTask } + scope(DefaultSession.SCOPE) { + DefaultJoinRoomTask(get()) as JoinRoomTask + } + + scope(DefaultSession.SCOPE) { + DefaultLeaveRoomTask(get()) as LeaveRoomTask + } + scope(DefaultSession.SCOPE) { DefaultSendStateTask(get()) as SendStateTask } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt index c8ed0ee9..7bf08b70 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt @@ -21,6 +21,7 @@ package im.vector.matrix.android.internal.session.room import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomTopicContent import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity @@ -28,8 +29,8 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver -import im.vector.matrix.android.internal.session.room.members.RoomMembers +import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver +import im.vector.matrix.android.internal.session.room.membership.RoomMembers import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications import io.realm.Realm @@ -41,11 +42,12 @@ internal class RoomSummaryUpdater(private val credentials: Credentials, fun update(realm: Realm, roomId: String, + membership: Membership? = null, roomSummary: RoomSyncSummary? = null, unreadNotifications: RoomSyncUnreadNotifications? = null) { val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) if (roomSummary != null) { if (roomSummary.heroes.isNotEmpty()) { @@ -65,8 +67,11 @@ internal class RoomSummaryUpdater(private val credentials: Credentials, if (unreadNotifications?.notificationCount != null) { roomSummaryEntity.notificationCount = unreadNotifications.notificationCount } + if (membership != null) { + roomSummaryEntity.membership = membership + } - val lastEvent = EventEntity.latestEvent(realm, roomId, includedTypes = listOf(EventType.MESSAGE)) + val lastEvent = EventEntity.latestEvent(realm, roomId) val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain() val otherRoomMembers = RoomMembers(realm, roomId).getLoaded().filterKeys { it != credentials.userId } roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt similarity index 61% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt index a007a1eb..a9b48ea6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/DefaultRoomMembersService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/DefaultMembershipService.kt @@ -16,28 +16,32 @@ * */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership 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.members.MembershipService 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.session.room.membership.joining.InviteTask +import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask +import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith 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 { +internal class DefaultMembershipService(private val roomId: String, + private val monarchy: Monarchy, + private val taskExecutor: TaskExecutor, + private val loadRoomMembersTask: LoadRoomMembersTask, + private val inviteTask: InviteTask, + private val joinTask: JoinRoomTask, + private val leaveRoomTask: LeaveRoomTask +) : MembershipService { override fun loadRoomMembersIfNeeded(): Cancelable { val params = LoadRoomMembersTask.Params(roomId, Membership.LEAVE) @@ -68,4 +72,18 @@ internal class DefaultRoomMembersService(private val roomId: String, .dispatchTo(callback) .executeBy(taskExecutor) } + + override fun join(callback: MatrixCallback) { + val params = JoinRoomTask.Params(roomId) + joinTask.configureWith(params) + .dispatchTo(callback) + .executeBy(taskExecutor) + } + + override fun leave(callback: MatrixCallback) { + val params = LeaveRoomTask.Params(roomId) + leaveRoomTask.configureWith(params) + .dispatchTo(callback) + .executeBy(taskExecutor) + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt similarity index 98% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersTask.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt index c421b3bd..4a243676 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/LoadRoomMembersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership import arrow.core.Try import com.zhuinden.monarchy.Monarchy diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt similarity index 85% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt index 7f19762c..605de81a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership import android.content.Context import com.zhuinden.monarchy.Monarchy @@ -22,7 +22,7 @@ import im.vector.matrix.android.R import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomAliasesContent import im.vector.matrix.android.api.session.room.model.RoomCanonicalAliasContent import im.vector.matrix.android.api.session.room.model.RoomNameContent @@ -77,24 +77,17 @@ internal class RoomDisplayNameResolver(private val context: Context, } val roomMembers = RoomMembers(realm, roomId) - val otherRoomMembers = roomMembers.getLoaded() - .filterKeys { it != credentials.userId } - - if (roomEntity?.membership == MyMembership.INVITED) { - //TODO handle invited - /* - if (currentUser != null - && !othersActiveMembers.isEmpty() - && !TextUtils.isEmpty(currentUser!!.mSender)) { - // extract who invited us to the room - name = context.getString(R.string.room_displayname_invite_from, roomState.resolve(currentUser!!.mSender)) + val loadedMembers = roomMembers.getLoaded() + val otherRoomMembers = loadedMembers.filterKeys { it != credentials.userId } + if (roomEntity?.membership == Membership.INVITE) { + val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst() + val inviterId = inviteMeEvent?.sender + name = if (inviterId != null && otherRoomMembers.containsKey(inviterId)) { + roomMemberDisplayNameResolver.resolve(inviterId, otherRoomMembers) } else { - name = context.getString(R.string.room_displayname_room_invite) + context.getString(R.string.room_displayname_room_invite) } - */ - name = context.getString(R.string.room_displayname_room_invite) } else { - val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() val memberIds = if (roomSummary?.heroes?.isNotEmpty() == true) { roomSummary.heroes diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMemberDisplayNameResolver.kt similarity index 96% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberDisplayNameResolver.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMemberDisplayNameResolver.kt index fb17872d..97435bd4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMemberDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMemberDisplayNameResolver.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership import im.vector.matrix.android.api.session.room.model.RoomMember diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt similarity index 98% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt index 40266cb7..7ea158d1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembersResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt similarity index 92% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembersResponse.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt index 26bd759a..af3bf9b6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomMembersResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembersResponse.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/SenderRoomMemberExtractor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt similarity index 97% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/SenderRoomMemberExtractor.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt index de2d3de0..c8944bac 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/SenderRoomMemberExtractor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.members +package im.vector.matrix.android.internal.session.room.membership import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteBody.kt similarity index 85% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteBody.kt index 652f8d63..4529a17a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteBody.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteBody.kt @@ -5,7 +5,7 @@ * 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 + * 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, @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.invite +package im.vector.matrix.android.internal.session.room.membership.joining import com.squareup.moshi.Json import com.squareup.moshi.JsonClass diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt similarity index 94% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt index 1086c6b5..d94b106e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/invite/InviteTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/InviteTask.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room.invite +package im.vector.matrix.android.internal.session.room.membership.joining import arrow.core.Try import im.vector.matrix.android.internal.network.executeRequest diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt new file mode 100644 index 00000000..be2befa0 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/joining/JoinRoomTask.kt @@ -0,0 +1,38 @@ +/* + * 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.membership.joining + +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 JoinRoomTask : Task { + data class Params( + val roomId: String + ) +} + +internal class DefaultJoinRoomTask(private val roomAPI: RoomAPI) : JoinRoomTask { + + override fun execute(params: JoinRoomTask.Params): Try { + return executeRequest { + apiCall = roomAPI.join(params.roomId, HashMap()) + } + } + +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt new file mode 100644 index 00000000..b7d53b51 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/leaving/LeaveRoomTask.kt @@ -0,0 +1,38 @@ +/* + * 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.membership.leaving + +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 LeaveRoomTask : Task { + data class Params( + val roomId: String + ) +} + +internal class DefaultLeaveRoomTask(private val roomAPI: RoomAPI) : LeaveRoomTask { + + override fun execute(params: LeaveRoomTask.Params): Try { + return executeRequest { + apiCall = roomAPI.leave(params.roomId, HashMap()) + } + } + +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt index e1ca59e5..30bbe30c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt @@ -27,8 +27,8 @@ import im.vector.matrix.android.internal.util.fetchCopied internal class DefaultReadService(private val roomId: String, private val monarchy: Monarchy, - private val setReadMarkersTask: SetReadMarkersTask, - private val taskExecutor: TaskExecutor) : ReadService { + private val taskExecutor: TaskExecutor, + private val setReadMarkersTask: SetReadMarkersTask) : ReadService { override fun markAllAsRead(callback: MatrixCallback) { val latestEvent = getLatestEvent() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt index b471bf19..f1ad712e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/state/DefaultStateService.kt @@ -23,8 +23,8 @@ import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith internal class DefaultStateService(private val roomId: String, - private val sendStateTask: SendStateTask, - private val taskExecutor: TaskExecutor) : StateService { + private val taskExecutor: TaskExecutor, + private val sendStateTask: SendStateTask) : StateService { override fun updateTopic(topic: String, callback: MatrixCallback) { val params = SendStateTask.Params(roomId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt index 8b949721..c8629ecc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimelineService.kt @@ -28,8 +28,8 @@ import im.vector.matrix.android.internal.util.fetchCopyMap internal class DefaultTimelineService(private val roomId: String, private val monarchy: Monarchy, private val taskExecutor: TaskExecutor, - private val contextOfEventTask: GetContextOfEventTask, private val timelineEventFactory: TimelineEventFactory, + private val contextOfEventTask: GetContextOfEventTask, private val paginationTask: PaginationTask ) : TimelineService { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt index 8fd15c18..910bb79a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventFactory.kt @@ -20,7 +20,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.session.room.EventRelationExtractor -import im.vector.matrix.android.internal.session.room.members.SenderRoomMemberExtractor +import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor import io.realm.Realm internal class TimelineEventFactory( diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt index eb985759..25bea096 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt @@ -17,7 +17,7 @@ package im.vector.matrix.android.internal.session.sync import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.model.GroupEntity import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.session.sync.model.GroupsSyncResponse @@ -56,7 +56,7 @@ internal class GroupSyncHandler(private val monarchy: Monarchy) { groupId: String): GroupEntity { val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) - groupEntity.membership = MyMembership.JOINED + groupEntity.membership = Membership.JOIN return groupEntity } @@ -64,7 +64,7 @@ internal class GroupSyncHandler(private val monarchy: Monarchy) { groupId: String): GroupEntity { val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) - groupEntity.membership = MyMembership.INVITED + groupEntity.membership = Membership.INVITE return groupEntity } @@ -74,7 +74,7 @@ internal class GroupSyncHandler(private val monarchy: Monarchy) { groupId: String): GroupEntity { val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) - groupEntity.membership = MyMembership.LEFT + groupEntity.membership = Membership.LEAVE return groupEntity } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt index d5ec714c..eaab9846 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt @@ -20,7 +20,7 @@ import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.MyMembership +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent import im.vector.matrix.android.internal.database.helper.addAll import im.vector.matrix.android.internal.database.helper.addOrUpdate @@ -69,7 +69,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, val rooms = when (handlingStrategy) { is HandlingStrategy.JOINED -> handlingStrategy.data.map { handleJoinedRoom(realm, it.key, it.value) } is HandlingStrategy.INVITED -> handlingStrategy.data.map { handleInvitedRoom(realm, it.key, it.value) } - is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(it.key, it.value) } + is HandlingStrategy.LEFT -> handlingStrategy.data.map { handleLeftRoom(realm, it.key, it.value) } } realm.insertOrUpdate(rooms) } @@ -83,11 +83,10 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, val roomEntity = RoomEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId) - if (roomEntity.membership == MyMembership.INVITED) { + if (roomEntity.membership == Membership.INVITE) { roomEntity.chunks.deleteAllFromRealm() } - - roomEntity.membership = MyMembership.JOINED + roomEntity.membership = Membership.JOIN val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) val isInitialSync = lastChunk == null @@ -121,8 +120,8 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, } } } - roomSummaryUpdater.update(realm, roomId, roomSync.summary, roomSync.unreadNotifications) - eventRelationsAggregationUpdater.update(realm,roomId,roomSync.timeline?.events) + eventRelationsAggregationUpdater.update(realm, roomId, roomSync.timeline?.events) + roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications) if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) { handleEphemeral(realm, roomId, roomSync.ephemeral) @@ -131,7 +130,6 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, if (roomSync.accountData != null && roomSync.accountData.events.isNullOrEmpty().not()) { handleRoomAccountDataEvents(realm, roomId, roomSync.accountData) } - return roomEntity } @@ -139,26 +137,28 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, roomId: String, roomSync: InvitedRoomSync): RoomEntity { - Timber.v("Handle invited sync for room $roomId") - - val roomEntity = RoomEntity() - roomEntity.roomId = roomId - roomEntity.membership = MyMembership.INVITED + val roomEntity = RoomEntity.where(realm, roomId).findFirst() + ?: realm.createObject(roomId) + roomEntity.membership = Membership.INVITE if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) { val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.inviteState.events) roomEntity.addOrUpdate(chunkEntity) } + roomSummaryUpdater.update(realm, roomId, Membership.INVITE) return roomEntity } - // TODO : handle it - private fun handleLeftRoom(roomId: String, + private fun handleLeftRoom(realm: Realm, + roomId: String, roomSync: RoomSync): RoomEntity { - return RoomEntity().apply { - this.roomId = roomId - this.membership = MyMembership.LEFT - } + val roomEntity = RoomEntity.where(realm, roomId).findFirst() + ?: realm.createObject(roomId) + + roomEntity.membership = Membership.LEAVE + roomEntity.chunks.deleteAllFromRealm() + roomSummaryUpdater.update(realm, roomId, Membership.LEAVE, roomSync.summary, roomSync.unreadNotifications) + return roomEntity } private fun handleTimelineEvents(realm: Realm, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt index 4197156d..f125f30f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt @@ -23,7 +23,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.UserEntity import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.session.room.members.RoomMembers +import im.vector.matrix.android.internal.session.room.membership.RoomMembers import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.tryTransactionSync diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt index e1ddcee9..4461ce95 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt @@ -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() } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index 49e4fd62..91e77a61 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -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)?.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) + } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt index 553078b8..6b6ac2cc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt @@ -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 {}) + } + + private fun handleAcceptInvite() { + room.join(object : MatrixCallback {}) + } + 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() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewState.kt index 4df1551c..43fbe9bd 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewState.kt @@ -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 = Uninitialized, val asyncRoomSummary: Async = Uninitialized, val asyncTimelineData: Async = Uninitialized ) : MvRxState { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt index 656617bb..b9476ce5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt @@ -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): RoomSummaries { + val invites = ArrayList() val favourites = ArrayList() val directChats = ArrayList() val groupRooms = ArrayList() @@ -160,8 +162,10 @@ class RoomListViewModel(initialState: RoomListViewState, val serverNotices = ArrayList() 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)) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt index 6d84c683..164b6d3b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt @@ -26,15 +26,17 @@ import im.vector.riotredesign.R data class RoomListViewState( val asyncRooms: Async = 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> 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), diff --git a/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt b/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt new file mode 100644 index 00000000..5cfddff2 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt @@ -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) + } + } +} \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_button_secondary.xml b/vector/src/main/res/drawable/bg_button_secondary.xml new file mode 100644 index 00000000..f889d60f --- /dev/null +++ b/vector/src/main/res/drawable/bg_button_secondary.xml @@ -0,0 +1,24 @@ + + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/fragment_room_detail.xml b/vector/src/main/res/layout/fragment_room_detail.xml index 880b8041..a5711bce 100644 --- a/vector/src/main/res/layout/fragment_room_detail.xml +++ b/vector/src/main/res/layout/fragment_room_detail.xml @@ -139,4 +139,16 @@ + + \ No newline at end of file diff --git a/vector/src/main/res/layout/vector_invite_view.xml b/vector/src/main/res/layout/vector_invite_view.xml new file mode 100644 index 00000000..dee10b3f --- /dev/null +++ b/vector/src/main/res/layout/vector_invite_view.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + +