Merge pull request #5858 from vector-im/feature/bma/room_api

Room now exposes methods to get the various Services
This commit is contained in:
Benoit Marty 2022-05-04 11:55:04 +02:00 committed by GitHub
commit 5076b2cdbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 565 additions and 372 deletions

1
changelog.d/5858.sdk Normal file
View file

@ -0,0 +1 @@
`Room` apis are now available by requesting the service first. For instance `Room.updateAvatar(...)` is now `Room.stateService().updateAvatar(...)`

View file

@ -21,6 +21,8 @@ import kotlinx.coroutines.flow.Flow
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.RoomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary
import org.matrix.android.sdk.api.session.room.model.ReadReceipt import org.matrix.android.sdk.api.session.room.model.ReadReceipt
@ -45,81 +47,81 @@ class FlowRoom(private val room: Room) {
} }
fun liveRoomMembers(queryParams: RoomMemberQueryParams): Flow<List<RoomMemberSummary>> { fun liveRoomMembers(queryParams: RoomMemberQueryParams): Flow<List<RoomMemberSummary>> {
return room.getRoomMembersLive(queryParams).asFlow() return room.membershipService().getRoomMembersLive(queryParams).asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getRoomMembers(queryParams) room.membershipService().getRoomMembers(queryParams)
} }
} }
fun liveAnnotationSummary(eventId: String): Flow<Optional<EventAnnotationsSummary>> { fun liveAnnotationSummary(eventId: String): Flow<Optional<EventAnnotationsSummary>> {
return room.getEventAnnotationsSummaryLive(eventId).asFlow() return room.relationService().getEventAnnotationsSummaryLive(eventId).asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getEventAnnotationsSummary(eventId).toOptional() room.relationService().getEventAnnotationsSummary(eventId).toOptional()
} }
} }
fun liveTimelineEvent(eventId: String): Flow<Optional<TimelineEvent>> { fun liveTimelineEvent(eventId: String): Flow<Optional<TimelineEvent>> {
return room.getTimelineEventLive(eventId).asFlow() return room.timelineService().getTimelineEventLive(eventId).asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getTimelineEvent(eventId).toOptional() room.getTimelineEvent(eventId).toOptional()
} }
} }
fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Flow<Optional<Event>> { fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Flow<Optional<Event>> {
return room.getStateEventLive(eventType, stateKey).asFlow() return room.stateService().getStateEventLive(eventType, stateKey).asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getStateEvent(eventType, stateKey).toOptional() room.getStateEvent(eventType, stateKey).toOptional()
} }
} }
fun liveStateEvents(eventTypes: Set<String>): Flow<List<Event>> { fun liveStateEvents(eventTypes: Set<String>): Flow<List<Event>> {
return room.getStateEventsLive(eventTypes).asFlow() return room.stateService().getStateEventsLive(eventTypes).asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getStateEvents(eventTypes) room.stateService().getStateEvents(eventTypes)
} }
} }
fun liveReadMarker(): Flow<Optional<String>> { fun liveReadMarker(): Flow<Optional<String>> {
return room.getReadMarkerLive().asFlow() return room.readService().getReadMarkerLive().asFlow()
} }
fun liveReadReceipt(): Flow<Optional<String>> { fun liveReadReceipt(): Flow<Optional<String>> {
return room.getMyReadReceiptLive().asFlow() return room.readService().getMyReadReceiptLive().asFlow()
} }
fun liveEventReadReceipts(eventId: String): Flow<List<ReadReceipt>> { fun liveEventReadReceipts(eventId: String): Flow<List<ReadReceipt>> {
return room.getEventReadReceiptsLive(eventId).asFlow() return room.readService().getEventReadReceiptsLive(eventId).asFlow()
} }
fun liveDraft(): Flow<Optional<UserDraft>> { fun liveDraft(): Flow<Optional<UserDraft>> {
return room.getDraftLive().asFlow() return room.draftService().getDraftLive().asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getDraft().toOptional() room.draftService().getDraft().toOptional()
} }
} }
fun liveNotificationState(): Flow<RoomNotificationState> { fun liveNotificationState(): Flow<RoomNotificationState> {
return room.getLiveRoomNotificationState().asFlow() return room.roomPushRuleService().getLiveRoomNotificationState().asFlow()
} }
fun liveThreadSummaries(): Flow<List<ThreadSummary>> { fun liveThreadSummaries(): Flow<List<ThreadSummary>> {
return room.getAllThreadSummariesLive().asFlow() return room.threadsService().getAllThreadSummariesLive().asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getAllThreadSummaries() room.threadsService().getAllThreadSummaries()
} }
} }
fun liveThreadList(): Flow<List<ThreadRootEvent>> { fun liveThreadList(): Flow<List<ThreadRootEvent>> {
return room.getAllThreadsLive().asFlow() return room.threadsLocalService().getAllThreadsLive().asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getAllThreads() room.threadsLocalService().getAllThreads()
} }
} }
fun liveLocalUnreadThreadList(): Flow<List<ThreadRootEvent>> { fun liveLocalUnreadThreadList(): Flow<List<ThreadRootEvent>> {
return room.getMarkedThreadNotificationsLive().asFlow() return room.threadsLocalService().getMarkedThreadNotificationsLive().asFlow()
.startWith(room.coroutineDispatchers.io) { .startWith(room.coroutineDispatchers.io) {
room.getMarkedThreadNotifications() room.threadsLocalService().getMarkedThreadNotifications()
} }
} }
} }

View file

