Creates a Widget Manager to be used internally and state event service
This commit is contained in:
parent
4fdd2f4eed
commit
b047f36e86
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.rx
|
package im.vector.matrix.rx
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.Room
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
import im.vector.matrix.android.api.session.room.members.RoomMemberQueryParams
|
import im.vector.matrix.android.api.session.room.members.RoomMemberQueryParams
|
||||||
|
@ -60,7 +61,7 @@ class RxRoom(private val room: Room) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun liveStateEvent(eventType: String, stateKey: String): Observable<Optional<Event>> {
|
fun liveStateEvent(eventType: String, stateKey: QueryStringValue): Observable<Optional<Event>> {
|
||||||
return room.getStateEventLive(eventType, stateKey).asObservable()
|
return room.getStateEventLive(eventType, stateKey).asObservable()
|
||||||
.startWithCallable {
|
.startWithCallable {
|
||||||
room.getStateEvent(eventType, stateKey).toOptional()
|
room.getStateEvent(eventType, stateKey).toOptional()
|
||||||
|
|
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.api.session.room.state
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.util.Optional
|
import im.vector.matrix.android.api.util.Optional
|
||||||
|
|
||||||
|
@ -28,7 +29,11 @@ interface StateService {
|
||||||
*/
|
*/
|
||||||
fun updateTopic(topic: String, callback: MatrixCallback<Unit>)
|
fun updateTopic(topic: String, callback: MatrixCallback<Unit>)
|
||||||
|
|
||||||
fun getStateEvent(eventType: String, stateKey: String): Event?
|
fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event?
|
||||||
|
|
||||||
fun getStateEventLive(eventType: String, stateKey: String): LiveData<Optional<Event>>
|
fun getStateEventLive(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<Optional<Event>>
|
||||||
|
|
||||||
|
fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): List<Event>
|
||||||
|
|
||||||
|
fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue = QueryStringValue.NoCondition): LiveData<List<Event>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
import io.realm.kotlin.createObject
|
import io.realm.kotlin.createObject
|
||||||
|
|
||||||
internal fun CurrentStateEventEntity.Companion.where(realm: Realm, roomId: String, type: String): RealmQuery<CurrentStateEventEntity> {
|
internal fun CurrentStateEventEntity.Companion.whereType(realm: Realm, roomId: String, type: String): RealmQuery<CurrentStateEventEntity> {
|
||||||
return realm.where(CurrentStateEventEntity::class.java)
|
return realm.where(CurrentStateEventEntity::class.java)
|
||||||
.equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
|
.equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
|
||||||
.equalTo(CurrentStateEventEntityFields.TYPE, type)
|
.equalTo(CurrentStateEventEntityFields.TYPE, type)
|
||||||
|
@ -31,7 +31,7 @@ internal fun CurrentStateEventEntity.Companion.where(realm: Realm, roomId: Strin
|
||||||
|
|
||||||
internal fun CurrentStateEventEntity.Companion.whereStateKey(realm: Realm, roomId: String, type: String, stateKey: String)
|
internal fun CurrentStateEventEntity.Companion.whereStateKey(realm: Realm, roomId: String, type: String, stateKey: String)
|
||||||
: RealmQuery<CurrentStateEventEntity> {
|
: RealmQuery<CurrentStateEventEntity> {
|
||||||
return where(realm = realm, roomId = roomId, type = type)
|
return whereType(realm = realm, roomId = roomId, type = type)
|
||||||
.equalTo(CurrentStateEventEntityFields.STATE_KEY, stateKey)
|
.equalTo(CurrentStateEventEntityFields.STATE_KEY, stateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.api.pushrules.ContainsDisplayNameCondition
|
||||||
import im.vector.matrix.android.api.pushrules.EventMatchCondition
|
import im.vector.matrix.android.api.pushrules.EventMatchCondition
|
||||||
import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition
|
import im.vector.matrix.android.api.pushrules.RoomMemberCountCondition
|
||||||
import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition
|
import im.vector.matrix.android.api.pushrules.SenderNotificationPermissionCondition
|
||||||
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
@ -48,7 +49,7 @@ internal class DefaultConditionResolver @Inject constructor(
|
||||||
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 powerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS, "")
|
val powerLevelsContent = room.getStateEvent(EventType.STATE_ROOM_POWER_LEVELS)
|
||||||
?.content
|
?.content
|
||||||
?.toModel<PowerLevelsContent>()
|
?.toModel<PowerLevelsContent>()
|
||||||
?: PowerLevelsContent()
|
?: PowerLevelsContent()
|
||||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.model.create.JoinRoomResponse
|
||||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsParams
|
||||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoomsResponse
|
||||||
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
|
import im.vector.matrix.android.api.session.room.model.thirdparty.ThirdPartyProtocol
|
||||||
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||||
import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription
|
import im.vector.matrix.android.internal.session.room.alias.RoomAliasDescription
|
||||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse
|
import im.vector.matrix.android.internal.session.room.membership.RoomMembersResponse
|
||||||
|
@ -175,7 +176,7 @@ internal interface RoomAPI {
|
||||||
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}")
|
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/state/{state_event_type}")
|
||||||
fun sendStateEvent(@Path("roomId") roomId: String,
|
fun sendStateEvent(@Path("roomId") roomId: String,
|
||||||
@Path("state_event_type") stateEventType: String,
|
@Path("state_event_type") stateEventType: String,
|
||||||
@Body params: Map<String, String>): Call<Unit>
|
@Body params: JsonDict): Call<Unit>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a generic state events
|
* Send a generic state events
|
||||||
|
@ -189,7 +190,7 @@ internal interface RoomAPI {
|
||||||
fun sendStateEvent(@Path("roomId") roomId: String,
|
fun sendStateEvent(@Path("roomId") roomId: String,
|
||||||
@Path("state_event_type") stateEventType: String,
|
@Path("state_event_type") stateEventType: String,
|
||||||
@Path("state_key") stateKey: String,
|
@Path("state_key") stateKey: String,
|
||||||
@Body params: Map<String, String>): Call<Unit>
|
@Body params: JsonDict): Call<Unit>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a relation event to a room.
|
* Send a relation event to a room.
|
||||||
|
|
|
@ -17,26 +17,19 @@
|
||||||
package im.vector.matrix.android.internal.session.room.state
|
package im.vector.matrix.android.internal.session.room.state
|
||||||
|
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.Transformations
|
|
||||||
import com.squareup.inject.assisted.Assisted
|
import com.squareup.inject.assisted.Assisted
|
||||||
import com.squareup.inject.assisted.AssistedInject
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
import com.zhuinden.monarchy.Monarchy
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.room.state.StateService
|
import im.vector.matrix.android.api.session.room.state.StateService
|
||||||
import im.vector.matrix.android.api.util.Optional
|
import im.vector.matrix.android.api.util.Optional
|
||||||
import im.vector.matrix.android.api.util.toOptional
|
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
|
||||||
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
|
|
||||||
import im.vector.matrix.android.internal.database.query.getOrNull
|
|
||||||
import im.vector.matrix.android.internal.database.query.whereStateKey
|
|
||||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
import im.vector.matrix.android.internal.task.configureWith
|
import im.vector.matrix.android.internal.task.configureWith
|
||||||
import io.realm.Realm
|
|
||||||
|
|
||||||
internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
|
internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||||
private val monarchy: Monarchy,
|
private val stateEventDataSource: StateEventDataSource,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val sendStateTask: SendStateTask
|
private val sendStateTask: SendStateTask
|
||||||
) : StateService {
|
) : StateService {
|
||||||
|
@ -46,20 +39,20 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
||||||
fun create(roomId: String): StateService
|
fun create(roomId: String): StateService
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStateEvent(eventType: String, stateKey: String): Event? {
|
override fun getStateEvent(eventType: String, stateKey: QueryStringValue): Event? {
|
||||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
return stateEventDataSource.getStateEvent(roomId, eventType, stateKey)
|
||||||
CurrentStateEventEntity.getOrNull(realm, roomId, type = eventType, stateKey = stateKey)?.root?.asDomain()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStateEventLive(eventType: String, stateKey: String): LiveData<Optional<Event>> {
|
override fun getStateEventLive(eventType: String, stateKey: QueryStringValue): LiveData<Optional<Event>> {
|
||||||
val liveData = monarchy.findAllMappedWithChanges(
|
return stateEventDataSource.getStateEventLive(roomId, eventType, stateKey)
|
||||||
{ realm -> CurrentStateEventEntity.whereStateKey(realm, roomId, type = eventType, stateKey = "") },
|
}
|
||||||
{ it.root?.asDomain() }
|
|
||||||
)
|
override fun getStateEvents(eventTypes: Set<String>, stateKey: QueryStringValue): List<Event> {
|
||||||
return Transformations.map(liveData) { results ->
|
return stateEventDataSource.getStateEvents(roomId, eventTypes, stateKey)
|
||||||
results.firstOrNull().toOptional()
|
}
|
||||||
}
|
|
||||||
|
override fun getStateEventsLive(eventTypes: Set<String>, stateKey: QueryStringValue): LiveData<List<Event>> {
|
||||||
|
return stateEventDataSource.getStateEventsLive(roomId, eventTypes, stateKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateTopic(topic: String, callback: MatrixCallback<Unit>) {
|
override fun updateTopic(topic: String, callback: MatrixCallback<Unit>) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.matrix.android.internal.session.room.state
|
package im.vector.matrix.android.internal.session.room.state
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.util.JsonDict
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
import im.vector.matrix.android.internal.task.Task
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
@ -26,7 +27,7 @@ internal interface SendStateTask : Task<SendStateTask.Params, Unit> {
|
||||||
data class Params(
|
data class Params(
|
||||||
val roomId: String,
|
val roomId: String,
|
||||||
val eventType: String,
|
val eventType: String,
|
||||||
val body: Map<String, String>
|
val body: JsonDict
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.room.state
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.Transformations
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.api.util.Optional
|
||||||
|
import im.vector.matrix.android.api.util.toOptional
|
||||||
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
|
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntityFields
|
||||||
|
import im.vector.matrix.android.internal.query.process
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmQuery
|
||||||
|
import io.realm.kotlin.where
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal class StateEventDataSource @Inject constructor(private val monarchy: Monarchy) {
|
||||||
|
|
||||||
|
fun getStateEvent(roomId: String, eventType: String, stateKey: QueryStringValue): Event? {
|
||||||
|
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||||
|
buildStateEventQuery(realm, roomId, setOf(eventType), stateKey).findFirst()?.root?.asDomain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStateEventLive(roomId: String, eventType: String, stateKey: QueryStringValue): LiveData<Optional<Event>> {
|
||||||
|
val liveData = monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm -> buildStateEventQuery(realm, roomId, setOf(eventType), stateKey) },
|
||||||
|
{ it.root?.asDomain() }
|
||||||
|
)
|
||||||
|
return Transformations.map(liveData) { results ->
|
||||||
|
results.firstOrNull().toOptional()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStateEvents(roomId: String, eventTypes: Set<String>, stateKey: QueryStringValue): List<Event> {
|
||||||
|
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||||
|
buildStateEventQuery(realm, roomId, eventTypes, stateKey)
|
||||||
|
.findAll()
|
||||||
|
.mapNotNull {
|
||||||
|
it.root?.asDomain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStateEventsLive(roomId: String, eventTypes: Set<String>, stateKey: QueryStringValue): LiveData<List<Event>> {
|
||||||
|
val liveData = monarchy.findAllMappedWithChanges(
|
||||||
|
{ realm -> buildStateEventQuery(realm, roomId, eventTypes, stateKey) },
|
||||||
|
{ it.root?.asDomain() }
|
||||||
|
)
|
||||||
|
return Transformations.map(liveData) { results ->
|
||||||
|
results.filterNotNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildStateEventQuery(realm: Realm,
|
||||||
|
roomId: String,
|
||||||
|
eventTypes: Set<String>,
|
||||||
|
stateKey: QueryStringValue
|
||||||
|
): RealmQuery<CurrentStateEventEntity> {
|
||||||
|
return realm.where<CurrentStateEventEntity>()
|
||||||
|
.equalTo(CurrentStateEventEntityFields.ROOM_ID, roomId)
|
||||||
|
.`in`(CurrentStateEventEntityFields.TYPE, eventTypes.toTypedArray())
|
||||||
|
.process(CurrentStateEventEntityFields.STATE_KEY, stateKey)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.widgets
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.failure.Failure
|
||||||
|
|
||||||
|
sealed class CreateWidgetFailure : Failure.FeatureFailure() {
|
||||||
|
object NotEnoughtPower : CreateWidgetFailure()
|
||||||
|
object CreationFailed : CreateWidgetFailure()
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.widgets
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
|
import im.vector.matrix.android.internal.database.awaitNotEmptyResult
|
||||||
|
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity
|
||||||
|
import im.vector.matrix.android.internal.database.model.CurrentStateEventEntityFields
|
||||||
|
import im.vector.matrix.android.internal.database.query.whereStateKey
|
||||||
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
|
import im.vector.matrix.android.internal.task.Task
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal interface CreateWidgetTask : Task<CreateWidgetTask.Params, Unit> {
|
||||||
|
|
||||||
|
data class Params(
|
||||||
|
val roomId: String,
|
||||||
|
val widgetId: String,
|
||||||
|
val content: Content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultCreateWidgetTask @Inject constructor(private val monarchy: Monarchy,
|
||||||
|
private val roomAPI: RoomAPI,
|
||||||
|
@UserId private val userId: String,
|
||||||
|
private val eventBus: EventBus) : CreateWidgetTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: CreateWidgetTask.Params) {
|
||||||
|
executeRequest<Unit>(eventBus) {
|
||||||
|
apiCall = roomAPI.sendStateEvent(
|
||||||
|
roomId = params.roomId,
|
||||||
|
stateEventType = WidgetManager.WIDGET_EVENT_TYPE,
|
||||||
|
stateKey = params.widgetId,
|
||||||
|
params = params.content
|
||||||
|
)
|
||||||
|
}
|
||||||
|
awaitNotEmptyResult(monarchy.realmConfiguration, 30_000L) {
|
||||||
|
CurrentStateEventEntity
|
||||||
|
.whereStateKey(it, params.roomId, type = WidgetManager.WIDGET_EVENT_TYPE, stateKey = params.widgetId)
|
||||||
|
.and()
|
||||||
|
.equalTo(CurrentStateEventEntityFields.ROOT.SENDER, userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.widgets
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.api.session.widgets.model.WidgetContent
|
||||||
|
|
||||||
|
data class Widget(
|
||||||
|
private val widgetContent: WidgetContent,
|
||||||
|
private val event: Event
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.widgets
|
||||||
|
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.LifecycleRegistry
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.query.QueryStringValue
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Content
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
import im.vector.matrix.android.api.session.room.model.PowerLevelsContent
|
||||||
|
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
|
||||||
|
import im.vector.matrix.android.api.session.widgets.model.WidgetContent
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.internal.di.UserId
|
||||||
|
import im.vector.matrix.android.internal.session.SessionScope
|
||||||
|
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
|
||||||
|
import im.vector.matrix.android.internal.session.room.state.StateEventDataSource
|
||||||
|
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||||
|
import im.vector.matrix.android.internal.task.launchToCallback
|
||||||
|
import java.util.HashMap
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@SessionScope
|
||||||
|
internal class WidgetManager @Inject constructor(private val integrationManager: IntegrationManager,
|
||||||
|
private val stateEventDataSource: StateEventDataSource,
|
||||||
|
private val taskExecutor: TaskExecutor,
|
||||||
|
private val createWidgetTask: CreateWidgetTask,
|
||||||
|
@UserId private val userId: String) : IntegrationManager.Listener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val WIDGET_EVENT_TYPE = "im.vector.modular.widgets"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val lifecycleOwner: LifecycleOwner = LifecycleOwner { lifecycleRegistry }
|
||||||
|
private val lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(lifecycleOwner)
|
||||||
|
|
||||||
|
fun start() {
|
||||||
|
lifecycleRegistry.currentState = Lifecycle.State.STARTED
|
||||||
|
integrationManager.addListener(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop() {
|
||||||
|
integrationManager.removeListener(this)
|
||||||
|
lifecycleRegistry.currentState = Lifecycle.State.DESTROYED
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getRoomWidgets(
|
||||||
|
roomId: String,
|
||||||
|
widgetId: QueryStringValue = QueryStringValue.NoCondition,
|
||||||
|
widgetTypes: Set<String>? = null,
|
||||||
|
excludedTypes: Set<String>? = null
|
||||||
|
): List<Widget> {
|
||||||
|
// Get all im.vector.modular.widgets state events in the room
|
||||||
|
val widgetEvents: List<Event> = stateEventDataSource.getStateEvents(roomId, setOf(WIDGET_EVENT_TYPE), widgetId)
|
||||||
|
// Widget id -> widget
|
||||||
|
val widgets: MutableMap<String, Widget> = HashMap()
|
||||||
|
// Order widgetEvents with the last event first
|
||||||
|
// There can be several im.vector.modular.widgets state events for a same widget but
|
||||||
|
// only the last one must be considered.
|
||||||
|
val sortedWidgetEvents = widgetEvents.sortedByDescending {
|
||||||
|
it.originServerTs
|
||||||
|
}
|
||||||
|
// Create each widget from its latest im.vector.modular.widgets state event
|
||||||
|
for (widgetEvent in sortedWidgetEvents) { // Filter widget types if required
|
||||||
|
val widgetContent = widgetEvent.content.toModel<WidgetContent>()
|
||||||
|
if (widgetContent?.url == null) continue
|
||||||
|
val widgetType = widgetContent.type ?: continue
|
||||||
|
if (widgetTypes != null && !widgetTypes.contains(widgetType)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (excludedTypes != null && excludedTypes.contains(widgetType)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// widgetEvent.stateKey = widget id
|
||||||
|
if (widgetEvent.stateKey != null && !widgets.containsKey(widgetEvent.stateKey)) {
|
||||||
|
val widget = Widget(widgetContent, widgetEvent)
|
||||||
|
widgets[widgetEvent.stateKey] = widget
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return widgets.values.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createWidget(roomId: String, widgetId: String, content: Content, callback: MatrixCallback<Widget>): Cancelable {
|
||||||
|
return taskExecutor.executorScope.launchToCallback(callback = callback) {
|
||||||
|
if (!hasPermissionsToHandleWidgets(roomId)) {
|
||||||
|
throw CreateWidgetFailure.NotEnoughtPower
|
||||||
|
}
|
||||||
|
val params = CreateWidgetTask.Params(
|
||||||
|
roomId = roomId,
|
||||||
|
widgetId = widgetId,
|
||||||
|
content = content
|
||||||
|
)
|
||||||
|
createWidgetTask.execute(params)
|
||||||
|
try {
|
||||||
|
getRoomWidgets(roomId, widgetId = QueryStringValue.Equals(widgetId, QueryStringValue.Case.INSENSITIVE)).first()
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
throw CreateWidgetFailure.CreationFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hasPermissionsToHandleWidgets(roomId: String): Boolean {
|
||||||
|
val powerLevelsEvent = stateEventDataSource.getStateEvent(roomId, EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
|
||||||
|
val powerLevelsContent = powerLevelsEvent?.content?.toModel<PowerLevelsContent>() ?: return false
|
||||||
|
return PowerLevelsHelper(powerLevelsContent).isAllowedToSend(EventType.STATE_ROOM_POWER_LEVELS, userId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.widgets.token
|
||||||
|
|
||||||
|
internal class ScalarTokenStore {
|
||||||
|
}
|
|
@ -1002,7 +1002,7 @@ class RoomDetailViewModel @AssistedInject constructor(
|
||||||
setState { copy(asyncInviter = Success(it)) }
|
setState { copy(asyncInviter = Success(it)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE, "")?.also {
|
room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE)?.also {
|
||||||
setState { copy(tombstoneEvent = it) }
|
setState { copy(tombstoneEvent = it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,7 @@ class RoomMemberProfileViewModel @AssistedInject constructor(@Assisted private v
|
||||||
|
|
||||||
private fun observeRoomSummaryAndPowerLevels(room: Room) {
|
private fun observeRoomSummaryAndPowerLevels(room: Room) {
|
||||||
val roomSummaryLive = room.rx().liveRoomSummary().unwrap()
|
val roomSummaryLive = room.rx().liveRoomSummary().unwrap()
|
||||||
val powerLevelsContentLive = room.rx().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, "")
|
val powerLevelsContentLive = room.rx().liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
|
||||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ class RoomMemberListViewModel @AssistedInject constructor(@Assisted initialState
|
||||||
.combineLatest<List<RoomMemberSummary>, PowerLevelsContent, RoomMemberSummaries>(
|
.combineLatest<List<RoomMemberSummary>, PowerLevelsContent, RoomMemberSummaries>(
|
||||||
room.rx().liveRoomMembers(roomMemberQueryParams),
|
room.rx().liveRoomMembers(roomMemberQueryParams),
|
||||||
room.rx()
|
room.rx()
|
||||||
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, "")
|
.liveStateEvent(EventType.STATE_ROOM_POWER_LEVELS, QueryStringValue.NoCondition)
|
||||||
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
.mapOptional { it.content.toModel<PowerLevelsContent>() }
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
BiFunction { roomMembers, powerLevelsContent ->
|
BiFunction { roomMembers, powerLevelsContent ->
|
||||||
|
|
Loading…
Reference in New Issue