@ -145,7 +145,7 @@ class CommonTestHelper(context: Context) {
* @param nbOfMessages the number of time the message will be sent * @param nbOfMessages the number of time the message will be sent
*/ */
fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> { fun sendTextMessage(room: Room, message: String, nbOfMessages: Int, timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> {
val timeline = room.createTimeline(null, TimelineSettings(10)) val timeline = room.timelineService().createTimeline(null, TimelineSettings(10))
timeline.start() timeline.start()
val sentEvents = sendTextMessagesBatched(timeline, room, message, nbOfMessages, timeout) val sentEvents = sendTextMessagesBatched(timeline, room, message, nbOfMessages, timeout)
timeline.dispose() timeline.dispose()
@ -165,11 +165,11 @@ class CommonTestHelper(context: Context) {
.forEach { batchedMessages -> .forEach { batchedMessages ->
batchedMessages.forEach { formattedMessage -> batchedMessages.forEach { formattedMessage ->
if (rootThreadEventId != null) { if (rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = rootThreadEventId, rootThreadEventId = rootThreadEventId,
replyInThreadText = formattedMessage) replyInThreadText = formattedMessage)
} else { } else {
room.sendTextMessage(formattedMessage) room.sendService().sendTextMessage(formattedMessage)
} }
} }
waitWithLatch(timeout) { latch -> waitWithLatch(timeout) { latch ->
@ -214,7 +214,7 @@ class CommonTestHelper(context: Context) {
numberOfMessages: Int, numberOfMessages: Int,
rootThreadEventId: String, rootThreadEventId: String,
timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> { timeout: Long = TestConstants.timeOutMillis): List<TimelineEvent> {
val timeline = room.createTimeline(null, TimelineSettings(10)) val timeline = room.timelineService().createTimeline(null, TimelineSettings(10))
timeline.start() timeline.start()
val sentEvents = sendTextMessagesBatched(timeline, room, message, numberOfMessages, timeout, rootThreadEventId) val sentEvents = sendTextMessagesBatched(timeline, room, message, numberOfMessages, timeout, rootThreadEventId)
timeline.dispose() timeline.dispose()

View file

@ -70,7 +70,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
if (encryptedRoom) { if (encryptedRoom) {
testHelper.waitWithLatch { latch -> testHelper.waitWithLatch { latch ->
val room = aliceSession.getRoom(roomId)!! val room = aliceSession.getRoom(roomId)!!
room.enableEncryption() room.roomCryptoService().enableEncryption()
val roomSummaryLive = room.getRoomSummaryLive() val roomSummaryLive = room.getRoomSummaryLive()
val roomSummaryObserver = object : Observer<Optional<RoomSummary>> { val roomSummaryObserver = object : Observer<Optional<RoomSummary>> {
override fun onChanged(roomSummary: Optional<RoomSummary>) { override fun onChanged(roomSummary: Optional<RoomSummary>) {
@ -109,7 +109,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
} }
} }
bobRoomSummariesLive.observeForever(newRoomObserver) bobRoomSummariesLive.observeForever(newRoomObserver)
aliceRoom.invite(bobSession.myUserId) aliceRoom.membershipService().invite(bobSession.myUserId)
} }
testHelper.waitWithLatch { latch -> testHelper.waitWithLatch { latch ->
@ -117,6 +117,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
val roomJoinedObserver = object : Observer<List<RoomSummary>> { val roomJoinedObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) { override fun onChanged(t: List<RoomSummary>?) {
if (bobSession.getRoom(aliceRoomId) if (bobSession.getRoom(aliceRoomId)
?.membershipService()
?.getRoomMember(bobSession.myUserId) ?.getRoomMember(bobSession.myUserId)
?.membership == Membership.JOIN) { ?.membership == Membership.JOIN) {
bobRoomSummariesLive.removeObserver(this) bobRoomSummariesLive.removeObserver(this)
@ -161,7 +162,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
val samSession = testHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams) val samSession = testHelper.createAccount(TestConstants.USER_SAM, defaultSessionParams)
testHelper.runBlockingTest { testHelper.runBlockingTest {
room.invite(samSession.myUserId, null) room.membershipService().invite(samSession.myUserId, null)
} }
testHelper.runBlockingTest { testHelper.runBlockingTest {
@ -261,6 +262,7 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
val newRoomObserver = object : Observer<List<RoomSummary>> { val newRoomObserver = object : Observer<List<RoomSummary>> {
override fun onChanged(t: List<RoomSummary>?) { override fun onChanged(t: List<RoomSummary>?) {
if (bob.getRoom(roomId) if (bob.getRoom(roomId)
?.membershipService()
?.getRoomMember(bob.myUserId) ?.getRoomMember(bob.myUserId)
?.membership == Membership.JOIN) { ?.membership == Membership.JOIN) {
bobRoomSummariesLive.removeObserver(this) bobRoomSummariesLive.removeObserver(this)
@ -373,13 +375,13 @@ class CryptoTestHelper(private val testHelper: CommonTestHelper) {
val room = aliceSession.getRoom(roomId)!! val room = aliceSession.getRoom(roomId)!!
testHelper.runBlockingTest { testHelper.runBlockingTest {
room.enableEncryption() room.roomCryptoService().enableEncryption()
} }
val sessions = mutableListOf(aliceSession) val sessions = mutableListOf(aliceSession)
for (index in 1 until numberOfMembers) { for (index in 1 until numberOfMembers) {
val session = testHelper.createAccount("User_$index", defaultSessionParams) val session = testHelper.createAccount("User_$index", defaultSessionParams)
testHelper.runBlockingTest(timeout = 600_000) { room.invite(session.myUserId, null) } testHelper.runBlockingTest(timeout = 600_000) { room.membershipService().invite(session.myUserId, null) }
println("TEST -> " + session.myUserId + " invited") println("TEST -> " + session.myUserId + " invited")
testHelper.runBlockingTest { session.roomService().joinRoom(room.roomId, null, emptyList()) } testHelper.runBlockingTest { session.roomService().joinRoom(room.roomId, null, emptyList()) }
println("TEST -> " + session.myUserId + " joined") println("TEST -> " + session.myUserId + " joined")

View file

@ -42,6 +42,7 @@ import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.failure.JoinRoomFailure import org.matrix.android.sdk.api.session.room.failure.JoinRoomFailure
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.send.SendState
@ -88,7 +89,7 @@ class E2eeSanityTests : InstrumentedTest {
otherAccounts.forEach { otherAccounts.forEach {
testHelper.runBlockingTest { testHelper.runBlockingTest {
Log.v("#E2E TEST", "Alice invites ${it.myUserId}") Log.v("#E2E TEST", "Alice invites ${it.myUserId}")
aliceRoomPOV.invite(it.myUserId) aliceRoomPOV.membershipService().invite(it.myUserId)
} }
} }
@ -130,7 +131,7 @@ class E2eeSanityTests : InstrumentedTest {
newAccount.forEach { newAccount.forEach {
testHelper.runBlockingTest { testHelper.runBlockingTest {
Log.v("#E2E TEST", "Alice invites ${it.myUserId}") Log.v("#E2E TEST", "Alice invites ${it.myUserId}")
aliceRoomPOV.invite(it.myUserId) aliceRoomPOV.membershipService().invite(it.myUserId)
} }
} }
@ -525,10 +526,10 @@ class E2eeSanityTests : InstrumentedTest {
} }
private fun sendMessageInRoom(aliceRoomPOV: Room, text: String): String? { private fun sendMessageInRoom(aliceRoomPOV: Room, text: String): String? {
aliceRoomPOV.sendTextMessage(text) aliceRoomPOV.sendService().sendTextMessage(text)
var sentEventId: String? = null var sentEventId: String? = null
testHelper.waitWithLatch(4 * TestConstants.timeOutMillis) { latch -> testHelper.waitWithLatch(4 * TestConstants.timeOutMillis) { latch ->
val timeline = aliceRoomPOV.createTimeline(null, TimelineSettings(60)) val timeline = aliceRoomPOV.timelineService().createTimeline(null, TimelineSettings(60))
timeline.start() timeline.start()
testHelper.retryPeriodicallyWithLatch(latch) { testHelper.retryPeriodicallyWithLatch(latch) {

View file

@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent import org.matrix.android.sdk.api.session.events.model.content.RoomKeyContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CryptoTestHelper

View file

@ -98,7 +98,7 @@ class UnwedgingTest : InstrumentedTest {
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!! val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(20)) val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(20))
bobTimeline.start() bobTimeline.start()
val bobFinalLatch = CountDownLatch(1) val bobFinalLatch = CountDownLatch(1)
@ -129,7 +129,7 @@ class UnwedgingTest : InstrumentedTest {
messagesReceivedByBob = emptyList() messagesReceivedByBob = emptyList()
// - Alice sends a 1st message with a 1st megolm session // - Alice sends a 1st message with a 1st megolm session
roomFromAlicePOV.sendTextMessage("First message") roomFromAlicePOV.sendService().sendTextMessage("First message")
// Wait for the message to be received by Bob // Wait for the message to be received by Bob
testHelper.await(latch) testHelper.await(latch)
@ -157,7 +157,7 @@ class UnwedgingTest : InstrumentedTest {
Timber.i("## CRYPTO | testUnwedging: Alice sends a 2nd message with a 2nd megolm session") Timber.i("## CRYPTO | testUnwedging: Alice sends a 2nd message with a 2nd megolm session")
// - Alice sends a 2nd message with a 2nd megolm session // - Alice sends a 2nd message with a 2nd megolm session
roomFromAlicePOV.sendTextMessage("Second message") roomFromAlicePOV.sendService().sendTextMessage("Second message")
// Wait for the message to be received by Bob // Wait for the message to be received by Bob
testHelper.await(latch) testHelper.await(latch)
@ -186,7 +186,7 @@ class UnwedgingTest : InstrumentedTest {
Timber.i("## CRYPTO | testUnwedging: Alice sends a 3rd message with a 3rd megolm session but a wedged olm session") Timber.i("## CRYPTO | testUnwedging: Alice sends a 3rd message with a 3rd megolm session but a wedged olm session")
// - Alice sends a 3rd message with a 3rd megolm session but a wedged olm session // - Alice sends a 3rd message with a 3rd megolm session but a wedged olm session
roomFromAlicePOV.sendTextMessage("Third message") roomFromAlicePOV.sendService().sendTextMessage("Third message")
// Bob should not be able to decrypt, because the session key could not be sent // Bob should not be able to decrypt, because the session key could not be sent
} }
bobTimeline.removeListener(bobEventsListener) bobTimeline.removeListener(bobEventsListener)

View file

@ -49,7 +49,7 @@ class EncryptionTest : InstrumentedTest {
fun test_EncryptionEvent() { fun test_EncryptionEvent() {
performTest(roomShouldBeEncrypted = false) { room -> performTest(roomShouldBeEncrypted = false) { room ->
// Send an encryption Event as an Event (and not as a state event) // Send an encryption Event as an Event (and not as a state event)
room.sendEvent( room.sendService().sendEvent(
eventType = EventType.STATE_ROOM_ENCRYPTION, eventType = EventType.STATE_ROOM_ENCRYPTION,
content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
) )
@ -61,7 +61,7 @@ class EncryptionTest : InstrumentedTest {
performTest(roomShouldBeEncrypted = true) { room -> performTest(roomShouldBeEncrypted = true) { room ->
runBlocking { runBlocking {
// Send an encryption Event as a State Event // Send an encryption Event as a State Event
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_ROOM_ENCRYPTION, eventType = EventType.STATE_ROOM_ENCRYPTION,
stateKey = "", stateKey = "",
body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent() body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
@ -76,9 +76,9 @@ class EncryptionTest : InstrumentedTest {
val aliceSession = cryptoTestData.firstSession val aliceSession = cryptoTestData.firstSession
val room = aliceSession.getRoom(cryptoTestData.roomId)!! val room = aliceSession.getRoom(cryptoTestData.roomId)!!
room.isEncrypted() shouldBe false room.roomCryptoService().isEncrypted() shouldBe false
val timeline = room.createTimeline(null, TimelineSettings(10)) val timeline = room.timelineService().createTimeline(null, TimelineSettings(10))
val latch = CountDownLatch(1) val latch = CountDownLatch(1)
val timelineListener = object : Timeline.Listener { val timelineListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) { override fun onTimelineFailure(throwable: Throwable) {
@ -106,7 +106,7 @@ class EncryptionTest : InstrumentedTest {
testHelper.await(latch) testHelper.await(latch)
timeline.dispose() timeline.dispose()
testHelper.waitWithLatch { testHelper.waitWithLatch {
room.isEncrypted() shouldBe roomShouldBeEncrypted room.roomCryptoService().isEncrypted() shouldBe roomShouldBeEncrypted
it.countDown() it.countDown()
} }
cryptoTestData.cleanUp(testHelper) cryptoTestData.cleanUp(testHelper)

View file

@ -51,6 +51,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomDirectoryVisibility
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageContent
@ -84,7 +85,7 @@ class KeyShareTests : InstrumentedTest {
val room = aliceSession.getRoom(roomId) val room = aliceSession.getRoom(roomId)
assertNotNull(room) assertNotNull(room)
Thread.sleep(4_000) Thread.sleep(4_000)
assertTrue(room?.isEncrypted() == true) assertTrue(room?.roomCryptoService()?.isEncrypted() == true)
val sentEventId = commonTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId val sentEventId = commonTestHelper.sendTextMessage(room!!, "My Message", 1).first().eventId
// Open a new sessionx // Open a new sessionx
@ -351,7 +352,7 @@ class KeyShareTests : InstrumentedTest {
val roomAlicePov = aliceSession.getRoom(roomId) val roomAlicePov = aliceSession.getRoom(roomId)
assertNotNull(roomAlicePov) assertNotNull(roomAlicePov)
Thread.sleep(1_000) Thread.sleep(1_000)
assertTrue(roomAlicePov?.isEncrypted() == true) assertTrue(roomAlicePov?.roomCryptoService()?.isEncrypted() == true)
val secondEventId = commonTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId val secondEventId = commonTestHelper.sendTextMessage(roomAlicePov!!, "Message", 3)[1].eventId
// Create bob session // Create bob session
@ -375,7 +376,7 @@ class KeyShareTests : InstrumentedTest {
// Let alice invite bob // Let alice invite bob
commonTestHelper.runBlockingTest { commonTestHelper.runBlockingTest {
roomAlicePov.invite(bobSession.myUserId, null) roomAlicePov.membershipService().invite(bobSession.myUserId, null)
} }
commonTestHelper.runBlockingTest { commonTestHelper.runBlockingTest {

View file

@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.common.CommonTestHelper import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.common.MockOkHttpInterceptor import org.matrix.android.sdk.common.MockOkHttpInterceptor

View file

@ -81,7 +81,7 @@ class ThreadMessagingTest : InstrumentedTest {
replyInThread.root.getRootThreadEventId().shouldBeEqualTo(initMessage.root.eventId) replyInThread.root.getRootThreadEventId().shouldBeEqualTo(initMessage.root.eventId)
// The init normal message should now be a root thread event // The init normal message should now be a root thread event
val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.startSync(true)
@ -142,7 +142,7 @@ class ThreadMessagingTest : InstrumentedTest {
replyInThread.root.getRootThreadEventId().shouldBeEqualTo(initMessage.root.eventId) replyInThread.root.getRootThreadEventId().shouldBeEqualTo(initMessage.root.eventId)
// The init normal message should now be a root thread event // The init normal message should now be a root thread event
val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.startSync(true)
@ -215,7 +215,7 @@ class ThreadMessagingTest : InstrumentedTest {
} }
// The init normal message should now be a root thread event // The init normal message should now be a root thread event
val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.startSync(true)
@ -310,7 +310,7 @@ class ThreadMessagingTest : InstrumentedTest {
} }
// The init normal message should now be a root thread event // The init normal message should now be a root thread event
val timeline = aliceRoom.createTimeline(null, TimelineSettings(30)) val timeline = aliceRoom.timelineService().createTimeline(null, TimelineSettings(30))
timeline.start() timeline.start()
aliceSession.startSync(true) aliceSession.startSync(true)

View file

@ -58,10 +58,10 @@ class PollAggregationTest : InstrumentedTest {
val roomFromBobPOV = cryptoTestData.secondSession!!.getRoom(cryptoTestData.roomId)!! val roomFromBobPOV = cryptoTestData.secondSession!!.getRoom(cryptoTestData.roomId)!!
// Bob creates a poll // Bob creates a poll
roomFromBobPOV.sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions) roomFromBobPOV.sendService().sendPoll(PollType.DISCLOSED, pollQuestion, pollOptions)
aliceSession.startSync(true) aliceSession.startSync(true)
val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(30)) val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30))
aliceTimeline.start() aliceTimeline.start()
val TOTAL_TEST_COUNT = 7 val TOTAL_TEST_COUNT = 7
@ -84,37 +84,37 @@ class PollAggregationTest : InstrumentedTest {
// Poll has just been created. // Poll has just been created.
testInitialPollConditions(pollContent, pollSummary) testInitialPollConditions(pollContent, pollSummary)
lock.countDown() lock.countDown()
roomFromBobPOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "") roomFromBobPOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "")
} }
TOTAL_TEST_COUNT - 1 -> { TOTAL_TEST_COUNT - 1 -> {
// Bob: Option 1 // Bob: Option 1
testBobVotesOption1(pollContent, pollSummary) testBobVotesOption1(pollContent, pollSummary)
lock.countDown() lock.countDown()
roomFromBobPOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") roomFromBobPOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "")
} }
TOTAL_TEST_COUNT - 2 -> { TOTAL_TEST_COUNT - 2 -> {
// Bob: Option 2 // Bob: Option 2
testBobChangesVoteToOption2(pollContent, pollSummary) testBobChangesVoteToOption2(pollContent, pollSummary)
lock.countDown() lock.countDown()
roomFromAlicePOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") roomFromAlicePOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "")
} }
TOTAL_TEST_COUNT - 3 -> { TOTAL_TEST_COUNT - 3 -> {
// Alice: Option 2, Bob: Option 2 // Alice: Option 2, Bob: Option 2
testAliceAndBobVoteToOption2(pollContent, pollSummary) testAliceAndBobVoteToOption2(pollContent, pollSummary)
lock.countDown() lock.countDown()
roomFromAlicePOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "") roomFromAlicePOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.firstOrNull()?.id ?: "")
} }
TOTAL_TEST_COUNT - 4 -> { TOTAL_TEST_COUNT - 4 -> {
// Alice: Option 1, Bob: Option 2 // Alice: Option 1, Bob: Option 2
testAliceVotesOption1AndBobVotesOption2(pollContent, pollSummary) testAliceVotesOption1AndBobVotesOption2(pollContent, pollSummary)
lock.countDown() lock.countDown()
roomFromBobPOV.endPoll(pollEventId) roomFromBobPOV.sendService().endPoll(pollEventId)
} }
TOTAL_TEST_COUNT - 5 -> { TOTAL_TEST_COUNT - 5 -> {
// Alice: Option 1, Bob: Option 2 [poll is ended] // Alice: Option 1, Bob: Option 2 [poll is ended]
testEndedPoll(pollSummary) testEndedPoll(pollSummary)
lock.countDown() lock.countDown()
roomFromAlicePOV.voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "") roomFromAlicePOV.sendService().voteToPoll(pollEventId, pollContent.getBestPollCreationInfo()?.answers?.get(1)?.id ?: "")
} }
TOTAL_TEST_COUNT - 6 -> { TOTAL_TEST_COUNT - 6 -> {
// Alice: Option 1 (ignore change), Bob: Option 2 [poll is ended] // Alice: Option 1 (ignore change), Bob: Option 2 [poll is ended]

View file

@ -75,7 +75,7 @@ class TimelineForwardPaginationTest : InstrumentedTest {
// Alice clear the cache and restart the sync // Alice clear the cache and restart the sync
commonTestHelper.clearCacheAndSync(aliceSession) commonTestHelper.clearCacheAndSync(aliceSession)
val aliceTimeline = roomFromAlicePOV.createTimeline(null, TimelineSettings(30)) val aliceTimeline = roomFromAlicePOV.timelineService().createTimeline(null, TimelineSettings(30))
aliceTimeline.start() aliceTimeline.start()
// Alice sees the 10 last message of the room, and can only navigate BACKWARD // Alice sees the 10 last message of the room, and can only navigate BACKWARD

View file

@ -63,7 +63,7 @@ class TimelinePreviousLastForwardTest : InstrumentedTest {
val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!! val roomFromAlicePOV = aliceSession.getRoom(aliceRoomId)!!
val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!! val roomFromBobPOV = bobSession.getRoom(aliceRoomId)!!
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(30)) val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30))
bobTimeline.start() bobTimeline.start()
run { run {

View file

@ -66,7 +66,7 @@ class TimelineSimpleBackPaginationTest : InstrumentedTest {
message, message,
numberOfMessagesToSent) numberOfMessagesToSent)
val bobTimeline = roomFromBobPOV.createTimeline(null, TimelineSettings(30)) val bobTimeline = roomFromBobPOV.timelineService().createTimeline(null, TimelineSettings(30))
bobTimeline.start() bobTimeline.start()
commonTestHelper.waitWithLatch(timeout = TestConstants.timeOutMillis * 10) { commonTestHelper.waitWithLatch(timeout = TestConstants.timeOutMillis * 10) {

View file

@ -72,7 +72,7 @@ class TimelineWithManyMembersTest : InstrumentedTest {
for (index in 1 until cryptoTestData.sessions.size) { for (index in 1 until cryptoTestData.sessions.size) {
val session = cryptoTestData.sessions[index] val session = cryptoTestData.sessions[index]
val roomForCurrentMember = session.getRoom(cryptoTestData.roomId)!! val roomForCurrentMember = session.getRoom(cryptoTestData.roomId)!!
val timelineForCurrentMember = roomForCurrentMember.createTimeline(null, TimelineSettings(30)) val timelineForCurrentMember = roomForCurrentMember.timelineService().createTimeline(null, TimelineSettings(30))
timelineForCurrentMember.start() timelineForCurrentMember.start()
session.startSync(true) session.startSync(true)

View file

@ -29,6 +29,7 @@ import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent

View file

@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
@ -499,7 +500,7 @@ class SpaceHierarchyTest : InstrumentedTest {
)) ))
commonTestHelper.runBlockingTest { commonTestHelper.runBlockingTest {
aliceSession.getRoom(spaceAInfo.spaceId)!!.invite(bobSession.myUserId, null) aliceSession.getRoom(spaceAInfo.spaceId)!!.membershipService().invite(bobSession.myUserId, null)
} }
commonTestHelper.runBlockingTest { commonTestHelper.runBlockingTest {
@ -509,7 +510,7 @@ class SpaceHierarchyTest : InstrumentedTest {
var bobRoomId = "" var bobRoomId = ""
commonTestHelper.waitWithLatch { commonTestHelper.waitWithLatch {
bobRoomId = bobSession.roomService().createRoom(CreateRoomParams().apply { name = "A Bob Room" }) bobRoomId = bobSession.roomService().createRoom(CreateRoomParams().apply { name = "A Bob Room" })
bobSession.getRoom(bobRoomId)!!.invite(aliceSession.myUserId) bobSession.getRoom(bobRoomId)!!.membershipService().invite(aliceSession.myUserId)
it.countDown() it.countDown()
} }
@ -554,7 +555,7 @@ class SpaceHierarchyTest : InstrumentedTest {
?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value) ?.setUserPowerLevel(aliceSession.myUserId, Role.Admin.value)
?.toContent() ?.toContent()
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent!!) room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent!!)
it.countDown() it.countDown()
} }

View file

@ -44,7 +44,7 @@ class RoomMemberCountCondition(
// Parse the is field into prefix and number the first time // Parse the is field into prefix and number the first time
val (prefix, count) = parseIsField() ?: return false val (prefix, count) = parseIsField() ?: return false
val numMembers = room.getNumberOfJoinedMembers() val numMembers = room.membershipService().getNumberOfJoinedMembers()
return when (prefix) { return when (prefix) {
"<" -> numMembers < count "<" -> numMembers < count

View file

@ -44,26 +44,7 @@ import org.matrix.android.sdk.api.util.Optional
/** /**
* This interface defines methods to interact within a room. * This interface defines methods to interact within a room.
*/ */
interface Room : interface Room {
TimelineService,
ThreadsService,
ThreadsLocalService,
SendService,
DraftService,
ReadService,
TypingService,
AliasService,
TagsService,
MembershipService,
StateService,
UploadsService,
ReportingService,
RoomCallService,
RelationService,
RoomCryptoService,
RoomPushRuleService,
RoomAccountDataService,
RoomVersionService {
val coroutineDispatchers: MatrixCoroutineDispatchers val coroutineDispatchers: MatrixCoroutineDispatchers
@ -87,4 +68,99 @@ interface Room :
* Use this room as a Space, if the type is correct. * Use this room as a Space, if the type is correct.
*/ */
fun asSpace(): Space? fun asSpace(): Space?
/**
* Get the TimelineService associated to this Room
*/
fun timelineService(): TimelineService
/**
* Get the ThreadsService associated to this Room
*/
fun threadsService(): ThreadsService
/**
* Get the ThreadsLocalService associated to this Room
*/
fun threadsLocalService(): ThreadsLocalService
/**
* Get the SendService associated to this Room
*/
fun sendService(): SendService
/**
* Get the DraftService associated to this Room
*/
fun draftService(): DraftService
/**
* Get the ReadService associated to this Room
*/
fun readService(): ReadService
/**
* Get the TypingService associated to this Room
*/
fun typingService(): TypingService
/**
* Get the AliasService associated to this Room
*/
fun aliasService(): AliasService
/**
* Get the TagsService associated to this Room
*/
fun tagsService(): TagsService
/**
* Get the MembershipService associated to this Room
*/
fun membershipService(): MembershipService
/**
* Get the StateService associated to this Room
*/
fun stateService(): StateService
/**
* Get the UploadsService associated to this Room
*/
fun uploadsService(): UploadsService
/**
* Get the ReportingService associated to this Room
*/
fun reportingService(): ReportingService
/**
* Get the RoomCallService associated to this Room
*/
fun roomCallService(): RoomCallService
/**
* Get the RelationService associated to this Room
*/
fun relationService(): RelationService
/**
* Get the RoomCryptoService associated to this Room
*/
fun roomCryptoService(): RoomCryptoService
/**
* Get the RoomPushRuleService associated to this Room
*/
fun roomPushRuleService(): RoomPushRuleService
/**
* Get the RoomAccountDataService associated to this Room
*/
fun roomAccountDataService(): RoomAccountDataService
/**
* Get the RoomVersionService associated to this Room
*/
fun roomVersionService(): RoomVersionService
} }

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.api.session.room
import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
/**
* Get a TimelineEvent using the TimelineService of a Room
*/
fun Room.getTimelineEvent(eventId: String): TimelineEvent? =
timelineService().getTimelineEvent(eventId)
/**
* Get a StateEvent using the StateService of a Room
*/
fun Room.getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event? =
stateService().getStateEvent(eventType, stateKey)

View file

@ -72,6 +72,7 @@ internal class ViaParameterFinder @Inject constructor(
*/ */
private fun getUserIdsOfJoinedMembers(roomId: String): Set<String> { private fun getUserIdsOfJoinedMembers(roomId: String): Set<String> {
return roomGetterProvider.get().getRoom(roomId) return roomGetterProvider.get().getRoom(roomId)
?.membershipService()
?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) }) ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
?.map { it.userId } ?.map { it.userId }
.orEmpty() .orEmpty()
@ -84,6 +85,7 @@ internal class ViaParameterFinder @Inject constructor(
// It may not be possible for a user to join a room if there's no overlap between these // It may not be possible for a user to join a room if there's no overlap between these
fun computeViaParamsForRestricted(roomId: String, max: Int): List<String> { fun computeViaParamsForRestricted(roomId: String, max: Int): List<String> {
val userThatCanInvite = roomGetterProvider.get().getRoom(roomId) val userThatCanInvite = roomGetterProvider.get().getRoom(roomId)
?.membershipService()
?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) }) ?.getRoomMembers(roomMemberQueryParams { memberships = listOf(Membership.JOIN) })
?.map { it.userId } ?.map { it.userId }
?.filter { userCanInvite(userId, roomId) } ?.filter { userCanInvite(userId, roomId) }

View file

@ -23,6 +23,7 @@ import org.matrix.android.sdk.api.session.pushrules.ContainsDisplayNameCondition
import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition
import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition
import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.room.RoomGetter import org.matrix.android.sdk.internal.session.room.RoomGetter
@ -60,7 +61,7 @@ internal class DefaultConditionResolver @Inject constructor(
condition: ContainsDisplayNameCondition): Boolean { condition: ContainsDisplayNameCondition): Boolean {
val roomId = event.roomId ?: return false val roomId = event.roomId ?: return false
val room = roomGetter.getRoom(roomId) ?: return false val room = roomGetter.getRoom(roomId) ?: return false
val myDisplayName = room.getRoomMember(userId)?.displayName ?: return false val myDisplayName = room.membershipService().getRoomMember(userId)?.displayName ?: return false
return condition.isSatisfied(event, myDisplayName) return condition.isSatisfied(event, myDisplayName)
} }
} }

View file

@ -18,13 +18,11 @@ package org.matrix.android.sdk.internal.session.room
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService import org.matrix.android.sdk.api.session.room.accountdata.RoomAccountDataService
import org.matrix.android.sdk.api.session.room.alias.AliasService import org.matrix.android.sdk.api.session.room.alias.AliasService
import org.matrix.android.sdk.api.session.room.call.RoomCallService import org.matrix.android.sdk.api.session.room.call.RoomCallService
import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
import org.matrix.android.sdk.api.session.room.members.MembershipService import org.matrix.android.sdk.api.session.room.members.MembershipService
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.RoomType
@ -44,57 +42,35 @@ import org.matrix.android.sdk.api.session.room.uploads.UploadsService
import org.matrix.android.sdk.api.session.room.version.RoomVersionService import org.matrix.android.sdk.api.session.room.version.RoomVersionService
import org.matrix.android.sdk.api.session.space.Space import org.matrix.android.sdk.api.session.space.Space
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
import org.matrix.android.sdk.api.util.awaitCallback
import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
import org.matrix.android.sdk.internal.session.room.state.SendStateTask
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
import org.matrix.android.sdk.internal.session.space.DefaultSpace import org.matrix.android.sdk.internal.session.space.DefaultSpace
import java.security.InvalidParameterException
internal class DefaultRoom(override val roomId: String, internal class DefaultRoom(
private val roomSummaryDataSource: RoomSummaryDataSource, override val roomId: String,
private val timelineService: TimelineService, private val roomSummaryDataSource: RoomSummaryDataSource,
private val threadsService: ThreadsService, private val roomCryptoService: RoomCryptoService,
private val threadsLocalService: ThreadsLocalService, private val timelineService: TimelineService,
private val sendService: SendService, private val threadsService: ThreadsService,
private val draftService: DraftService, private val threadsLocalService: ThreadsLocalService,
private val stateService: StateService, private val sendService: SendService,
private val uploadsService: UploadsService, private val draftService: DraftService,
private val reportingService: ReportingService, private val stateService: StateService,
private val roomCallService: RoomCallService, private val uploadsService: UploadsService,
private val readService: ReadService, private val reportingService: ReportingService,
private val typingService: TypingService, private val roomCallService: RoomCallService,
private val aliasService: AliasService, private val readService: ReadService,
private val tagsService: TagsService, private val typingService: TypingService,
private val cryptoService: CryptoService, private val aliasService: AliasService,
private val relationService: RelationService, private val tagsService: TagsService,
private val roomMembersService: MembershipService, private val relationService: RelationService,
private val roomPushRuleService: RoomPushRuleService, private val roomMembersService: MembershipService,
private val roomAccountDataService: RoomAccountDataService, private val roomPushRuleService: RoomPushRuleService,
private val roomVersionService: RoomVersionService, private val roomAccountDataService: RoomAccountDataService,
private val sendStateTask: SendStateTask, private val roomVersionService: RoomVersionService,
private val viaParameterFinder: ViaParameterFinder, private val viaParameterFinder: ViaParameterFinder,
override val coroutineDispatchers: MatrixCoroutineDispatchers override val coroutineDispatchers: MatrixCoroutineDispatchers
) : ) : Room {
Room,
TimelineService by timelineService,
ThreadsService by threadsService,
ThreadsLocalService by threadsLocalService,
SendService by sendService,
DraftService by draftService,
StateService by stateService,
UploadsService by uploadsService,
ReportingService by reportingService,
RoomCallService by roomCallService,
ReadService by readService,
TypingService by typingService,
AliasService by aliasService,
TagsService by tagsService,
RelationService by relationService,
MembershipService by roomMembersService,
RoomPushRuleService by roomPushRuleService,
RoomAccountDataService by roomAccountDataService,
RoomVersionService by roomVersionService {
override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> { override fun getRoomSummaryLive(): LiveData<Optional<RoomSummary>> {
return roomSummaryDataSource.getRoomSummaryLive(roomId) return roomSummaryDataSource.getRoomSummaryLive(roomId)
@ -104,49 +80,28 @@ internal class DefaultRoom(override val roomId: String,
return roomSummaryDataSource.getRoomSummary(roomId) return roomSummaryDataSource.getRoomSummary(roomId)
} }
override fun isEncrypted(): Boolean {
return cryptoService.isRoomEncrypted(roomId)
}
override fun encryptionAlgorithm(): String? {
return cryptoService.getEncryptionAlgorithm(roomId)
}
override fun shouldEncryptForInvitedMembers(): Boolean {
return cryptoService.shouldEncryptForInvitedMembers(roomId)
}
override suspend fun prepareToEncrypt() {
awaitCallback<Unit> {
cryptoService.prepareToEncrypt(roomId, it)
}
}
override suspend fun enableEncryption(algorithm: String, force: Boolean) {
when {
(!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> {
throw IllegalStateException("Encryption is already enabled for this room")
}
(!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> {
throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported")
}
else -> {
val params = SendStateTask.Params(
roomId = roomId,
stateKey = "",
eventType = EventType.STATE_ROOM_ENCRYPTION,
body = mapOf(
"algorithm" to algorithm
)
)
sendStateTask.execute(params)
}
}
}
override fun asSpace(): Space? { override fun asSpace(): Space? {
if (roomSummary()?.roomType != RoomType.SPACE) return null if (roomSummary()?.roomType != RoomType.SPACE) return null
return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder) return DefaultSpace(this, roomSummaryDataSource, viaParameterFinder)
} }
override fun timelineService() = timelineService
override fun threadsService() = threadsService
override fun threadsLocalService() = threadsLocalService
override fun sendService() = sendService
override fun draftService() = draftService
override fun stateService() = stateService
override fun uploadsService() = uploadsService
override fun reportingService() = reportingService
override fun roomCallService() = roomCallService
override fun readService() = readService
override fun typingService() = typingService
override fun aliasService() = aliasService
override fun tagsService() = tagsService
override fun relationService() = relationService
override fun roomCryptoService() = roomCryptoService
override fun membershipService() = roomMembersService
override fun roomPushRuleService() = roomPushRuleService
override fun roomAccountDataService() = roomAccountDataService
override fun roomVersionService() = roomVersionService
} }

View file

@ -28,6 +28,7 @@ import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventCon
import org.matrix.android.sdk.api.session.events.model.getRelationContent import org.matrix.android.sdk.api.session.events.model.getRelationContent
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.PollSummaryContent import org.matrix.android.sdk.api.session.room.model.PollSummaryContent
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedContent

View file

@ -17,13 +17,13 @@
package org.matrix.android.sdk.internal.session.room package org.matrix.android.sdk.internal.session.room
import org.matrix.android.sdk.api.MatrixCoroutineDispatchers import org.matrix.android.sdk.api.MatrixCoroutineDispatchers
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder import org.matrix.android.sdk.internal.session.permalinks.ViaParameterFinder
import org.matrix.android.sdk.internal.session.room.accountdata.DefaultRoomAccountDataService import org.matrix.android.sdk.internal.session.room.accountdata.DefaultRoomAccountDataService
import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService import org.matrix.android.sdk.internal.session.room.alias.DefaultAliasService
import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService import org.matrix.android.sdk.internal.session.room.call.DefaultRoomCallService
import org.matrix.android.sdk.internal.session.room.crypto.DefaultRoomCryptoService
import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService import org.matrix.android.sdk.internal.session.room.draft.DefaultDraftService
import org.matrix.android.sdk.internal.session.room.membership.DefaultMembershipService import org.matrix.android.sdk.internal.session.room.membership.DefaultMembershipService
import org.matrix.android.sdk.internal.session.room.notification.DefaultRoomPushRuleService import org.matrix.android.sdk.internal.session.room.notification.DefaultRoomPushRuleService
@ -32,7 +32,6 @@ import org.matrix.android.sdk.internal.session.room.relation.DefaultRelationServ
import org.matrix.android.sdk.internal.session.room.reporting.DefaultReportingService import org.matrix.android.sdk.internal.session.room.reporting.DefaultReportingService
import org.matrix.android.sdk.internal.session.room.send.DefaultSendService import org.matrix.android.sdk.internal.session.room.send.DefaultSendService
import org.matrix.android.sdk.internal.session.room.state.DefaultStateService import org.matrix.android.sdk.internal.session.room.state.DefaultStateService
import org.matrix.android.sdk.internal.session.room.state.SendStateTask
import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource import org.matrix.android.sdk.internal.session.room.summary.RoomSummaryDataSource
import org.matrix.android.sdk.internal.session.room.tags.DefaultTagsService import org.matrix.android.sdk.internal.session.room.tags.DefaultTagsService
import org.matrix.android.sdk.internal.session.room.threads.DefaultThreadsService import org.matrix.android.sdk.internal.session.room.threads.DefaultThreadsService
@ -48,35 +47,36 @@ internal interface RoomFactory {
} }
@SessionScope @SessionScope
internal class DefaultRoomFactory @Inject constructor(private val cryptoService: CryptoService, internal class DefaultRoomFactory @Inject constructor(
private val roomSummaryDataSource: RoomSummaryDataSource, private val roomSummaryDataSource: RoomSummaryDataSource,
private val timelineServiceFactory: DefaultTimelineService.Factory, private val timelineServiceFactory: DefaultTimelineService.Factory,
private val threadsServiceFactory: DefaultThreadsService.Factory, private val threadsServiceFactory: DefaultThreadsService.Factory,
private val threadsLocalServiceFactory: DefaultThreadsLocalService.Factory, private val threadsLocalServiceFactory: DefaultThreadsLocalService.Factory,
private val sendServiceFactory: DefaultSendService.Factory, private val sendServiceFactory: DefaultSendService.Factory,
private val draftServiceFactory: DefaultDraftService.Factory, private val draftServiceFactory: DefaultDraftService.Factory,
private val stateServiceFactory: DefaultStateService.Factory, private val stateServiceFactory: DefaultStateService.Factory,
private val uploadsServiceFactory: DefaultUploadsService.Factory, private val uploadsServiceFactory: DefaultUploadsService.Factory,
private val reportingServiceFactory: DefaultReportingService.Factory, private val reportingServiceFactory: DefaultReportingService.Factory,
private val roomCallServiceFactory: DefaultRoomCallService.Factory, private val roomCallServiceFactory: DefaultRoomCallService.Factory,
private val readServiceFactory: DefaultReadService.Factory, private val readServiceFactory: DefaultReadService.Factory,
private val typingServiceFactory: DefaultTypingService.Factory, private val typingServiceFactory: DefaultTypingService.Factory,
private val aliasServiceFactory: DefaultAliasService.Factory, private val aliasServiceFactory: DefaultAliasService.Factory,
private val tagsServiceFactory: DefaultTagsService.Factory, private val tagsServiceFactory: DefaultTagsService.Factory,
private val relationServiceFactory: DefaultRelationService.Factory, private val relationServiceFactory: DefaultRelationService.Factory,
private val membershipServiceFactory: DefaultMembershipService.Factory, private val roomCryptoServiceFactory: DefaultRoomCryptoService.Factory,
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory, private val membershipServiceFactory: DefaultMembershipService.Factory,
private val roomVersionServiceFactory: DefaultRoomVersionService.Factory, private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory, private val roomVersionServiceFactory: DefaultRoomVersionService.Factory,
private val sendStateTask: SendStateTask, private val roomAccountDataServiceFactory: DefaultRoomAccountDataService.Factory,
private val viaParameterFinder: ViaParameterFinder, private val viaParameterFinder: ViaParameterFinder,
private val coroutineDispatchers: MatrixCoroutineDispatchers) : private val coroutineDispatchers: MatrixCoroutineDispatchers
RoomFactory { ) : RoomFactory {
override fun create(roomId: String): Room { override fun create(roomId: String): Room {
return DefaultRoom( return DefaultRoom(
roomId = roomId, roomId = roomId,
roomSummaryDataSource = roomSummaryDataSource, roomSummaryDataSource = roomSummaryDataSource,
roomCryptoService = roomCryptoServiceFactory.create(roomId),
timelineService = timelineServiceFactory.create(roomId), timelineService = timelineServiceFactory.create(roomId),
threadsService = threadsServiceFactory.create(roomId), threadsService = threadsServiceFactory.create(roomId),
threadsLocalService = threadsLocalServiceFactory.create(roomId), threadsLocalService = threadsLocalServiceFactory.create(roomId),
@ -90,13 +90,11 @@ internal class DefaultRoomFactory @Inject constructor(private val cryptoService:
typingService = typingServiceFactory.create(roomId), typingService = typingServiceFactory.create(roomId),
aliasService = aliasServiceFactory.create(roomId), aliasService = aliasServiceFactory.create(roomId),
tagsService = tagsServiceFactory.create(roomId), tagsService = tagsServiceFactory.create(roomId),
cryptoService = cryptoService,
relationService = relationServiceFactory.create(roomId), relationService = relationServiceFactory.create(roomId),
roomMembersService = membershipServiceFactory.create(roomId), roomMembersService = membershipServiceFactory.create(roomId),
roomPushRuleService = roomPushRuleServiceFactory.create(roomId), roomPushRuleService = roomPushRuleServiceFactory.create(roomId),
roomAccountDataService = roomAccountDataServiceFactory.create(roomId), roomAccountDataService = roomAccountDataServiceFactory.create(roomId),
roomVersionService = roomVersionServiceFactory.create(roomId), roomVersionService = roomVersionServiceFactory.create(roomId),
sendStateTask = sendStateTask,
viaParameterFinder = viaParameterFinder, viaParameterFinder = viaParameterFinder,
coroutineDispatchers = coroutineDispatchers coroutineDispatchers = coroutineDispatchers
) )

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
*
* 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 org.matrix.android.sdk.internal.session.room.crypto
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.session.crypto.CryptoService
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.crypto.RoomCryptoService
import org.matrix.android.sdk.api.util.awaitCallback
import org.matrix.android.sdk.internal.session.room.state.SendStateTask
import java.security.InvalidParameterException
internal class DefaultRoomCryptoService @AssistedInject constructor(
@Assisted private val roomId: String,
private val cryptoService: CryptoService,
private val sendStateTask: SendStateTask,
) : RoomCryptoService {
@AssistedFactory
interface Factory {
fun create(roomId: String): DefaultRoomCryptoService
}
override fun isEncrypted(): Boolean {
return cryptoService.isRoomEncrypted(roomId)
}
override fun encryptionAlgorithm(): String? {
return cryptoService.getEncryptionAlgorithm(roomId)
}
override fun shouldEncryptForInvitedMembers(): Boolean {
return cryptoService.shouldEncryptForInvitedMembers(roomId)
}
override suspend fun prepareToEncrypt() {
awaitCallback<Unit> {
cryptoService.prepareToEncrypt(roomId, it)
}
}
override suspend fun enableEncryption(algorithm: String, force: Boolean) {
when {
(!force && isEncrypted() && encryptionAlgorithm() == MXCRYPTO_ALGORITHM_MEGOLM) -> {
throw IllegalStateException("Encryption is already enabled for this room")
}
(!force && algorithm != MXCRYPTO_ALGORITHM_MEGOLM) -> {
throw InvalidParameterException("Only MXCRYPTO_ALGORITHM_MEGOLM algorithm is supported")
}
else -> {
val params = SendStateTask.Params(
roomId = roomId,
stateKey = "",
eventType = EventType.STATE_ROOM_ENCRYPTION,
body = mapOf(
"algorithm" to algorithm
)
)
sendStateTask.execute(params)
}
}
}
}

View file

@ -60,7 +60,7 @@ internal class DefaultSpace(
} }
?: viaParameterFinder.computeViaParams(roomId, 3)) ?: viaParameterFinder.computeViaParams(roomId, 3))
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD, eventType = EventType.STATE_SPACE_CHILD,
stateKey = roomId, stateKey = roomId,
body = SpaceChildContent( body = SpaceChildContent(
@ -79,7 +79,7 @@ internal class DefaultSpace(
// return // return
// edit state event and set via to null // edit state event and set via to null
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD, eventType = EventType.STATE_SPACE_CHILD,
stateKey = roomId, stateKey = roomId,
body = SpaceChildContent( body = SpaceChildContent(
@ -91,19 +91,19 @@ internal class DefaultSpace(
} }
override fun getChildInfo(roomId: String): SpaceChildContent? { override fun getChildInfo(roomId: String): SpaceChildContent? {
return room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) return room.stateService().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
.firstOrNull() .firstOrNull()
?.content.toModel<SpaceChildContent>() ?.content.toModel<SpaceChildContent>()
} }
override suspend fun setChildrenOrder(roomId: String, order: String?) { override suspend fun setChildrenOrder(roomId: String, order: String?) {
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) val existing = room.stateService().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
.firstOrNull() .firstOrNull()
?.content.toModel<SpaceChildContent>() ?.content.toModel<SpaceChildContent>()
?: throw IllegalArgumentException("$roomId is not a child of this space") ?: throw IllegalArgumentException("$roomId is not a child of this space")
// edit state event and set via to null // edit state event and set via to null
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD, eventType = EventType.STATE_SPACE_CHILD,
stateKey = roomId, stateKey = roomId,
body = SpaceChildContent( body = SpaceChildContent(
@ -140,7 +140,7 @@ internal class DefaultSpace(
// } // }
override suspend fun setChildrenSuggested(roomId: String, suggested: Boolean) { override suspend fun setChildrenSuggested(roomId: String, suggested: Boolean) {
val existing = room.getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId)) val existing = room.stateService().getStateEvents(setOf(EventType.STATE_SPACE_CHILD), QueryStringValue.Equals(roomId))
.firstOrNull() .firstOrNull()
?.content.toModel<SpaceChildContent>() ?.content.toModel<SpaceChildContent>()
?: throw IllegalArgumentException("$roomId is not a child of this space") ?: throw IllegalArgumentException("$roomId is not a child of this space")
@ -150,7 +150,7 @@ internal class DefaultSpace(
return return
} }
// edit state event and set via to null // edit state event and set via to null
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_SPACE_CHILD, eventType = EventType.STATE_SPACE_CHILD,
stateKey = roomId, stateKey = roomId,
body = SpaceChildContent( body = SpaceChildContent(

View file

@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.RoomSortOrder import org.matrix.android.sdk.api.session.room.RoomSortOrder
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.GuestAccess import org.matrix.android.sdk.api.session.room.model.GuestAccess
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
@ -258,7 +259,7 @@ internal class DefaultSpaceService @Inject constructor(
val room = roomGetter.getRoom(childRoomId) val room = roomGetter.getRoom(childRoomId)
?: throw IllegalArgumentException("Unknown Room $childRoomId") ?: throw IllegalArgumentException("Unknown Room $childRoomId")
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_SPACE_PARENT, eventType = EventType.STATE_SPACE_PARENT,
stateKey = parentSpaceId, stateKey = parentSpaceId,
body = SpaceParentContent( body = SpaceParentContent(
@ -276,7 +277,7 @@ internal class DefaultSpaceService @Inject constructor(
if (existingEvent != null) { if (existingEvent != null) {
// Should i check if it was sent by me? // Should i check if it was sent by me?
// we don't check power level, it will throw if you cannot do that // we don't check power level, it will throw if you cannot do that
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_SPACE_PARENT, eventType = EventType.STATE_SPACE_PARENT,
stateKey = parentSpaceId, stateKey = parentSpaceId,
body = SpaceParentContent( body = SpaceParentContent(

View file

@ -26,6 +26,7 @@ import org.matrix.android.sdk.MatrixTest
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.members.MembershipService
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
@ -148,14 +149,22 @@ class PushRulesConditionTest : MatrixTest {
val room2JoinedId = "2joined" val room2JoinedId = "2joined"
val room3JoinedId = "3joined" val room3JoinedId = "3joined"
val roomStub2Joined = mockk<Room> { val roomMembershipService2 = mockk<MembershipService> {
every { getNumberOfJoinedMembers() } returns 2 every { getNumberOfJoinedMembers() } returns 2
} }
val roomStub3Joined = mockk<Room> { val roomMembershipService3 = mockk<MembershipService> {
every { getNumberOfJoinedMembers() } returns 3 every { getNumberOfJoinedMembers() } returns 3
} }
val roomStub2Joined = mockk<Room> {
every { membershipService() } returns roomMembershipService2
}
val roomStub3Joined = mockk<Room> {
every { membershipService() } returns roomMembershipService3
}
val roomGetterStub = mockk<RoomGetter> { val roomGetterStub = mockk<RoomGetter> {
every { getRoom(room2JoinedId) } returns roomStub2Joined every { getRoom(room2JoinedId) } returns roomStub2Joined
every { getRoom(room3JoinedId) } returns roomStub3Joined every { getRoom(room3JoinedId) } returns roomStub3Joined

View file

@ -47,6 +47,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.logger.LoggerTag
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject

View file

@ -102,7 +102,7 @@ class AppStateHandler @Inject constructor(
if (spaceId != null) { if (spaceId != null) {
uSession.coroutineScope.launch(Dispatchers.IO) { uSession.coroutineScope.launch(Dispatchers.IO) {
tryOrNull { tryOrNull {
uSession.getRoom(spaceId)?.loadRoomMembersIfNeeded() uSession.getRoom(spaceId)?.membershipService()?.loadRoomMembersIfNeeded()
} }
} }
} }

View file

@ -127,7 +127,8 @@ class AutocompleteMemberPresenter @AssistedInject constructor(context: Context,
) )
private fun createMemberItems(queryParams: RoomMemberQueryParams) = private fun createMemberItems(queryParams: RoomMemberQueryParams) =
room.getRoomMembers(queryParams) room.membershipService()
.getRoomMembers(queryParams)
.asSequence() .asSequence()
.sortedBy { it.displayName } .sortedBy { it.displayName }
.disambiguate() .disambiguate()

View file

@ -30,7 +30,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker:
fun nativeRoomForVirtualRoom(roomId: String): String? { fun nativeRoomForVirtualRoom(roomId: String): String? {
if (!protocolsChecker.supportVirtualRooms) return null if (!protocolsChecker.supportVirtualRooms) return null
val virtualRoom = session.getRoom(roomId) ?: return null val virtualRoom = session.getRoom(roomId) ?: return null
val virtualRoomEvent = virtualRoom.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM) val virtualRoomEvent = virtualRoom.roomAccountDataService().getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM)
return virtualRoomEvent?.content?.toModel<RoomVirtualContent>()?.nativeRoomId return virtualRoomEvent?.content?.toModel<RoomVirtualContent>()?.nativeRoomId
} }
@ -79,7 +79,7 @@ class CallUserMapper(private val session: Session, private val protocolsChecker:
private suspend fun Room.markVirtual(nativeRoomId: String) { private suspend fun Room.markVirtual(nativeRoomId: String) {
val virtualRoomContent = RoomVirtualContent(nativeRoomId = nativeRoomId) val virtualRoomContent = RoomVirtualContent(nativeRoomId = nativeRoomId)
updateAccountData(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM, virtualRoomContent.toContent()) roomAccountDataService().updateAccountData(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM, virtualRoomContent.toContent())
} }
private suspend fun ensureVirtualRoomExists(userId: String, nativeRoomId: String): String { private suspend fun ensureVirtualRoomExists(userId: String, nativeRoomId: String): String {

View file

@ -30,7 +30,7 @@ fun WebRtcCall.getOpponentAsMatrixItem(session: Session): MatrixItem? {
roomSummary.toMatrixItem() roomSummary.toMatrixItem()
} else { } else {
val userId = roomSummary.otherMemberIds.first() val userId = roomSummary.otherMemberIds.first()
return room.getRoomMember(userId)?.toMatrixItem() return room.membershipService().getRoomMember(userId)?.toMatrixItem()
} }
} }
} }

View file

@ -174,11 +174,10 @@ class RoomDevToolViewModel @AssistedInject constructor(
val json = adapter.fromJson(state.editedContent ?: "") val json = adapter.fromJson(state.editedContent ?: "")
?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_no_content)) ?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_no_content))
room.sendStateEvent( room.stateService().sendStateEvent(
state.selectedEvent?.type.orEmpty(), state.selectedEvent?.type.orEmpty(),
state.selectedEvent?.stateKey.orEmpty(), state.selectedEvent?.stateKey.orEmpty(),
json json
) )
_viewEvents.post(DevToolsViewEvents.ShowSnackMessage(stringProvider.getString(R.string.dev_tools_success_state_event))) _viewEvents.post(DevToolsViewEvents.ShowSnackMessage(stringProvider.getString(R.string.dev_tools_success_state_event)))
setState { setState {
@ -212,7 +211,7 @@ class RoomDevToolViewModel @AssistedInject constructor(
?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_no_message_type)) ?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_no_message_type))
if (isState) { if (isState) {
room.sendStateEvent( room.stateService().sendStateEvent(
eventType, eventType,
state.sendEventDraft.stateKey.orEmpty(), state.sendEventDraft.stateKey.orEmpty(),
json json
@ -222,7 +221,7 @@ class RoomDevToolViewModel @AssistedInject constructor(
// val validParse = MoshiProvider.providesMoshi().adapter(MessageContent::class.java).fromJson(it.sendEventDraft.content ?: "") // val validParse = MoshiProvider.providesMoshi().adapter(MessageContent::class.java).fromJson(it.sendEventDraft.content ?: "")
json.toModel<MessageContent>(catchError = false) json.toModel<MessageContent>(catchError = false)
?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_malformed_event)) ?: throw IllegalArgumentException(stringProvider.getString(R.string.dev_tools_error_malformed_event))
room.sendEvent( room.sendService().sendEvent(
eventType, eventType,
json json
) )

View file

@ -89,6 +89,8 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.file.FileService
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.initsync.SyncStatusService import org.matrix.android.sdk.api.session.initsync.SyncStatusService
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
@ -183,7 +185,7 @@ class TimelineViewModel @AssistedInject constructor(
setupPreviewUrlObservers() setupPreviewUrlObservers()
room.getRoomSummaryLive() room.getRoomSummaryLive()
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) } tryOrNull { room.readService().markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
} }
// Inform the SDK that the room is displayed // Inform the SDK that the room is displayed
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
@ -194,7 +196,7 @@ class TimelineViewModel @AssistedInject constructor(
chatEffectManager.delegate = this chatEffectManager.delegate = this
// Ensure to share the outbound session keys with all members // Ensure to share the outbound session keys with all members
if (OutboundSessionKeySharingStrategy.WhenEnteringRoom == BuildConfig.outboundSessionKeySharingStrategy && room.isEncrypted()) { if (OutboundSessionKeySharingStrategy.WhenEnteringRoom == BuildConfig.outboundSessionKeySharingStrategy && room.roomCryptoService().isEncrypted()) {
prepareForEncryption() prepareForEncryption()
} }
@ -250,7 +252,7 @@ class TimelineViewModel @AssistedInject constructor(
prepareToEncrypt = Loading() prepareToEncrypt = Loading()
viewModelScope.launch { viewModelScope.launch {
runCatching { runCatching {
room.prepareToEncrypt() room.roomCryptoService().prepareToEncrypt()
}.fold({ }.fold({
prepareToEncrypt = Success(Unit) prepareToEncrypt = Success(Unit)
}, { }, {
@ -354,7 +356,7 @@ class TimelineViewModel @AssistedInject constructor(
private fun markThreadTimelineAsReadLocal() { private fun markThreadTimelineAsReadLocal() {
initialState.rootThreadEventId?.let { initialState.rootThreadEventId?.let {
session.coroutineScope.launch { session.coroutineScope.launch {
room.markThreadAsRead(it) room.threadsLocalService().markThreadAsRead(it)
} }
} }
} }
@ -490,7 +492,7 @@ class TimelineViewModel @AssistedInject constructor(
private fun handleSetNewAvatar(action: RoomDetailAction.SetAvatarAction) { private fun handleSetNewAvatar(action: RoomDetailAction.SetAvatarAction) {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
room.updateAvatar(action.newAvatarUri, action.newAvatarFileName) room.stateService().updateAvatar(action.newAvatarUri, action.newAvatarFileName)
_viewEvents.post(RoomDetailViewEvents.ActionSuccess(action)) _viewEvents.post(RoomDetailViewEvents.ActionSuccess(action))
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure)) _viewEvents.post(RoomDetailViewEvents.ActionFailure(action, failure))
@ -507,7 +509,7 @@ class TimelineViewModel @AssistedInject constructor(
} }
private fun handleJumpToReadReceipt(action: RoomDetailAction.JumpToReadReceipt) { private fun handleJumpToReadReceipt(action: RoomDetailAction.JumpToReadReceipt) {
room.getUserReadReceipt(action.userId) room.readService().getUserReadReceipt(action.userId)
?.let { handleNavigateToEvent(RoomDetailAction.NavigateToEvent(it, true)) } ?.let { handleNavigateToEvent(RoomDetailAction.NavigateToEvent(it, true)) }
} }
@ -519,7 +521,7 @@ class TimelineViewModel @AssistedInject constructor(
eventId = it)) eventId = it))
} ?: action.stickerContent } ?: action.stickerContent
room.sendEvent(EventType.STICKER, content.toContent()) room.sendService().sendEvent(EventType.STICKER, content.toContent())
} }
private fun handleStartCall(action: RoomDetailAction.StartCall) { private fun handleStartCall(action: RoomDetailAction.StartCall) {
@ -639,7 +641,7 @@ class TimelineViewModel @AssistedInject constructor(
if (trackUnreadMessages.getAndSet(false)) { if (trackUnreadMessages.getAndSet(false)) {
mostRecentDisplayedEvent?.root?.eventId?.also { mostRecentDisplayedEvent?.root?.eventId?.also {
session.coroutineScope.launch { session.coroutineScope.launch {
tryOrNull { room.setReadMarker(it) } tryOrNull { room.readService().setReadMarker(it) }
} }
} }
mostRecentDisplayedEvent = null mostRecentDisplayedEvent = null
@ -652,12 +654,12 @@ class TimelineViewModel @AssistedInject constructor(
} }
fun getMember(userId: String): RoomMemberSummary? { fun getMember(userId: String): RoomMemberSummary? {
return room.getRoomMember(userId) return room.membershipService().getRoomMember(userId)
} }
private fun handleComposerFocusChange(action: RoomDetailAction.ComposerFocusChange) { private fun handleComposerFocusChange(action: RoomDetailAction.ComposerFocusChange) {
// Ensure outbound session keys // Ensure outbound session keys
if (OutboundSessionKeySharingStrategy.WhenTyping == BuildConfig.outboundSessionKeySharingStrategy && room.isEncrypted()) { if (OutboundSessionKeySharingStrategy.WhenTyping == BuildConfig.outboundSessionKeySharingStrategy && room.roomCryptoService().isEncrypted()) {
if (action.focused) { if (action.focused) {
// Should we add some rate limit here, or do it only once per model lifecycle? // Should we add some rate limit here, or do it only once per model lifecycle?
prepareForEncryption() prepareForEncryption()
@ -738,36 +740,36 @@ class TimelineViewModel @AssistedInject constructor(
// PRIVATE METHODS ***************************************************************************** // PRIVATE METHODS *****************************************************************************
private fun handleSendReaction(action: RoomDetailAction.SendReaction) { private fun handleSendReaction(action: RoomDetailAction.SendReaction) {
room.sendReaction(action.targetEventId, action.reaction) room.relationService().sendReaction(action.targetEventId, action.reaction)
} }
private fun handleRedactEvent(action: RoomDetailAction.RedactAction) { private fun handleRedactEvent(action: RoomDetailAction.RedactAction) {
val event = room.getTimelineEvent(action.targetEventId) ?: return val event = room.getTimelineEvent(action.targetEventId) ?: return
room.redactEvent(event.root, action.reason) room.sendService().redactEvent(event.root, action.reason)
} }
private fun handleUndoReact(action: RoomDetailAction.UndoReaction) { private fun handleUndoReact(action: RoomDetailAction.UndoReaction) {
viewModelScope.launch { viewModelScope.launch {
tryOrNull { tryOrNull {
room.undoReaction(action.targetEventId, action.reaction) room.relationService().undoReaction(action.targetEventId, action.reaction)
} }
} }
} }
private fun handleUpdateQuickReaction(action: RoomDetailAction.UpdateQuickReactAction) { private fun handleUpdateQuickReaction(action: RoomDetailAction.UpdateQuickReactAction) {
if (action.add) { if (action.add) {
room.sendReaction(action.targetEventId, action.selectedReaction) room.relationService().sendReaction(action.targetEventId, action.selectedReaction)
} else { } else {
viewModelScope.launch { viewModelScope.launch {
tryOrNull { tryOrNull {
room.undoReaction(action.targetEventId, action.selectedReaction) room.relationService().undoReaction(action.targetEventId, action.selectedReaction)
} }
} }
} }
} }
private fun handleSendMedia(action: RoomDetailAction.SendMedia) { private fun handleSendMedia(action: RoomDetailAction.SendMedia) {
room.sendMedias( room.sendService().sendMedias(
action.attachments, action.attachments,
action.compressBeforeSending, action.compressBeforeSending,
emptySet(), emptySet(),
@ -902,8 +904,8 @@ class TimelineViewModel @AssistedInject constructor(
return return
} }
when { when {
it.root.isTextMessage() -> room.resendTextMessage(it) it.root.isTextMessage() -> room.sendService().resendTextMessage(it)
it.root.isAttachmentMessage() -> room.resendMediaMessage(it) it.root.isAttachmentMessage() -> room.sendService().resendMediaMessage(it)
else -> { else -> {
// TODO // TODO
} }
@ -919,13 +921,13 @@ class TimelineViewModel @AssistedInject constructor(
Timber.e("Cannot resend message, it is not failed, Cancel first") Timber.e("Cannot resend message, it is not failed, Cancel first")
return return
} }
room.deleteFailedEcho(it) room.sendService().deleteFailedEcho(it)
} }
} }
private fun handleCancel(action: RoomDetailAction.CancelSend) { private fun handleCancel(action: RoomDetailAction.CancelSend) {
if (action.force) { if (action.force) {
room.cancelSend(action.eventId) room.sendService().cancelSend(action.eventId)
return return
} }
val targetEventId = action.eventId val targetEventId = action.eventId
@ -935,16 +937,16 @@ class TimelineViewModel @AssistedInject constructor(
Timber.e("Cannot cancel message, it is not sending") Timber.e("Cannot cancel message, it is not sending")
return return
} }
room.cancelSend(targetEventId) room.sendService().cancelSend(targetEventId)
} }
} }
private fun handleResendAll() { private fun handleResendAll() {
room.resendAllFailedMessages() room.sendService().resendAllFailedMessages()
} }
private fun handleRemoveAllFailedMessages() { private fun handleRemoveAllFailedMessages() {
room.cancelAllFailedMessages() room.sendService().cancelAllFailedMessages()
} }
private fun observeEventDisplayedActions() { private fun observeEventDisplayedActions() {
@ -967,7 +969,7 @@ class TimelineViewModel @AssistedInject constructor(
} }
bufferedMostRecentDisplayedEvent.root.eventId?.let { eventId -> bufferedMostRecentDisplayedEvent.root.eventId?.let { eventId ->
session.coroutineScope.launch { session.coroutineScope.launch {
tryOrNull { room.setReadReceipt(eventId) } tryOrNull { room.readService().setReadReceipt(eventId) }
} }
} }
} }
@ -984,14 +986,14 @@ class TimelineViewModel @AssistedInject constructor(
private fun handleMarkAllAsRead() { private fun handleMarkAllAsRead() {
setState { copy(unreadState = UnreadState.HasNoUnread) } setState { copy(unreadState = UnreadState.HasNoUnread) }
viewModelScope.launch { viewModelScope.launch {
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.BOTH) } tryOrNull { room.readService().markAsRead(ReadService.MarkAsReadParams.BOTH) }
} }
} }
private fun handleReportContent(action: RoomDetailAction.ReportContent) { private fun handleReportContent(action: RoomDetailAction.ReportContent) {
viewModelScope.launch { viewModelScope.launch {
val event = try { val event = try {
room.reportContent(action.eventId, -100, action.reason) room.reportingService().reportContent(action.eventId, -100, action.reason)
RoomDetailViewEvents.ActionSuccess(action) RoomDetailViewEvents.ActionSuccess(action)
} catch (failure: Exception) { } catch (failure: Exception) {
RoomDetailViewEvents.ActionFailure(action, failure) RoomDetailViewEvents.ActionFailure(action, failure)
@ -1081,13 +1083,13 @@ class TimelineViewModel @AssistedInject constructor(
room.getTimelineEvent(action.eventId)?.let { pollTimelineEvent -> room.getTimelineEvent(action.eventId)?.let { pollTimelineEvent ->
val currentVote = pollTimelineEvent.annotations?.pollResponseSummary?.aggregatedContent?.myVote val currentVote = pollTimelineEvent.annotations?.pollResponseSummary?.aggregatedContent?.myVote
if (currentVote != action.optionKey) { if (currentVote != action.optionKey) {
room.voteToPoll(action.eventId, action.optionKey) room.sendService().voteToPoll(action.eventId, action.optionKey)
} }
} }
} }
private fun handleEndPoll(eventId: String) { private fun handleEndPoll(eventId: String) {
room.endPoll(eventId) room.sendService().endPoll(eventId)
} }
private fun observeSyncState() { private fun observeSyncState() {
@ -1265,7 +1267,7 @@ class TimelineViewModel @AssistedInject constructor(
timeline.removeAllListeners() timeline.removeAllListeners()
decryptionFailureTracker.onTimeLineDisposed(room.roomId) decryptionFailureTracker.onTimeLineDisposed(room.roomId)
if (vectorPreferences.sendTypingNotifs()) { if (vectorPreferences.sendTypingNotifs()) {
room.userStopsTyping() room.typingService().userStopsTyping()
} }
chatEffectManager.delegate = null chatEffectManager.delegate = null
chatEffectManager.dispose() chatEffectManager.dispose()

View file

@ -53,6 +53,8 @@ import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm import org.matrix.android.sdk.api.session.room.model.RoomEncryptionAlgorithm
@ -205,12 +207,12 @@ class MessageComposerViewModel @AssistedInject constructor(
is ParsedCommand.ErrorNotACommand -> { is ParsedCommand.ErrorNotACommand -> {
// Send the text message to the room // Send the text message to the room
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = action.text, replyInThreadText = action.text,
autoMarkdown = action.autoMarkdown) autoMarkdown = action.autoMarkdown)
} else { } else {
room.sendTextMessage(action.text, autoMarkdown = action.autoMarkdown) room.sendService().sendTextMessage(action.text, autoMarkdown = action.autoMarkdown)
} }
_viewEvents.post(MessageComposerViewEvents.MessageSent) _viewEvents.post(MessageComposerViewEvents.MessageSent)
@ -231,12 +233,12 @@ class MessageComposerViewModel @AssistedInject constructor(
is ParsedCommand.SendPlainText -> { is ParsedCommand.SendPlainText -> {
// Send the text message to the room, without markdown // Send the text message to the room, without markdown
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = parsedCommand.message, replyInThreadText = parsedCommand.message,
autoMarkdown = false) autoMarkdown = false)
} else { } else {
room.sendTextMessage(parsedCommand.message, autoMarkdown = false) room.sendService().sendTextMessage(parsedCommand.message, autoMarkdown = false)
} }
_viewEvents.post(MessageComposerViewEvents.MessageSent) _viewEvents.post(MessageComposerViewEvents.MessageSent)
popDraft() popDraft()
@ -286,13 +288,16 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
is ParsedCommand.SendEmote -> { is ParsedCommand.SendEmote -> {
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = parsedCommand.message, replyInThreadText = parsedCommand.message,
msgType = MessageType.MSGTYPE_EMOTE, msgType = MessageType.MSGTYPE_EMOTE,
autoMarkdown = action.autoMarkdown) autoMarkdown = action.autoMarkdown)
} else { } else {
room.sendTextMessage(parsedCommand.message, msgType = MessageType.MSGTYPE_EMOTE, autoMarkdown = action.autoMarkdown) room.sendService().sendTextMessage(
text = parsedCommand.message,
msgType = MessageType.MSGTYPE_EMOTE,
autoMarkdown = action.autoMarkdown)
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
@ -300,12 +305,12 @@ class MessageComposerViewModel @AssistedInject constructor(
is ParsedCommand.SendRainbow -> { is ParsedCommand.SendRainbow -> {
val message = parsedCommand.message.toString() val message = parsedCommand.message.toString()
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = parsedCommand.message, replyInThreadText = parsedCommand.message,
formattedText = rainbowGenerator.generate(message)) formattedText = rainbowGenerator.generate(message))
} else { } else {
room.sendFormattedTextMessage(message, rainbowGenerator.generate(message)) room.sendService().sendFormattedTextMessage(message, rainbowGenerator.generate(message))
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
@ -313,13 +318,13 @@ class MessageComposerViewModel @AssistedInject constructor(
is ParsedCommand.SendRainbowEmote -> { is ParsedCommand.SendRainbowEmote -> {
val message = parsedCommand.message.toString() val message = parsedCommand.message.toString()
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = parsedCommand.message, replyInThreadText = parsedCommand.message,
msgType = MessageType.MSGTYPE_EMOTE, msgType = MessageType.MSGTYPE_EMOTE,
formattedText = rainbowGenerator.generate(message)) formattedText = rainbowGenerator.generate(message))
} else { } else {
room.sendFormattedTextMessage(message, rainbowGenerator.generate(message), MessageType.MSGTYPE_EMOTE) room.sendService().sendFormattedTextMessage(message, rainbowGenerator.generate(message), MessageType.MSGTYPE_EMOTE)
} }
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
@ -329,12 +334,12 @@ class MessageComposerViewModel @AssistedInject constructor(
val text = "[${stringProvider.getString(R.string.spoiler)}](${parsedCommand.message})" val text = "[${stringProvider.getString(R.string.spoiler)}](${parsedCommand.message})"
val formattedText = "<span data-mx-spoiler>${parsedCommand.message}</span>" val formattedText = "<span data-mx-spoiler>${parsedCommand.message}</span>"
if (state.rootThreadEventId != null) { if (state.rootThreadEventId != null) {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = state.rootThreadEventId, rootThreadEventId = state.rootThreadEventId,
replyInThreadText = text, replyInThreadText = text,
formattedText = formattedText) formattedText = formattedText)
} else { } else {
room.sendFormattedTextMessage( room.sendService().sendFormattedTextMessage(
text, text,
formattedText) formattedText)
} }
@ -377,7 +382,7 @@ class MessageComposerViewModel @AssistedInject constructor(
popDraft() popDraft()
} }
is ParsedCommand.DiscardSession -> { is ParsedCommand.DiscardSession -> {
if (room.isEncrypted()) { if (room.roomCryptoService().isEncrypted()) {
session.cryptoService().discardOutboundSession(room.roomId) session.cryptoService().discardOutboundSession(room.roomId)
_viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand))
popDraft() popDraft()
@ -489,13 +494,13 @@ class MessageComposerViewModel @AssistedInject constructor(
if (inReplyTo != null) { if (inReplyTo != null) {
// TODO check if same content? // TODO check if same content?
room.getTimelineEvent(inReplyTo)?.let { room.getTimelineEvent(inReplyTo)?.let {
room.editReply(state.sendMode.timelineEvent, it, action.text.toString()) room.relationService().editReply(state.sendMode.timelineEvent, it, action.text.toString())
} }
} else { } else {
val messageContent = state.sendMode.timelineEvent.getLastMessageContent() val messageContent = state.sendMode.timelineEvent.getLastMessageContent()
val existingBody = messageContent?.body ?: "" val existingBody = messageContent?.body ?: ""
if (existingBody != action.text) { if (existingBody != action.text) {
room.editTextMessage(state.sendMode.timelineEvent, room.relationService().editTextMessage(state.sendMode.timelineEvent,
messageContent?.msgType ?: MessageType.MSGTYPE_TEXT, messageContent?.msgType ?: MessageType.MSGTYPE_TEXT,
action.text, action.text,
action.autoMarkdown) action.autoMarkdown)
@ -507,7 +512,7 @@ class MessageComposerViewModel @AssistedInject constructor(
popDraft() popDraft()
} }
is SendMode.Quote -> { is SendMode.Quote -> {
room.sendQuotedTextMessage( room.sendService().sendQuotedTextMessage(
quotedEvent = state.sendMode.timelineEvent, quotedEvent = state.sendMode.timelineEvent,
text = action.text.toString(), text = action.text.toString(),
autoMarkdown = action.autoMarkdown, autoMarkdown = action.autoMarkdown,
@ -521,12 +526,12 @@ class MessageComposerViewModel @AssistedInject constructor(
// If threads are disabled this will make the fallback replies visible to clients with threads enabled // If threads are disabled this will make the fallback replies visible to clients with threads enabled
val rootThreadEventId = if (showInThread) timelineEvent.root.getRootThreadEventId() else null val rootThreadEventId = if (showInThread) timelineEvent.root.getRootThreadEventId() else null
state.rootThreadEventId?.let { state.rootThreadEventId?.let {
room.replyInThread( room.relationService().replyInThread(
rootThreadEventId = it, rootThreadEventId = it,
replyInThreadText = action.text.toString(), replyInThreadText = action.text.toString(),
autoMarkdown = action.autoMarkdown, autoMarkdown = action.autoMarkdown,
eventReplied = timelineEvent) eventReplied = timelineEvent)
} ?: room.replyToMessage( } ?: room.relationService().replyToMessage(
eventReplied = timelineEvent, eventReplied = timelineEvent,
replyText = action.text.toString(), replyText = action.text.toString(),
autoMarkdown = action.autoMarkdown, autoMarkdown = action.autoMarkdown,
@ -552,13 +557,13 @@ class MessageComposerViewModel @AssistedInject constructor(
// Otherwise we clear the composer and remove the draft from db // Otherwise we clear the composer and remove the draft from db
setState { copy(sendMode = SendMode.Regular("", false)) } setState { copy(sendMode = SendMode.Regular("", false)) }
viewModelScope.launch { viewModelScope.launch {
room.deleteDraft() room.draftService().deleteDraft()
} }
} }
} }
private fun loadDraftIfAny() { private fun loadDraftIfAny() {
val currentDraft = room.getDraft() val currentDraft = room.draftService().getDraft()
setState { setState {
copy( copy(
// Create a sendMode from a draft and retrieve the TimelineEvent // Create a sendMode from a draft and retrieve the TimelineEvent
@ -589,9 +594,9 @@ class MessageComposerViewModel @AssistedInject constructor(
private fun handleUserIsTyping(action: MessageComposerAction.UserIsTyping) { private fun handleUserIsTyping(action: MessageComposerAction.UserIsTyping) {
if (vectorPreferences.sendTypingNotifs()) { if (vectorPreferences.sendTypingNotifs()) {
if (action.isTyping) { if (action.isTyping) {
room.userIsTyping() room.typingService().userIsTyping()
} else { } else {
room.userStopsTyping() room.typingService().userStopsTyping()
} }
} }
} }
@ -603,9 +608,9 @@ class MessageComposerViewModel @AssistedInject constructor(
ChatEffect.CONFETTI -> R.string.default_message_emote_confetti ChatEffect.CONFETTI -> R.string.default_message_emote_confetti
ChatEffect.SNOWFALL -> R.string.default_message_emote_snow ChatEffect.SNOWFALL -> R.string.default_message_emote_snow
}) })
room.sendTextMessage(defaultMessage, MessageType.MSGTYPE_EMOTE) room.sendService().sendTextMessage(defaultMessage, MessageType.MSGTYPE_EMOTE)
} else { } else {
room.sendTextMessage(sendChatEffect.message, sendChatEffect.chatEffect.toMessageType()) room.sendService().sendTextMessage(sendChatEffect.message, sendChatEffect.chatEffect.toMessageType())
} }
} }
@ -648,19 +653,19 @@ class MessageComposerViewModel @AssistedInject constructor(
private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) { private fun handleChangeTopicSlashCommand(changeTopic: ParsedCommand.ChangeTopic) {
launchSlashCommandFlowSuspendable(changeTopic) { launchSlashCommandFlowSuspendable(changeTopic) {
room.updateTopic(changeTopic.topic) room.stateService().updateTopic(changeTopic.topic)
} }
} }
private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) { private fun handleInviteSlashCommand(invite: ParsedCommand.Invite) {
launchSlashCommandFlowSuspendable(invite) { launchSlashCommandFlowSuspendable(invite) {
room.invite(invite.userId, invite.reason) room.membershipService().invite(invite.userId, invite.reason)
} }
} }
private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) { private fun handleInvite3pidSlashCommand(invite: ParsedCommand.Invite3Pid) {
launchSlashCommandFlowSuspendable(invite) { launchSlashCommandFlowSuspendable(invite) {
room.invite3pid(invite.threePid) room.membershipService().invite3pid(invite.threePid)
} }
} }
@ -673,7 +678,7 @@ class MessageComposerViewModel @AssistedInject constructor(
?: return ?: return
launchSlashCommandFlowSuspendable(setUserPowerLevel) { launchSlashCommandFlowSuspendable(setUserPowerLevel) {
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent) room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent)
} }
} }
@ -701,25 +706,25 @@ class MessageComposerViewModel @AssistedInject constructor(
private fun handleRemoveSlashCommand(removeUser: ParsedCommand.RemoveUser) { private fun handleRemoveSlashCommand(removeUser: ParsedCommand.RemoveUser) {
launchSlashCommandFlowSuspendable(removeUser) { launchSlashCommandFlowSuspendable(removeUser) {
room.remove(removeUser.userId, removeUser.reason) room.membershipService().remove(removeUser.userId, removeUser.reason)
} }
} }
private fun handleBanSlashCommand(ban: ParsedCommand.BanUser) { private fun handleBanSlashCommand(ban: ParsedCommand.BanUser) {
launchSlashCommandFlowSuspendable(ban) { launchSlashCommandFlowSuspendable(ban) {
room.ban(ban.userId, ban.reason) room.membershipService().ban(ban.userId, ban.reason)
} }
} }
private fun handleUnbanSlashCommand(unban: ParsedCommand.UnbanUser) { private fun handleUnbanSlashCommand(unban: ParsedCommand.UnbanUser) {
launchSlashCommandFlowSuspendable(unban) { launchSlashCommandFlowSuspendable(unban) {
room.unban(unban.userId, unban.reason) room.membershipService().unban(unban.userId, unban.reason)
} }
} }
private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) { private fun handleChangeRoomNameSlashCommand(changeRoomName: ParsedCommand.ChangeRoomName) {
launchSlashCommandFlowSuspendable(changeRoomName) { launchSlashCommandFlowSuspendable(changeRoomName) {
room.updateName(changeRoomName.name) room.stateService().updateName(changeRoomName.name)
} }
} }
@ -735,14 +740,14 @@ class MessageComposerViewModel @AssistedInject constructor(
?.copy(displayName = changeDisplayName.displayName) ?.copy(displayName = changeDisplayName.displayName)
?.toContent() ?.toContent()
?.let { ?.let {
room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) room.stateService().sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it)
} }
} }
} }
private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) { private fun handleChangeRoomAvatarSlashCommand(changeAvatar: ParsedCommand.ChangeRoomAvatar) {
launchSlashCommandFlowSuspendable(changeAvatar) { launchSlashCommandFlowSuspendable(changeAvatar) {
room.sendStateEvent(EventType.STATE_ROOM_AVATAR, stateKey = "", RoomAvatarContent(changeAvatar.url).toContent()) room.stateService().sendStateEvent(EventType.STATE_ROOM_AVATAR, stateKey = "", RoomAvatarContent(changeAvatar.url).toContent())
} }
} }
@ -752,7 +757,7 @@ class MessageComposerViewModel @AssistedInject constructor(
?.copy(avatarUrl = changeAvatar.url) ?.copy(avatarUrl = changeAvatar.url)
?.toContent() ?.toContent()
?.let { ?.let {
room.sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it) room.stateService().sendStateEvent(EventType.STATE_ROOM_MEMBER, session.myUserId, it)
} }
} }
} }
@ -793,8 +798,8 @@ class MessageComposerViewModel @AssistedInject constructor(
} }
} }
rootThreadEventId?.let { rootThreadEventId?.let {
room.replyInThread(it, sequence) room.relationService().replyInThread(it, sequence)
} ?: room.sendTextMessage(sequence) } ?: room.sendService().sendTextMessage(sequence)
} }
/** /**
@ -805,19 +810,19 @@ class MessageComposerViewModel @AssistedInject constructor(
when { when {
it.sendMode is SendMode.Regular && !it.sendMode.fromSharing -> { it.sendMode is SendMode.Regular && !it.sendMode.fromSharing -> {
setState { copy(sendMode = it.sendMode.copy(text = draft)) } setState { copy(sendMode = it.sendMode.copy(text = draft)) }
room.saveDraft(UserDraft.Regular(draft)) room.draftService().saveDraft(UserDraft.Regular(draft))
} }
it.sendMode is SendMode.Reply -> { it.sendMode is SendMode.Reply -> {
setState { copy(sendMode = it.sendMode.copy(text = draft)) } setState { copy(sendMode = it.sendMode.copy(text = draft)) }
room.saveDraft(UserDraft.Reply(it.sendMode.timelineEvent.root.eventId!!, draft)) room.draftService().saveDraft(UserDraft.Reply(it.sendMode.timelineEvent.root.eventId!!, draft))
} }
it.sendMode is SendMode.Quote -> { it.sendMode is SendMode.Quote -> {
setState { copy(sendMode = it.sendMode.copy(text = draft)) } setState { copy(sendMode = it.sendMode.copy(text = draft)) }
room.saveDraft(UserDraft.Quote(it.sendMode.timelineEvent.root.eventId!!, draft)) room.draftService().saveDraft(UserDraft.Quote(it.sendMode.timelineEvent.root.eventId!!, draft))
} }
it.sendMode is SendMode.Edit -> { it.sendMode is SendMode.Edit -> {
setState { copy(sendMode = it.sendMode.copy(text = draft)) } setState { copy(sendMode = it.sendMode.copy(text = draft)) }
room.saveDraft(UserDraft.Edit(it.sendMode.timelineEvent.root.eventId!!, draft)) room.draftService().saveDraft(UserDraft.Edit(it.sendMode.timelineEvent.root.eventId!!, draft))
} }
} }
} }
@ -838,7 +843,7 @@ class MessageComposerViewModel @AssistedInject constructor(
} else { } else {
audioMessageHelper.stopRecording(convertForSending = true)?.let { audioType -> audioMessageHelper.stopRecording(convertForSending = true)?.let { audioType ->
if (audioType.duration > 1000) { if (audioType.duration > 1000) {
room.sendMedia( room.sendService().sendMedia(
attachment = audioType.toContentAttachmentData(isVoiceMessage = true), attachment = audioType.toContentAttachmentData(isVoiceMessage = true),
compressBeforeSending = false, compressBeforeSending = false,
roomIds = emptySet(), roomIds = emptySet(),
@ -905,7 +910,7 @@ class MessageComposerViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
playingAudioContent?.toContentAttachmentData()?.let { voiceDraft -> playingAudioContent?.toContentAttachmentData()?.let { voiceDraft ->
val content = voiceDraft.toJsonString() val content = voiceDraft.toJsonString()
room.saveDraft(UserDraft.Voice(content)) room.draftService().saveDraft(UserDraft.Voice(content))
setState { copy(sendMode = SendMode.Voice(content)) } setState { copy(sendMode = SendMode.Voice(content)) }
} }
} }

View file

@ -62,7 +62,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
val data = try { val data = try {
room.fetchEditHistory(eventId) room.relationService().fetchEditHistory(eventId)
} catch (failure: Throwable) { } catch (failure: Throwable) {
setState { setState {
copy(editList = Fail(failure)) copy(editList = Fail(failure))

View file

@ -39,6 +39,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper

View file

@ -45,18 +45,18 @@ class TimelineFactory @Inject constructor(private val session: Session, private
val settings = timelineSettingsFactory.create(rootThreadEventId) val settings = timelineSettingsFactory.create(rootThreadEventId)
if (!session.vectorCallService.protocolChecker.supportVirtualRooms) { if (!session.vectorCallService.protocolChecker.supportVirtualRooms) {
return mainRoom.createTimeline(eventId, settings) return mainRoom.timelineService().createTimeline(eventId, settings)
} }
val virtualRoomId = session.vectorCallService.userMapper.virtualRoomForNativeRoom(mainRoom.roomId) val virtualRoomId = session.vectorCallService.userMapper.virtualRoomForNativeRoom(mainRoom.roomId)
return if (virtualRoomId == null) { return if (virtualRoomId == null) {
mainRoom.createTimeline(eventId, settings) mainRoom.timelineService().createTimeline(eventId, settings)
} else { } else {
val virtualRoom = session.getRoom(virtualRoomId)!! val virtualRoom = session.getRoom(virtualRoomId)!!
MergedTimelines( MergedTimelines(
coroutineScope = coroutineScope, coroutineScope = coroutineScope,
mainTimeline = mainRoom.createTimeline(eventId, settings), mainTimeline = mainRoom.timelineService().createTimeline(eventId, settings),
secondaryTimelineParams = MergedTimelines.SecondaryTimelineParams( secondaryTimelineParams = MergedTimelines.SecondaryTimelineParams(
timeline = virtualRoom.createTimeline(null, settings), timeline = virtualRoom.timelineService().createTimeline(null, settings),
shouldFilterTypes = true, shouldFilterTypes = true,
allowedTypes = secondaryTimelineAllowedTypes allowedTypes = secondaryTimelineAllowedTypes
) )

View file

@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.RelationType import org.matrix.android.sdk.api.session.events.model.RelationType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent
import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationCancelContent import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationCancelContent
import javax.inject.Inject import javax.inject.Inject

View file

@ -34,6 +34,7 @@ import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFrag
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.flow.flow import org.matrix.android.sdk.flow.flow
import org.matrix.android.sdk.flow.unwrap import org.matrix.android.sdk.flow.unwrap

View file

@ -43,7 +43,7 @@ class MigrateRoomViewModel @AssistedInject constructor(
val summary = session.getRoomSummary(initialState.roomId) val summary = session.getRoomSummary(initialState.roomId)
setState { setState {
copy( copy(
currentVersion = room?.getRoomVersion(), currentVersion = room?.roomVersionService()?.getRoomVersion(),
isPublic = summary?.isPublic ?: false, isPublic = summary?.isPublic ?: false,
otherMemberCount = summary?.otherMemberIds?.count() ?: 0, otherMemberCount = summary?.otherMemberIds?.count() ?: 0,
knownParents = summary?.flattenParentIds ?: emptyList() knownParents = summary?.flattenParentIds ?: emptyList()

View file

@ -50,12 +50,12 @@ class UpgradeRoomViewModelTask @Inject constructor(
val room = session.getRoom(params.roomId) val room = session.getRoom(params.roomId)
?: return Result.UnknownRoom ?: return Result.UnknownRoom
if (!room.userMayUpgradeRoom(session.myUserId)) { if (!room.roomVersionService().userMayUpgradeRoom(session.myUserId)) {
return Result.NotAllowed return Result.NotAllowed
} }
val updatedRoomId = try { val updatedRoomId = try {
room.upgradeToVersion(params.newVersion) room.roomVersionService().upgradeToVersion(params.newVersion)
} catch (failure: Throwable) { } catch (failure: Throwable) {
return Result.ErrorFailure(failure) return Result.ErrorFailure(failure)
} }
@ -65,7 +65,7 @@ class UpgradeRoomViewModelTask @Inject constructor(
params.userIdsToAutoInvite.forEach { params.userIdsToAutoInvite.forEach {
params.progressReporter?.invoke(false, currentStep, totalStep) params.progressReporter?.invoke(false, currentStep, totalStep)
tryOrNull { tryOrNull {
session.getRoom(updatedRoomId)?.invite(it) session.getRoom(updatedRoomId)?.membershipService()?.invite(it)
} }
currentStep++ currentStep++
} }

View file

@ -170,7 +170,7 @@ class RoomListViewModel @AssistedInject constructor(
} }
fun isPublicRoom(roomId: String): Boolean { fun isPublicRoom(roomId: String): Boolean {
return session.getRoom(roomId)?.isPublic().orFalse() return session.getRoom(roomId)?.stateService()?.isPublic().orFalse()
} }
// PRIVATE METHODS ***************************************************************************** // PRIVATE METHODS *****************************************************************************
@ -254,7 +254,7 @@ class RoomListViewModel @AssistedInject constructor(
if (room != null) { if (room != null) {
viewModelScope.launch { viewModelScope.launch {
try { try {
room.setRoomNotificationState(action.notificationState) room.roomPushRuleService().setRoomNotificationState(action.notificationState)
} catch (failure: Exception) { } catch (failure: Exception) {
_viewEvents.post(RoomListViewEvents.Failure(failure)) _viewEvents.post(RoomListViewEvents.Failure(failure))
} }
@ -299,13 +299,13 @@ class RoomListViewModel @AssistedInject constructor(
action.tag.otherTag() action.tag.otherTag()
?.takeIf { room.roomSummary()?.hasTag(it).orFalse() } ?.takeIf { room.roomSummary()?.hasTag(it).orFalse() }
?.let { tagToRemove -> ?.let { tagToRemove ->
room.deleteTag(tagToRemove) room.tagsService().deleteTag(tagToRemove)
} }
// Set the tag. We do not handle the order for the moment // Set the tag. We do not handle the order for the moment
room.addTag(action.tag, 0.5) room.tagsService().addTag(action.tag, 0.5)
} else { } else {
room.deleteTag(action.tag) room.tagsService().deleteTag(action.tag)
} }
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomListViewEvents.Failure(failure)) _viewEvents.post(RoomListViewEvents.Failure(failure))

View file

@ -85,7 +85,7 @@ class ThreadListViewModel @AssistedInject constructor(@Assisted val initialState
private fun observeThreadSummaries() { private fun observeThreadSummaries() {
room?.flow() room?.flow()
?.liveThreadSummaries() ?.liveThreadSummaries()
?.map { room.enhanceThreadWithEditions(it) } ?.map { room.threadsService().enhanceThreadWithEditions(it) }
?.flowOn(room.coroutineDispatchers.io) ?.flowOn(room.coroutineDispatchers.io)
?.execute { asyncThreads -> ?.execute { asyncThreads ->
copy(threadSummaryList = asyncThreads) copy(threadSummaryList = asyncThreads)
@ -99,10 +99,10 @@ class ThreadListViewModel @AssistedInject constructor(@Assisted val initialState
private fun observeThreadsList() { private fun observeThreadsList() {
room?.flow() room?.flow()
?.liveThreadList() ?.liveThreadList()
?.map { room.mapEventsWithEdition(it) } ?.map { room.threadsLocalService().mapEventsWithEdition(it) }
?.map { ?.map {
it.map { threadRootEvent -> it.map { threadRootEvent ->
val isParticipating = room.isUserParticipatingInThread(threadRootEvent.eventId) val isParticipating = room.threadsLocalService().isUserParticipatingInThread(threadRootEvent.eventId)
ThreadTimelineEvent(threadRootEvent, isParticipating) ThreadTimelineEvent(threadRootEvent, isParticipating)
} }
} }
@ -115,7 +115,7 @@ class ThreadListViewModel @AssistedInject constructor(@Assisted val initialState
private fun fetchThreadList() { private fun fetchThreadList() {
viewModelScope.launch { viewModelScope.launch {
setLoading(true) setLoading(true)
room?.fetchThreadSummaries() room?.threadsService()?.fetchThreadSummaries()
setLoading(false) setLoading(false)
} }
} }

View file

@ -60,8 +60,8 @@ class InviteUsersToRoomViewModel @AssistedInject constructor(
selections.asFlow() selections.asFlow()
.map { user -> .map { user ->
when (user) { when (user) {
is PendingSelection.UserPendingSelection -> room.invite(user.user.userId, null) is PendingSelection.UserPendingSelection -> room.membershipService().invite(user.user.userId, null)
is PendingSelection.ThreePidPendingSelection -> room.invite3pid(user.threePid) is PendingSelection.ThreePidPendingSelection -> room.membershipService().invite3pid(user.threePid)
} }
} }
.catch { cause -> .catch { cause ->

View file

@ -105,6 +105,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
val stateKey = session.myUserId val stateKey = session.myUserId
session session
.getRoom(roomArgs.roomId) .getRoom(roomArgs.roomId)
?.stateService()
?.sendStateEvent( ?.sendStateEvent(
eventType = EventType.STATE_ROOM_BEACON_INFO.first(), eventType = EventType.STATE_ROOM_BEACON_INFO.first(),
stateKey = stateKey, stateKey = stateKey,
@ -147,7 +148,7 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
.getSafeActiveSession() .getSafeActiveSession()
?.let { session -> ?.let { session ->
session.coroutineScope.launch(session.coroutineDispatchers.io) { session.coroutineScope.launch(session.coroutineDispatchers.io) {
session.getRoom(roomId)?.stopLiveLocation(session.myUserId) session.getRoom(roomId)?.stateService()?.stopLiveLocation(session.myUserId)
} }
} }
} }
@ -174,10 +175,11 @@ class LocationSharingService : VectorService(), LocationTracker.Callback {
} }
room room
.stateService()
.getLiveLocationBeaconInfo(userId, true) .getLiveLocationBeaconInfo(userId, true)
?.eventId ?.eventId
?.let { ?.let {
room.sendLiveLocation( room.sendService().sendLiveLocation(
beaconInfoEventId = it, beaconInfoEventId = it,
latitude = locationData.latitude, latitude = locationData.latitude,
longitude = locationData.longitude, longitude = locationData.longitude,

View file

@ -136,7 +136,7 @@ class LocationSharingViewModel @AssistedInject constructor(
private fun shareLocation(locationData: LocationData?, isUserLocation: Boolean) { private fun shareLocation(locationData: LocationData?, isUserLocation: Boolean) {
locationData?.let { location -> locationData?.let { location ->
room.sendLocation( room.sendService().sendLocation(
latitude = location.latitude, latitude = location.latitude,
longitude = location.longitude, longitude = location.longitude,
uncertainty = location.uncertainty, uncertainty = location.uncertainty,

View file

@ -23,6 +23,7 @@ import kotlinx.coroutines.CoroutineScope
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.file.FileService
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.util.MimeTypes import org.matrix.android.sdk.api.util.MimeTypes
import java.io.File import java.io.File

View file

@ -135,7 +135,7 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), AttachmentInt
initialIndex = inMemoryData.indexOfFirst { it.eventId == args.eventId }.coerceAtLeast(0) initialIndex = inMemoryData.indexOfFirst { it.eventId == args.eventId }.coerceAtLeast(0)
dataSourceFactory.createProvider(inMemoryData, room, lifecycleScope) dataSourceFactory.createProvider(inMemoryData, room, lifecycleScope)
} else { } else {
val events = room?.getAttachmentMessages().orEmpty() val events = room?.timelineService()?.getAttachmentMessages().orEmpty()
initialIndex = events.indexOfFirst { it.eventId == args.eventId }.coerceAtLeast(0) initialIndex = events.indexOfFirst { it.eventId == args.eventId }.coerceAtLeast(0)
dataSourceFactory.createProvider(events, lifecycleScope) dataSourceFactory.createProvider(events, lifecycleScope)
} }

View file

@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.getUser import org.matrix.android.sdk.api.session.getUser
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent

View file

@ -106,7 +106,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
val room = session.getRoom(roomId) val room = session.getRoom(roomId)
if (room != null) { if (room != null) {
session.coroutineScope.launch { session.coroutineScope.launch {
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) } tryOrNull { room.readService().markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
} }
} }
} }
@ -129,7 +129,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() {
} }
private fun sendMatrixEvent(message: String, session: Session, room: Room, context: Context?) { private fun sendMatrixEvent(message: String, session: Session, room: Room, context: Context?) {
room.sendTextMessage(message) room.sendService().sendTextMessage(message)
// Create a new event to be displayed in the notification drawer, right now // Create a new event to be displayed in the notification drawer, right now

View file

@ -35,7 +35,7 @@ class OutdatedEventDetector @Inject constructor(
val eventID = notifiableEvent.eventId val eventID = notifiableEvent.eventId
val roomID = notifiableEvent.roomId val roomID = notifiableEvent.roomId
val room = session.getRoom(roomID) ?: return false val room = session.getRoom(roomID) ?: return false
return room.isEventRead(eventID) return room.readService().isEventRead(eventID)
} }
return false return false
} }

View file

@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.permalinks.PermalinkData import org.matrix.android.sdk.api.session.permalinks.PermalinkData
import org.matrix.android.sdk.api.session.permalinks.PermalinkParser import org.matrix.android.sdk.api.session.permalinks.PermalinkParser
import org.matrix.android.sdk.api.session.permalinks.PermalinkService import org.matrix.android.sdk.api.session.permalinks.PermalinkService
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.RoomType

View file

@ -26,6 +26,7 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.poll.PollMode import im.vector.app.features.poll.PollMode
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getTimelineEvent
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
import org.matrix.android.sdk.api.session.room.model.message.PollType import org.matrix.android.sdk.api.session.room.model.message.PollType
import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent
@ -109,7 +110,7 @@ class CreatePollViewModel @AssistedInject constructor(
} }
else -> { else -> {
when (state.mode) { when (state.mode) {
PollMode.CREATE -> room.sendPoll(state.pollType, state.question, nonEmptyOptions) PollMode.CREATE -> room.sendService().sendPoll(state.pollType, state.question, nonEmptyOptions)
PollMode.EDIT -> sendEditedPoll(state.editedEventId!!, state.pollType, state.question, nonEmptyOptions) PollMode.EDIT -> sendEditedPoll(state.editedEventId!!, state.pollType, state.question, nonEmptyOptions)
} }
_viewEvents.post(CreatePollViewEvents.Success) _viewEvents.post(CreatePollViewEvents.Success)
@ -119,7 +120,7 @@ class CreatePollViewModel @AssistedInject constructor(
private fun sendEditedPoll(editedEventId: String, pollType: PollType, question: String, options: List<String>) { private fun sendEditedPoll(editedEventId: String, pollType: PollType, question: String, options: List<String>) {
val editedEvent = room.getTimelineEvent(editedEventId) ?: return val editedEvent = room.getTimelineEvent(editedEventId) ?: return
room.editPoll(editedEvent, pollType, question, options) room.relationService().editPoll(editedEvent, pollType, question, options)
} }
private fun handleOnAddOption() { private fun handleOnAddOption() {

View file

@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.Room import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.api.util.Optional
@ -93,7 +94,7 @@ class RequireActiveMembershipViewModel @AssistedInject constructor(
} }
val senderId = room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId))?.senderId val senderId = room.getStateEvent(EventType.STATE_ROOM_MEMBER, QueryStringValue.Equals(session.myUserId))?.senderId
val senderDisplayName = senderId?.takeIf { it != session.myUserId }?.let { val senderDisplayName = senderId?.takeIf { it != session.myUserId }?.let {
room.getRoomMember(it)?.displayName ?: it room.membershipService().getRoomMember(it)?.displayName ?: it
} }
val viewEvent = when (roomSummary.membership) { val viewEvent = when (roomSummary.membership) {
Membership.LEAVE -> { Membership.LEAVE -> {

View file

@ -87,8 +87,8 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
setState { setState {
copy( copy(
isMine = session.myUserId == this.userId, isMine = session.myUserId == this.userId,
userMatrixItem = room?.getRoomMember(initialState.userId)?.toMatrixItem()?.let { Success(it) } ?: Uninitialized, userMatrixItem = room?.membershipService()?.getRoomMember(initialState.userId)?.toMatrixItem()?.let { Success(it) } ?: Uninitialized,
hasReadReceipt = room?.getUserReadReceipt(initialState.userId) != null, hasReadReceipt = room?.readService()?.getUserReadReceipt(initialState.userId) != null,
isSpace = room?.roomSummary()?.roomType == RoomType.SPACE isSpace = room?.roomSummary()?.roomType == RoomType.SPACE
) )
} }
@ -97,7 +97,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
viewModelScope.launch(Dispatchers.Main) { viewModelScope.launch(Dispatchers.Main) {
// Do we have a room member for this id. // Do we have a room member for this id.
val roomMember = withContext(Dispatchers.Default) { val roomMember = withContext(Dispatchers.Default) {
room?.getRoomMember(initialState.userId) room?.membershipService()?.getRoomMember(initialState.userId)
} }
// If not, we look for profile info on the server // If not, we look for profile info on the server
if (room == null || roomMember == null) { if (room == null || roomMember == null) {
@ -228,7 +228,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
_viewEvents.post(RoomMemberProfileViewEvents.Loading()) _viewEvents.post(RoomMemberProfileViewEvents.Loading())
try { try {
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent) room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent)
_viewEvents.post(RoomMemberProfileViewEvents.OnSetPowerLevelSuccess) _viewEvents.post(RoomMemberProfileViewEvents.OnSetPowerLevelSuccess)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure)) _viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
@ -257,7 +257,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
try { try {
_viewEvents.post(RoomMemberProfileViewEvents.Loading()) _viewEvents.post(RoomMemberProfileViewEvents.Loading())
room.invite(initialState.userId) room.membershipService().invite(initialState.userId)
_viewEvents.post(RoomMemberProfileViewEvents.OnInviteActionSuccess) _viewEvents.post(RoomMemberProfileViewEvents.OnInviteActionSuccess)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure)) _viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
@ -272,7 +272,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
try { try {
_viewEvents.post(RoomMemberProfileViewEvents.Loading()) _viewEvents.post(RoomMemberProfileViewEvents.Loading())
room.remove(initialState.userId, action.reason) room.membershipService().remove(initialState.userId, action.reason)
_viewEvents.post(RoomMemberProfileViewEvents.OnKickActionSuccess) _viewEvents.post(RoomMemberProfileViewEvents.OnKickActionSuccess)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomMemberProfileViewEvents.Failure(failure)) _viewEvents.post(RoomMemberProfileViewEvents.Failure(failure))
@ -289,9 +289,9 @@ class RoomMemberProfileViewModel @AssistedInject constructor(
try { try {
_viewEvents.post(RoomMemberProfileViewEvents.Loading()) _viewEvents.post(RoomMemberProfileViewEvents.Loading())
if (membership == Membership.BAN) { if (membership == Membership.BAN) {
room.unban(initialState.userId, action.reason) room.membershipService().unban(initialState.userId, action.reason)
} else { } else {
room.ban(initialState.userId, action.reason) room.membershipService().ban(initialState.userId, action.reason)
} }
_viewEvents.post(RoomMemberProfileViewEvents.OnBanActionSuccess) _viewEvents.post(RoomMemberProfileViewEvents.OnBanActionSuccess)
} catch (failure: Throwable) { } catch (failure: Throwable) {

View file

@ -40,6 +40,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
@ -97,9 +98,9 @@ class RoomProfileViewModel @AssistedInject constructor(
copy( copy(
roomCreateContent = async, roomCreateContent = async,
// This is a shortcut, we should do the next lines elsewhere, but keep it like that for the moment. // This is a shortcut, we should do the next lines elsewhere, but keep it like that for the moment.
recommendedRoomVersion = room.getRecommendedVersion(), recommendedRoomVersion = room.roomVersionService().getRecommendedVersion(),
isUsingUnstableRoomVersion = room.isUsingUnstableRoomVersion(), isUsingUnstableRoomVersion = room.roomVersionService().isUsingUnstableRoomVersion(),
canUpgradeRoom = room.userMayUpgradeRoom(session.myUserId), canUpgradeRoom = room.roomVersionService().userMayUpgradeRoom(session.myUserId),
isTombstoned = room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE) != null isTombstoned = room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE) != null
) )
} }
@ -144,14 +145,14 @@ class RoomProfileViewModel @AssistedInject constructor(
} }
fun isPublicRoom(): Boolean { fun isPublicRoom(): Boolean {
return room.isPublic() return room.stateService().isPublic()
} }
private fun handleEnableEncryption() { private fun handleEnableEncryption() {
postLoading(true) postLoading(true)
viewModelScope.launch { viewModelScope.launch {
val result = runCatching { room.enableEncryption() } val result = runCatching { room.roomCryptoService().enableEncryption() }
postLoading(false) postLoading(false)
result.onFailure { failure -> result.onFailure { failure ->
_viewEvents.post(RoomProfileViewEvents.Failure(failure)) _viewEvents.post(RoomProfileViewEvents.Failure(failure))
@ -178,7 +179,7 @@ class RoomProfileViewModel @AssistedInject constructor(
private fun handleChangeNotificationMode(action: RoomProfileAction.ChangeRoomNotificationState) { private fun handleChangeNotificationMode(action: RoomProfileAction.ChangeRoomNotificationState) {
viewModelScope.launch { viewModelScope.launch {
try { try {
room.setRoomNotificationState(action.notificationState) room.roomPushRuleService().setRoomNotificationState(action.notificationState)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomProfileViewEvents.Failure(failure)) _viewEvents.post(RoomProfileViewEvents.Failure(failure))
} }
@ -213,7 +214,7 @@ class RoomProfileViewModel @AssistedInject constructor(
_viewEvents.post(RoomProfileViewEvents.Loading()) _viewEvents.post(RoomProfileViewEvents.Loading())
session.coroutineScope.launch { session.coroutineScope.launch {
try { try {
room.enableEncryption(force = true) room.roomCryptoService().enableEncryption(force = true)
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.e(failure, "Failed to restore encryption state in room ${room.roomId}") Timber.e(failure, "Failed to restore encryption state in room ${room.roomId}")
_viewEvents.post(RoomProfileViewEvents.Failure(failure)) _viewEvents.post(RoomProfileViewEvents.Failure(failure))

View file

@ -109,7 +109,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo
} }
viewModelScope.launch { viewModelScope.launch {
runCatching { room.getRoomAliases() } runCatching { room.aliasService().getRoomAliases() }
.fold( .fold(
{ {
setState { copy(localAliases = Success(it.sorted())) } setState { copy(localAliases = Success(it.sorted())) }
@ -304,7 +304,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo
postLoading(true) postLoading(true)
viewModelScope.launch { viewModelScope.launch {
try { try {
room.updateCanonicalAlias(canonicalAlias, alternativeAliases) room.stateService().updateCanonicalAlias(canonicalAlias, alternativeAliases)
setState { setState {
copy( copy(
isLoading = false, isLoading = false,
@ -328,7 +328,7 @@ class RoomAliasViewModel @AssistedInject constructor(@Assisted initialState: Roo
) )
} }
viewModelScope.launch { viewModelScope.launch {
runCatching { room.addAlias(previousState.value) } runCatching { room.aliasService().addAlias(previousState.value) }
.onFailure { .onFailure {
setState { setState {
copy( copy(

View file

@ -33,6 +33,7 @@ import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.RoomMemberContent
@ -115,7 +116,7 @@ class RoomBannedMemberListViewModel @AssistedInject constructor(@Assisted initia
} }
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
room.unban(roomMemberSummary.userId, null) room.membershipService().unban(roomMemberSummary.userId, null)
} catch (failure: Throwable) { } catch (failure: Throwable) {
_viewEvents.post(RoomBannedMemberListViewEvents.ToastError(stringProvider.getString(R.string.failed_to_unban))) _viewEvents.post(RoomBannedMemberListViewEvents.ToastError(stringProvider.getString(R.string.failed_to_unban)))
} finally { } finally {

View file

@ -92,7 +92,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
copy(roomMemberSummaries = async) copy(roomMemberSummaries = async)
} }
if (room.isEncrypted()) { if (room.roomCryptoService().isEncrypted()) {
room.flow().liveRoomMembers(roomMemberQueryParams) room.flow().liveRoomMembers(roomMemberQueryParams)
.flatMapLatest { membersSummary -> .flatMapLatest { membersSummary ->
session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId }) session.cryptoService().getLiveCryptoDeviceInfo(membersSummary.map { it.userId })
@ -197,7 +197,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
private fun handleRevokeThreePidInvite(action: RoomMemberListAction.RevokeThreePidInvite) { private fun handleRevokeThreePidInvite(action: RoomMemberListAction.RevokeThreePidInvite) {
viewModelScope.launch { viewModelScope.launch {
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.STATE_ROOM_THIRD_PARTY_INVITE, eventType = EventType.STATE_ROOM_THIRD_PARTY_INVITE,
stateKey = action.stateKey, stateKey = action.stateKey,
body = emptyMap() body = emptyMap()

View file

@ -74,7 +74,7 @@ class RoomNotificationSettingsViewModel @AssistedInject constructor(
private fun handleSelectNotificationState(action: RoomNotificationSettingsAction.SelectNotificationState) { private fun handleSelectNotificationState(action: RoomNotificationSettingsAction.SelectNotificationState) {
setState { copy(isLoading = true) } setState { copy(isLoading = true) }
viewModelScope.launch { viewModelScope.launch {
runCatching { room.setRoomNotificationState(action.notificationState) } runCatching { room.roomPushRuleService().setRoomNotificationState(action.notificationState) }
.fold( .fold(
{ {
setState { setState {

View file

@ -124,7 +124,7 @@ class RoomPermissionsViewModel @AssistedInject constructor(@Assisted initialStat
} }
) )
} }
room.sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent.toContent()) room.stateService().sendStateEvent(EventType.STATE_ROOM_POWER_LEVELS, stateKey = "", newPowerLevelsContent.toContent())
setState { setState {
copy( copy(
isLoading = false isLoading = false

View file

@ -70,7 +70,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
val homeServerCapabilities = session.homeServerCapabilitiesService().getHomeServerCapabilities() val homeServerCapabilities = session.homeServerCapabilitiesService().getHomeServerCapabilities()
val canUseRestricted = homeServerCapabilities val canUseRestricted = homeServerCapabilities
.isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED, room.getRoomVersion()) .isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED, room.roomVersionService().getRoomVersion())
val restrictedSupport = homeServerCapabilities.isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED) val restrictedSupport = homeServerCapabilities.isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED)
val couldUpgradeToRestricted = restrictedSupport == HomeServerCapabilities.RoomCapabilitySupport.SUPPORTED val couldUpgradeToRestricted = restrictedSupport == HomeServerCapabilities.RoomCapabilitySupport.SUPPORTED
@ -249,25 +249,25 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
when (val avatarAction = state.avatarAction) { when (val avatarAction = state.avatarAction) {
RoomSettingsViewState.AvatarAction.None -> Unit RoomSettingsViewState.AvatarAction.None -> Unit
RoomSettingsViewState.AvatarAction.DeleteAvatar -> { RoomSettingsViewState.AvatarAction.DeleteAvatar -> {
operationList.add { room.deleteAvatar() } operationList.add { room.stateService().deleteAvatar() }
} }
is RoomSettingsViewState.AvatarAction.UpdateAvatar -> { is RoomSettingsViewState.AvatarAction.UpdateAvatar -> {
operationList.add { room.updateAvatar(avatarAction.newAvatarUri, avatarAction.newAvatarFileName) } operationList.add { room.stateService().updateAvatar(avatarAction.newAvatarUri, avatarAction.newAvatarFileName) }
} }
} }
if (summary?.name != state.newName) { if (summary?.name != state.newName) {
operationList.add { room.updateName(state.newName ?: "") } operationList.add { room.stateService().updateName(state.newName ?: "") }
} }
if (summary?.topic != state.newTopic) { if (summary?.topic != state.newTopic) {
operationList.add { room.updateTopic(state.newTopic ?: "") } operationList.add { room.stateService().updateTopic(state.newTopic ?: "") }
} }
if (state.newHistoryVisibility != null) { if (state.newHistoryVisibility != null) {
operationList.add { room.updateHistoryReadability(state.newHistoryVisibility) } operationList.add { room.stateService().updateHistoryReadability(state.newHistoryVisibility) }
} }
if (state.newRoomJoinRules.hasChanged()) { if (state.newRoomJoinRules.hasChanged()) {
operationList.add { room.updateJoinRule(state.newRoomJoinRules.newJoinRules, state.newRoomJoinRules.newGuestAccess) } operationList.add { room.stateService().updateJoinRule(state.newRoomJoinRules.newJoinRules, state.newRoomJoinRules.newGuestAccess) }
} }
viewModelScope.launch { viewModelScope.launch {
updateLoadingState(isLoading = true) updateLoadingState(isLoading = true)

View file

@ -43,6 +43,7 @@ import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.getRoomSummary import org.matrix.android.sdk.api.session.getRoomSummary
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomJoinRules import org.matrix.android.sdk.api.session.room.model.RoomJoinRules
import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesContent
@ -103,7 +104,7 @@ class RoomJoinRuleChooseRestrictedViewModel @AssistedInject constructor(
var safeRule: RoomJoinRules = joinRulesContent?.joinRules ?: RoomJoinRules.INVITE var safeRule: RoomJoinRules = joinRulesContent?.joinRules ?: RoomJoinRules.INVITE
// server is not really checking that, just to be sure let's check // server is not really checking that, just to be sure let's check
val restrictedSupportedByThisVersion = homeServerCapabilities val restrictedSupportedByThisVersion = homeServerCapabilities
.isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED, room.getRoomVersion()) .isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED, room.roomVersionService().getRoomVersion())
if (safeRule == RoomJoinRules.RESTRICTED && if (safeRule == RoomJoinRules.RESTRICTED &&
!restrictedSupportedByThisVersion) { !restrictedSupportedByThisVersion) {
safeRule = RoomJoinRules.INVITE safeRule = RoomJoinRules.INVITE
@ -191,9 +192,9 @@ class RoomJoinRuleChooseRestrictedViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
try { try {
when (state.currentRoomJoinRules) { when (state.currentRoomJoinRules) {
RoomJoinRules.PUBLIC -> room.setJoinRulePublic() RoomJoinRules.PUBLIC -> room.stateService().setJoinRulePublic()
RoomJoinRules.INVITE -> room.setJoinRuleInviteOnly() RoomJoinRules.INVITE -> room.stateService().setJoinRuleInviteOnly()
RoomJoinRules.RESTRICTED -> room.setJoinRuleRestricted(state.updatedAllowList.map { it.id }) RoomJoinRules.RESTRICTED -> room.stateService().setJoinRuleRestricted(state.updatedAllowList.map { it.id })
RoomJoinRules.KNOCK, RoomJoinRules.KNOCK,
RoomJoinRules.PRIVATE, RoomJoinRules.PRIVATE,
null -> { null -> {
@ -294,7 +295,7 @@ class RoomJoinRuleChooseRestrictedViewModel @AssistedInject constructor(
setState { copy(updatingStatus = Loading()) } setState { copy(updatingStatus = Loading()) }
viewModelScope.launch { viewModelScope.launch {
try { try {
room.setJoinRuleRestricted(candidates.map { it.id }) room.stateService().setJoinRuleRestricted(candidates.map { it.id })
setState { copy(updatingStatus = Success(Unit)) } setState { copy(updatingStatus = Success(Unit)) }
} catch (failure: Throwable) { } catch (failure: Throwable) {
setState { copy(updatingStatus = Fail(failure)) } setState { copy(updatingStatus = Fail(failure)) }

View file

@ -73,7 +73,7 @@ class RoomUploadsViewModel @AssistedInject constructor(
viewModelScope.launch { viewModelScope.launch {
try { try {
val result = room.getUploads(20, token) val result = room.uploadsService().getUploads(20, token)
token = result.nextToken token = result.nextToken

View file

@ -119,7 +119,7 @@ class IncomingShareViewModel @AssistedInject constructor(
is SharedData.Text -> { is SharedData.Text -> {
state.selectedRoomIds.forEach { roomId -> state.selectedRoomIds.forEach { roomId ->
val room = session.getRoom(roomId) val room = session.getRoom(roomId)
room?.sendTextMessage(sharedData.text) room?.sendService()?.sendTextMessage(sharedData.text)
} }
// This is it, pass the first roomId to let the screen open it // This is it, pass the first roomId to let the screen open it
_viewEvents.post(IncomingShareViewEvents.MultipleRoomsShareDone(state.selectedRoomIds.first())) _viewEvents.post(IncomingShareViewEvents.MultipleRoomsShareDone(state.selectedRoomIds.first()))
@ -153,6 +153,7 @@ class IncomingShareViewModel @AssistedInject constructor(
// Pick the first room to send the media // Pick the first room to send the media
selectedRoomIds.firstOrNull() selectedRoomIds.firstOrNull()
?.let { roomId -> session.getRoom(roomId) } ?.let { roomId -> session.getRoom(roomId) }
?.sendService()
?.sendMedias(grouped.notPreviewables, compressMediaBeforeSending, selectedRoomIds) ?.sendMedias(grouped.notPreviewables, compressMediaBeforeSending, selectedRoomIds)
// Ensure they will not be sent twice // Ensure they will not be sent twice
@ -173,6 +174,7 @@ class IncomingShareViewModel @AssistedInject constructor(
// Pick the first room to send the media // Pick the first room to send the media
selectedRoomIds.firstOrNull() selectedRoomIds.firstOrNull()
?.let { roomId -> session.getRoom(roomId) } ?.let { roomId -> session.getRoom(roomId) }
?.sendService()
?.sendMedias(attachmentData, compressMediaBeforeSending, selectedRoomIds) ?.sendMedias(attachmentData, compressMediaBeforeSending, selectedRoomIds)
// This is it, pass the first roomId to let the screen open it // This is it, pass the first roomId to let the screen open it
_viewEvents.post(IncomingShareViewEvents.MultipleRoomsShareDone(selectedRoomIds.first())) _viewEvents.post(IncomingShareViewEvents.MultipleRoomsShareDone(selectedRoomIds.first()))

View file

@ -212,7 +212,7 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
} }
session.coroutineScope.launch { session.coroutineScope.launch {
orderCommands.forEach { orderCommands.forEach {
session.getRoom(it.spaceId)?.updateAccountData( session.getRoom(it.spaceId)?.roomAccountDataService()?.updateAccountData(
RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER, RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER,
SpaceOrderContent(order = it.order).toContent() SpaceOrderContent(order = it.order).toContent()
) )
@ -292,6 +292,7 @@ class SpaceListViewModel @AssistedInject constructor(@Assisted initialState: Spa
val rootSpaces = async.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() } val rootSpaces = async.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() }
val orders = rootSpaces.associate { val orders = rootSpaces.associate {
it.roomId to session.getRoom(it.roomId) it.roomId to session.getRoom(it.roomId)
?.roomAccountDataService()
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER) ?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
?.content.toModel<SpaceOrderContent>() ?.content.toModel<SpaceOrderContent>()
?.safeOrder() ?.safeOrder()

View file

@ -34,6 +34,7 @@ import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.getRoom
import org.matrix.android.sdk.api.session.room.getStateEvent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
@ -117,7 +118,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
} }
val userId = eventData["user_id"] as String val userId = eventData["user_id"] as String
Timber.d("Received request to get options for bot $userId in room $roomId requested") Timber.d("Received request to get options for bot $userId in room $roomId requested")
val stateEvents = room.getStateEvents(setOf(EventType.BOT_OPTIONS)) val stateEvents = room.stateService().getStateEvents(setOf(EventType.BOT_OPTIONS))
var botOptionsEvent: Event? = null var botOptionsEvent: Event? = null
val stateKey = "_$userId" val stateKey = "_$userId"
for (stateEvent in stateEvents) { for (stateEvent in stateEvents) {
@ -196,7 +197,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
return return
} }
Timber.d("Received request join rules in room $roomId") Timber.d("Received request join rules in room $roomId")
val joinedEvents = room.getStateEvents(setOf(EventType.STATE_ROOM_JOIN_RULES)) val joinedEvents = room.stateService().getStateEvents(setOf(EventType.STATE_ROOM_JOIN_RULES))
if (joinedEvents.isNotEmpty()) { if (joinedEvents.isNotEmpty()) {
widgetPostAPIMediator.sendObjectResponse(Event::class.java, joinedEvents.last(), eventData) widgetPostAPIMediator.sendObjectResponse(Event::class.java, joinedEvents.last(), eventData)
} else { } else {
@ -316,7 +317,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
val params = HashMap<String, Any>() val params = HashMap<String, Any>()
params["status"] = status params["status"] = status
launchWidgetAPIAction(widgetPostAPIMediator, eventData) { launchWidgetAPIAction(widgetPostAPIMediator, eventData) {
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.PLUMBING, eventType = EventType.PLUMBING,
stateKey = "", stateKey = "",
body = params body = params
@ -341,7 +342,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
val stateKey = "_$userId" val stateKey = "_$userId"
launchWidgetAPIAction(widgetPostAPIMediator, eventData) { launchWidgetAPIAction(widgetPostAPIMediator, eventData) {
room.sendStateEvent( room.stateService().sendStateEvent(
eventType = EventType.BOT_OPTIONS, eventType = EventType.BOT_OPTIONS,
stateKey = stateKey, stateKey = stateKey,
body = content body = content
@ -383,12 +384,12 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
val userId = eventData["user_id"] as String val userId = eventData["user_id"] as String
val description = "Received request to invite $userId into room $roomId" val description = "Received request to invite $userId into room $roomId"
Timber.d(description) Timber.d(description)
val member = room.getRoomMember(userId) val member = room.membershipService().getRoomMember(userId)
if (member != null && member.membership == Membership.JOIN) { if (member != null && member.membership == Membership.JOIN) {
widgetPostAPIMediator.sendSuccess(eventData) widgetPostAPIMediator.sendSuccess(eventData)
} else { } else {
launchWidgetAPIAction(widgetPostAPIMediator, eventData) { launchWidgetAPIAction(widgetPostAPIMediator, eventData) {
room.invite(userId = userId) room.membershipService().invite(userId = userId)
} }
} }
} }
@ -402,7 +403,7 @@ class WidgetPostAPIHandler @AssistedInject constructor(@Assisted private val roo
if (checkRoomId(widgetPostAPIMediator, eventData)) { if (checkRoomId(widgetPostAPIMediator, eventData)) {
return return
} }
val numberOfJoinedMembers = room.getNumberOfJoinedMembers() val numberOfJoinedMembers = room.membershipService().getNumberOfJoinedMembers()
widgetPostAPIMediator.sendIntegerResponse(numberOfJoinedMembers, eventData) widgetPostAPIMediator.sendIntegerResponse(numberOfJoinedMembers, eventData)
} }