mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Merge branch 'release/0.6.0'
This commit is contained in:
commit
cc832633a5
157 changed files with 2028 additions and 981 deletions
|
@ -1,6 +1,7 @@
|
|||
# Use Docker file from https://hub.docker.com/r/runmymind/docker-android-sdk
|
||||
# Last docker plugin version can be found here:
|
||||
# https://github.com/buildkite-plugins/docker-buildkite-plugin/releases
|
||||
# We propagate the environment to the container (sse https://github.com/buildkite-plugins/docker-buildkite-plugin#propagate-environment-optional-boolean)
|
||||
|
||||
# Build debug version of the RiotX application, from the develop branch and the features branches
|
||||
|
||||
|
@ -18,6 +19,7 @@ steps:
|
|||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
- label: "Assemble FDroid Debug version"
|
||||
agents:
|
||||
|
@ -32,6 +34,7 @@ steps:
|
|||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
- label: "Build Google Play unsigned APK"
|
||||
agents:
|
||||
|
@ -46,6 +49,7 @@ steps:
|
|||
plugins:
|
||||
- docker#v3.1.0:
|
||||
image: "runmymind/docker-android-sdk"
|
||||
propagate-environment: true
|
||||
|
||||
# Code quality
|
||||
|
||||
|
|
26
CHANGES.md
26
CHANGES.md
|
@ -1,7 +1,33 @@
|
|||
Changes in RiotX 0.6.0 (2019-09-24)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Save draft of a message when exiting a room with non empty composer (#329)
|
||||
|
||||
Improvements:
|
||||
- Add unread indent on room list (#485)
|
||||
- Message Editing: Update notifications (#128)
|
||||
- Remove any notification of a redacted event (#563)
|
||||
|
||||
Other changes:
|
||||
- Fix a few accessibility issues
|
||||
|
||||
Bugfix:
|
||||
- Fix characters erased from the Search field when the result are coming (#545)
|
||||
- "No connection" banner was displayed by mistake
|
||||
- Leaving community (from another client) has no effect on RiotX (#497)
|
||||
- Push rules was not retrieved after a clear cache
|
||||
- m.notice messages trigger push notifications (#238)
|
||||
- Embiggen messages with multiple emojis also for edited messages (#458)
|
||||
|
||||
Build:
|
||||
- Fix (again) issue with bad versionCode generated by Buildkite (#553)
|
||||
|
||||
Changes in RiotX 0.5.0 (2019-09-17)
|
||||
===================================================
|
||||
|
||||
Features:
|
||||
- Implementation of login to homeserver with SSO (#557)
|
||||
- Handle M_CONSENT_NOT_GIVEN error (#64)
|
||||
- Auto configure homeserver and identity server URLs of LoginActivity with a magic link
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.room.Room
|
|||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
|
@ -54,6 +55,10 @@ class RxRoom(private val room: Room) {
|
|||
return room.getEventReadReceiptsLive(eventId).asObservable()
|
||||
}
|
||||
|
||||
fun liveDrafts(): Observable<List<UserDraft>> {
|
||||
return room.getDraftsLive().asObservable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Room.rx(): RxRoom {
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.io.IOException
|
|||
*/
|
||||
sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
|
||||
data class Unknown(val throwable: Throwable? = null) : Failure(throwable)
|
||||
data class Cancelled(val throwable: Throwable? = null) : Failure(throwable)
|
||||
data class NetworkConnection(val ioException: IOException? = null) : Failure(ioException)
|
||||
data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString()))
|
||||
// When server send an error, but it cannot be interpreted as a MatrixError
|
||||
|
|
|
@ -19,77 +19,92 @@ import im.vector.matrix.android.api.pushrules.rest.PushRule
|
|||
import timber.log.Timber
|
||||
|
||||
|
||||
class Action(val type: Type) {
|
||||
|
||||
enum class Type(val value: String) {
|
||||
NOTIFY("notify"),
|
||||
DONT_NOTIFY("dont_notify"),
|
||||
COALESCE("coalesce"),
|
||||
SET_TWEAK("set_tweak");
|
||||
|
||||
companion object {
|
||||
|
||||
fun safeValueOf(value: String): Type? {
|
||||
try {
|
||||
return valueOf(value)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tweak_action: String? = null
|
||||
var stringValue: String? = null
|
||||
var boolValue: Boolean? = null
|
||||
|
||||
companion object {
|
||||
fun mapFrom(pushRule: PushRule): List<Action>? {
|
||||
val actions = ArrayList<Action>()
|
||||
pushRule.actions.forEach { actionStrOrObj ->
|
||||
if (actionStrOrObj is String) {
|
||||
when (actionStrOrObj) {
|
||||
Action.Type.NOTIFY.value -> Action(Action.Type.NOTIFY)
|
||||
Action.Type.DONT_NOTIFY.value -> Action(Action.Type.DONT_NOTIFY)
|
||||
else -> {
|
||||
Timber.w("Unsupported action type ${actionStrOrObj}")
|
||||
null
|
||||
}
|
||||
}?.let {
|
||||
actions.add(it)
|
||||
}
|
||||
} else if (actionStrOrObj is Map<*, *>) {
|
||||
val tweakAction = actionStrOrObj["set_tweak"] as? String
|
||||
when (tweakAction) {
|
||||
"sound" -> {
|
||||
(actionStrOrObj["value"] as? String)?.let { stringValue ->
|
||||
Action(Action.Type.SET_TWEAK).also {
|
||||
it.tweak_action = "sound"
|
||||
it.stringValue = stringValue
|
||||
actions.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
"highlight" -> {
|
||||
(actionStrOrObj["value"] as? Boolean)?.let { boolValue ->
|
||||
Action(Action.Type.SET_TWEAK).also {
|
||||
it.tweak_action = "highlight"
|
||||
it.boolValue = boolValue
|
||||
actions.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unsupported action type ${actionStrOrObj}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Timber.w("Unsupported action type ${actionStrOrObj}")
|
||||
return null
|
||||
}
|
||||
}
|
||||
return if (actions.isEmpty()) null else actions
|
||||
}
|
||||
}
|
||||
sealed class Action {
|
||||
object Notify : Action()
|
||||
object DoNotNotify : Action()
|
||||
data class Sound(val sound: String) : Action()
|
||||
data class Highlight(val highlight: Boolean) : Action()
|
||||
}
|
||||
|
||||
|
||||
private const val ACTION_NOTIFY = "notify"
|
||||
private const val ACTION_DONT_NOTIFY = "dont_notify"
|
||||
private const val ACTION_COALESCE = "coalesce"
|
||||
|
||||
// Ref: https://matrix.org/docs/spec/client_server/latest#tweaks
|
||||
private const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak"
|
||||
|
||||
private const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound"
|
||||
private const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight"
|
||||
|
||||
private const val ACTION_OBJECT_VALUE_KEY = "value"
|
||||
private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default"
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#actions
|
||||
*
|
||||
* Convert
|
||||
* <pre>
|
||||
* "actions": [
|
||||
* "notify",
|
||||
* {
|
||||
* "set_tweak": "sound",
|
||||
* "value": "default"
|
||||
* },
|
||||
* {
|
||||
* "set_tweak": "highlight"
|
||||
* }
|
||||
* ]
|
||||
*
|
||||
* To
|
||||
* [
|
||||
* Action.Notify,
|
||||
* Action.Sound("default"),
|
||||
* Action.Highlight(true)
|
||||
* ]
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
fun PushRule.getActions(): List<Action> {
|
||||
val result = ArrayList<Action>()
|
||||
|
||||
actions.forEach { actionStrOrObj ->
|
||||
when (actionStrOrObj) {
|
||||
ACTION_NOTIFY -> Action.Notify
|
||||
ACTION_DONT_NOTIFY -> Action.DoNotNotify
|
||||
is Map<*, *> -> {
|
||||
when (actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]) {
|
||||
ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> {
|
||||
(actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue ->
|
||||
Action.Sound(stringValue)
|
||||
}
|
||||
// When the value is not there, default sound (not specified by the spec)
|
||||
?: Action.Sound(ACTION_OBJECT_VALUE_VALUE_DEFAULT)
|
||||
|
||||
}
|
||||
ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> {
|
||||
(actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue ->
|
||||
Action.Highlight(boolValue)
|
||||
}
|
||||
// When the value is not there, default is true, says the spec
|
||||
?: Action.Highlight(true)
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unsupported set_tweak value ${actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]}")
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
Timber.w("Unsupported action type $actionStrOrObj")
|
||||
null
|
||||
}
|
||||
}?.let {
|
||||
result.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@ interface PushRuleService {
|
|||
/**
|
||||
* Fetch the push rules from the server
|
||||
*/
|
||||
fun fetchPushRules(scope: String = "global")
|
||||
fun fetchPushRules(scope: String = RuleScope.GLOBAL)
|
||||
|
||||
//TODO get push rule set
|
||||
fun getPushRules(scope: String = "global"): List<PushRule>
|
||||
fun getPushRules(scope: String = RuleScope.GLOBAL): List<PushRule>
|
||||
|
||||
//TODO update rule
|
||||
|
||||
fun updatePushRuleEnableStatus(kind: String, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
|
||||
fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun addPushRuleListener(listener: PushRuleListener)
|
||||
|
||||
|
@ -43,6 +43,7 @@ interface PushRuleService {
|
|||
interface PushRuleListener {
|
||||
fun onMatchRule(event: Event, actions: List<Action>)
|
||||
fun onRoomLeft(roomId: String)
|
||||
fun onEventRedacted(redactedEventId: String)
|
||||
fun batchFinish()
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ object RuleIds {
|
|||
|
||||
// Default Underride Rules
|
||||
const val RULE_ID_CALL = ".m.rule.call"
|
||||
const val RULE_ID_one_to_one_encrypted_room = ".m.rule.encrypted_room_one_to_one"
|
||||
const val RULE_ID_ONE_TO_ONE_ENCRYPTED_ROOM = ".m.rule.encrypted_room_one_to_one"
|
||||
const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one"
|
||||
const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message"
|
||||
const val RULE_ID_ENCRYPTED = ".m.rule.encrypted"
|
||||
|
|
|
@ -15,12 +15,6 @@
|
|||
*/
|
||||
package im.vector.matrix.android.api.pushrules
|
||||
|
||||
|
||||
enum class RulesetKey(val value: String) {
|
||||
CONTENT("content"),
|
||||
OVERRIDE("override"),
|
||||
ROOM("room"),
|
||||
SENDER("sender"),
|
||||
UNDERRIDE("underride"),
|
||||
UNKNOWN("")
|
||||
object RuleScope {
|
||||
const val GLOBAL = "global"
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.pushrules
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules
|
||||
*/
|
||||
enum class RuleSetKey(val value: String) {
|
||||
CONTENT("content"),
|
||||
OVERRIDE("override"),
|
||||
ROOM("room"),
|
||||
SENDER("sender"),
|
||||
UNDERRIDE("underride")
|
||||
}
|
||||
|
||||
/**
|
||||
* Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushrules-scope-kind-ruleid
|
||||
*/
|
||||
typealias RuleKind = RuleSetKey
|
|
@ -71,7 +71,7 @@ data class PushCondition(
|
|||
this.key?.let { SenderNotificationPermissionCondition(it) }
|
||||
}
|
||||
Condition.Kind.UNRECOGNIZE -> {
|
||||
Timber.e("Unknwon kind $kind")
|
||||
Timber.e("Unknown kind $kind")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,15 @@
|
|||
|
||||
package im.vector.matrix.android.api.session.group.model
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
|
||||
/**
|
||||
* This class holds some data of a group.
|
||||
* It can be retrieved through [im.vector.matrix.android.api.session.group.GroupService]
|
||||
*/
|
||||
data class GroupSummary(
|
||||
val groupId: String,
|
||||
val membership: Membership,
|
||||
val displayName: String = "",
|
||||
val shortDescription: String = "",
|
||||
val avatarUrl: String = "",
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
package im.vector.matrix.android.api.session.pushers
|
||||
|
||||
data class Pusher(
|
||||
|
||||
val userId: String,
|
||||
|
||||
val pushKey: String,
|
||||
val kind: String,
|
||||
val appId: String,
|
||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.room.members.MembershipService
|
|||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.relation.RelationService
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.api.session.room.send.DraftService
|
||||
import im.vector.matrix.android.api.session.room.send.SendService
|
||||
import im.vector.matrix.android.api.session.room.state.StateService
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
|
@ -32,6 +33,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
|||
interface Room :
|
||||
TimelineService,
|
||||
SendService,
|
||||
DraftService,
|
||||
ReadService,
|
||||
MembershipService,
|
||||
StateService,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.matrix.android.api.session.room.model
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
|
||||
/**
|
||||
|
@ -29,13 +30,15 @@ data class RoomSummary(
|
|||
val topic: String = "",
|
||||
val avatarUrl: String = "",
|
||||
val isDirect: Boolean = false,
|
||||
val latestEvent: TimelineEvent? = null,
|
||||
val latestPreviewableEvent: TimelineEvent? = null,
|
||||
val otherMemberIds: List<String> = emptyList(),
|
||||
val notificationCount: Int = 0,
|
||||
val highlightCount: Int = 0,
|
||||
val hasUnreadMessages: Boolean = false,
|
||||
val tags: List<RoomTag> = emptyList(),
|
||||
val membership: Membership = Membership.NONE,
|
||||
val versioningState: VersioningState = VersioningState.NONE
|
||||
val versioningState: VersioningState = VersioningState.NONE,
|
||||
val userDrafts: List<UserDraft> = emptyList()
|
||||
) {
|
||||
|
||||
val isVersioned: Boolean
|
||||
|
|
|
@ -20,7 +20,6 @@ import android.util.Patterns
|
|||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.MatrixPatterns.isUserId
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
|
@ -219,7 +218,7 @@ class CreateRoomParams {
|
|||
* @param ids the participant ids to add.
|
||||
*/
|
||||
fun addParticipantIds(hsConfig: HomeServerConnectionConfig,
|
||||
credentials: Credentials,
|
||||
userId: String,
|
||||
ids: List<String>) {
|
||||
for (id in ids) {
|
||||
if (Patterns.EMAIL_ADDRESS.matcher(id).matches() && hsConfig.identityServerUri != null) {
|
||||
|
@ -233,7 +232,7 @@ class CreateRoomParams {
|
|||
invite3pids!!.add(pid)
|
||||
} else if (isUserId(id)) {
|
||||
// do not invite oneself
|
||||
if (credentials.userId != id) {
|
||||
if (userId != id) {
|
||||
if (null == invitedUserIds) {
|
||||
invitedUserIds = ArrayList()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.room.send
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
|
||||
interface DraftService {
|
||||
|
||||
/**
|
||||
* Save or update a draft to the room
|
||||
*/
|
||||
fun saveDraft(draft: UserDraft)
|
||||
|
||||
/**
|
||||
* Delete the last draft, basically just after sending the message
|
||||
*/
|
||||
fun deleteDraft()
|
||||
|
||||
/**
|
||||
* Return the current drafts if any, as a live data
|
||||
* The draft list can contain one draft for {regular, reply, quote} and an arbitrary number of {edit} drafts
|
||||
*/
|
||||
fun getDraftsLive(): LiveData<List<UserDraft>>
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.api.session.room.send
|
||||
|
||||
/**
|
||||
* Describes a user draft:
|
||||
* REGULAR: draft of a classical message
|
||||
* QUOTE: draft of a message which quotes another message
|
||||
* EDIT: draft of an edition of a message
|
||||
* REPLY: draft of a reply of another message
|
||||
*/
|
||||
sealed class UserDraft(open val text: String) {
|
||||
data class REGULAR(override val text: String) : UserDraft(text)
|
||||
data class QUOTE(val linkedEventId: String, override val text: String) : UserDraft(text)
|
||||
data class EDIT(val linkedEventId: String, override val text: String) : UserDraft(text)
|
||||
data class REPLY(val linkedEventId: String, override val text: String) : UserDraft(text)
|
||||
|
||||
fun isValid(): Boolean {
|
||||
return when (this) {
|
||||
is REGULAR -> text.isNotBlank()
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.api.session.room.timeline
|
|||
|
||||
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.RelationType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
||||
|
@ -92,6 +93,13 @@ data class TimelineEvent(
|
|||
*/
|
||||
fun TimelineEvent.hasBeenEdited() = annotations?.editSummary != null
|
||||
|
||||
/**
|
||||
* Get the eventId which was edited by this event if any
|
||||
*/
|
||||
fun TimelineEvent.getEditedEventId(): String? {
|
||||
return root.getClearContent().toModel<MessageContent>()?.relatesTo?.takeIf { it.type == RelationType.REPLACE }?.eventId
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last MessageContent, after a possible edition
|
||||
*/
|
||||
|
@ -99,6 +107,20 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? = annotations?.editSu
|
|||
?: root.getClearContent().toModel()
|
||||
|
||||
|
||||
/**
|
||||
* Get last Message body, after a possible edition
|
||||
*/
|
||||
fun TimelineEvent.getLastMessageBody(): String? {
|
||||
val lastMessageContent = getLastMessageContent()
|
||||
|
||||
if (lastMessageContent != null) {
|
||||
return lastMessageContent.newContent?.toModel<MessageContent>()?.body ?: lastMessageContent.body
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun TimelineEvent.getTextEditableContent(): String? {
|
||||
val originalContent = root.getClearContent().toModel<MessageContent>() ?: return null
|
||||
val isReply = originalContent.isReply() || root.content.toModel<EncryptedEventContent>()?.relatesTo?.inReplyTo?.eventId != null
|
||||
|
|
|
@ -20,7 +20,7 @@ import im.vector.matrix.android.api.auth.data.Credentials
|
|||
import javax.inject.Inject
|
||||
|
||||
internal class ObjectSigner @Inject constructor(private val credentials: Credentials,
|
||||
private val olmDevice: MXOlmDevice) {
|
||||
private val olmDevice: MXOlmDevice) {
|
||||
|
||||
/**
|
||||
* Sign Object
|
||||
|
|
|
@ -27,14 +27,14 @@ import java.util.*
|
|||
import javax.inject.Inject
|
||||
|
||||
internal class EnsureOlmSessionsForUsersAction @Inject constructor(private val olmDevice: MXOlmDevice,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) {
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction) {
|
||||
|
||||
/**
|
||||
* Try to make sure we have established olm sessions for the given users.
|
||||
* @param users a list of user ids.
|
||||
*/
|
||||
suspend fun handle(users: List<String>) : MXUsersDevicesMap<MXOlmSessionResult> {
|
||||
suspend fun handle(users: List<String>): MXUsersDevicesMap<MXOlmSessionResult> {
|
||||
Timber.v("## ensureOlmSessionsForUsers() : ensureOlmSessionsForUsers $users")
|
||||
val devicesByUser = HashMap<String /* userId */, MutableList<MXDeviceInfo>>()
|
||||
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto.actions
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.keysbackup.KeysBackup
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class SetDeviceVerificationAction @Inject constructor(private val cryptoStore: IMXCryptoStore,
|
||||
private val credentials: Credentials,
|
||||
private val keysBackup: KeysBackup) {
|
||||
@UserId private val userId: String,
|
||||
private val keysBackup: KeysBackup) {
|
||||
|
||||
fun handle(verificationStatus: Int, deviceId: String, userId: String) {
|
||||
val device = cryptoStore.getUserDevice(deviceId, userId)
|
||||
|
@ -39,7 +39,7 @@ internal class SetDeviceVerificationAction @Inject constructor(private val crypt
|
|||
device.verified = verificationStatus
|
||||
cryptoStore.storeUserDevice(userId, device)
|
||||
|
||||
if (userId == credentials.userId) {
|
||||
if (userId == this.userId) {
|
||||
// If one of the user's own devices is being marked as verified / unverified,
|
||||
// check the key backup status, since whether or not we use this depends on
|
||||
// whether it has a signature from a verified device
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||
|
||||
import android.text.TextUtils
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
|
@ -40,7 +39,7 @@ import kotlinx.coroutines.GlobalScope
|
|||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
internal class MXMegolmDecryption(private val credentials: Credentials,
|
||||
internal class MXMegolmDecryption(private val userId: String,
|
||||
private val olmDevice: MXOlmDevice,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager,
|
||||
|
@ -146,11 +145,11 @@ internal class MXMegolmDecryption(private val credentials: Credentials,
|
|||
|
||||
val selfMap = HashMap<String, String>()
|
||||
// TODO Replace this hard coded keys (see OutgoingRoomKeyRequestManager)
|
||||
selfMap["userId"] = credentials.userId
|
||||
selfMap["userId"] = userId
|
||||
selfMap["deviceId"] = "*"
|
||||
recipients.add(selfMap)
|
||||
|
||||
if (!TextUtils.equals(sender, credentials.userId)) {
|
||||
if (!TextUtils.equals(sender, userId)) {
|
||||
val senderMap = HashMap<String, String>()
|
||||
senderMap["userId"] = sender
|
||||
senderMap["deviceId"] = encryptedEventContent.deviceId!!
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto.algorithms.megolm
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.DeviceListManager
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.crypto.OutgoingRoomKeyRequestManager
|
||||
|
@ -24,22 +23,23 @@ import im.vector.matrix.android.internal.crypto.actions.EnsureOlmSessionsForDevi
|
|||
import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter
|
||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||
import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class MXMegolmDecryptionFactory @Inject constructor(private val credentials: Credentials,
|
||||
private val olmDevice: MXOlmDevice,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager,
|
||||
private val messageEncrypter: MessageEncrypter,
|
||||
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val sendToDeviceTask: SendToDeviceTask,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) {
|
||||
internal class MXMegolmDecryptionFactory @Inject constructor(@UserId private val userId: String,
|
||||
private val olmDevice: MXOlmDevice,
|
||||
private val deviceListManager: DeviceListManager,
|
||||
private val outgoingRoomKeyRequestManager: OutgoingRoomKeyRequestManager,
|
||||
private val messageEncrypter: MessageEncrypter,
|
||||
private val ensureOlmSessionsForDevicesAction: EnsureOlmSessionsForDevicesAction,
|
||||
private val cryptoStore: IMXCryptoStore,
|
||||
private val sendToDeviceTask: SendToDeviceTask,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) {
|
||||
|
||||
fun create(): MXMegolmDecryption {
|
||||
return MXMegolmDecryption(
|
||||
credentials,
|
||||
userId,
|
||||
olmDevice,
|
||||
deviceListManager,
|
||||
outgoingRoomKeyRequestManager,
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto.algorithms.olm
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.MXCryptoError
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
|
@ -35,8 +34,8 @@ import timber.log.Timber
|
|||
internal class MXOlmDecryption(
|
||||
// The olm device interface
|
||||
private val olmDevice: MXOlmDevice,
|
||||
// the matrix credentials
|
||||
private val credentials: Credentials)
|
||||
// the matrix userId
|
||||
private val userId: String)
|
||||
: IMXDecrypting {
|
||||
|
||||
override suspend fun decryptEvent(event: Event, timeline: String): MXEventDecryptionResult {
|
||||
|
@ -97,9 +96,9 @@ internal class MXOlmDecryption(
|
|||
throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY, reason)
|
||||
}
|
||||
|
||||
if (olmPayloadContent.recipient != credentials.userId) {
|
||||
if (olmPayloadContent.recipient != userId) {
|
||||
Timber.e("## decryptEvent() : Event ${event.eventId}:" +
|
||||
" Intended recipient ${olmPayloadContent.recipient} does not match our id ${credentials.userId}")
|
||||
" Intended recipient ${olmPayloadContent.recipient} does not match our id $userId")
|
||||
throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_RECIPIENT,
|
||||
String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient))
|
||||
}
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto.algorithms.olm
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.crypto.MXOlmDevice
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class MXOlmDecryptionFactory @Inject constructor(private val olmDevice: MXOlmDevice,
|
||||
private val credentials: Credentials) {
|
||||
@UserId private val userId: String) {
|
||||
|
||||
fun create(): MXOlmDecryption {
|
||||
return MXOlmDecryption(
|
||||
olmDevice,
|
||||
credentials)
|
||||
userId)
|
||||
}
|
||||
}
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package im.vector.matrix.android.internal.crypto.tasks
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.auth.data.LoginFlowTypes
|
||||
import im.vector.matrix.android.internal.crypto.api.CryptoApi
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceAuth
|
||||
import im.vector.matrix.android.internal.crypto.model.rest.DeleteDeviceParams
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
@ -34,7 +34,7 @@ internal interface DeleteDeviceWithUserPasswordTask : Task<DeleteDeviceWithUserP
|
|||
}
|
||||
|
||||
internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor(private val cryptoApi: CryptoApi,
|
||||
private val credentials: Credentials)
|
||||
@UserId private val userId: String)
|
||||
: DeleteDeviceWithUserPasswordTask {
|
||||
|
||||
override suspend fun execute(params: DeleteDeviceWithUserPasswordTask.Params) {
|
||||
|
@ -45,7 +45,7 @@ internal class DefaultDeleteDeviceWithUserPasswordTask @Inject constructor(priva
|
|||
.apply {
|
||||
type = LoginFlowTypes.PASSWORD
|
||||
session = params.authSession
|
||||
user = credentials.userId
|
||||
user = userId
|
||||
password = params.password
|
||||
}
|
||||
})
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.internal.database.model.DraftEntity
|
||||
|
||||
/**
|
||||
* DraftEntity <-> UserDraft
|
||||
*/
|
||||
internal object DraftMapper {
|
||||
|
||||
fun map(entity: DraftEntity): UserDraft {
|
||||
return when (entity.draftMode) {
|
||||
DraftEntity.MODE_REGULAR -> UserDraft.REGULAR(entity.content)
|
||||
DraftEntity.MODE_EDIT -> UserDraft.EDIT(entity.linkedEventId, entity.content)
|
||||
DraftEntity.MODE_QUOTE -> UserDraft.QUOTE(entity.linkedEventId, entity.content)
|
||||
DraftEntity.MODE_REPLY -> UserDraft.REPLY(entity.linkedEventId, entity.content)
|
||||
else -> null
|
||||
} ?: UserDraft.REGULAR("")
|
||||
}
|
||||
|
||||
fun map(domain: UserDraft): DraftEntity {
|
||||
return when (domain) {
|
||||
is UserDraft.REGULAR -> DraftEntity(content = domain.text, draftMode = DraftEntity.MODE_REGULAR, linkedEventId = "")
|
||||
is UserDraft.EDIT -> DraftEntity(content = domain.text, draftMode = DraftEntity.MODE_EDIT, linkedEventId = domain.linkedEventId)
|
||||
is UserDraft.QUOTE -> DraftEntity(content = domain.text, draftMode = DraftEntity.MODE_QUOTE, linkedEventId = domain.linkedEventId)
|
||||
is UserDraft.REPLY -> DraftEntity(content = domain.text, draftMode = DraftEntity.MODE_REPLY, linkedEventId = domain.linkedEventId)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,14 +22,15 @@ import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
|||
|
||||
internal object GroupSummaryMapper {
|
||||
|
||||
fun map(roomSummaryEntity: GroupSummaryEntity): GroupSummary {
|
||||
fun map(groupSummaryEntity: GroupSummaryEntity): GroupSummary {
|
||||
return GroupSummary(
|
||||
roomSummaryEntity.groupId,
|
||||
roomSummaryEntity.displayName,
|
||||
roomSummaryEntity.shortDescription,
|
||||
roomSummaryEntity.avatarUrl,
|
||||
roomSummaryEntity.roomIds.toList(),
|
||||
roomSummaryEntity.userIds.toList()
|
||||
groupSummaryEntity.groupId,
|
||||
groupSummaryEntity.membership,
|
||||
groupSummaryEntity.displayName,
|
||||
groupSummaryEntity.shortDescription,
|
||||
groupSummaryEntity.avatarUrl,
|
||||
groupSummaryEntity.roomIds.toList(),
|
||||
groupSummaryEntity.userIds.toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ internal object PushersMapper {
|
|||
fun map(pushEntity: PusherEntity): Pusher {
|
||||
|
||||
return Pusher(
|
||||
userId = pushEntity.userId,
|
||||
pushKey = pushEntity.pushKey,
|
||||
kind = pushEntity.kind ?: "",
|
||||
appId = pushEntity.appId,
|
||||
|
@ -39,9 +38,8 @@ internal object PushersMapper {
|
|||
)
|
||||
}
|
||||
|
||||
fun map(pusher: JsonPusher, userId: String): PusherEntity {
|
||||
fun map(pusher: JsonPusher): PusherEntity {
|
||||
return PusherEntity(
|
||||
userId = userId,
|
||||
pushKey = pusher.pushKey,
|
||||
kind = pusher.kind,
|
||||
appId = pusher.appId,
|
||||
|
@ -58,6 +56,6 @@ internal fun PusherEntity.asDomain(): Pusher {
|
|||
return PushersMapper.map(this)
|
||||
}
|
||||
|
||||
internal fun JsonPusher.toEntity(userId: String): PusherEntity {
|
||||
return PushersMapper.map(this, userId)
|
||||
internal fun JsonPusher.toEntity(): PusherEntity {
|
||||
return PushersMapper.map(this)
|
||||
}
|
|
@ -22,12 +22,12 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
|||
import im.vector.matrix.android.api.session.room.model.tag.RoomTag
|
||||
import im.vector.matrix.android.internal.crypto.algorithms.olm.OlmDecryptionResult
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomSummaryMapper @Inject constructor(
|
||||
val cryptoService: CryptoService,
|
||||
val timelineEventMapper: TimelineEventMapper
|
||||
private val cryptoService: CryptoService,
|
||||
private val timelineEventMapper: TimelineEventMapper
|
||||
) {
|
||||
|
||||
fun map(roomSummaryEntity: RoomSummaryEntity): RoomSummary {
|
||||
|
@ -35,7 +35,7 @@ internal class RoomSummaryMapper @Inject constructor(
|
|||
RoomTag(it.tagName, it.tagOrder)
|
||||
}
|
||||
|
||||
val latestEvent = roomSummaryEntity.latestEvent?.let {
|
||||
val latestEvent = roomSummaryEntity.latestPreviewableEvent?.let {
|
||||
timelineEventMapper.map(it)
|
||||
}
|
||||
if (latestEvent?.root?.isEncrypted() == true && latestEvent.root.mxDecryptionResult == null) {
|
||||
|
@ -43,29 +43,32 @@ internal class RoomSummaryMapper @Inject constructor(
|
|||
//for now decrypt sync
|
||||
try {
|
||||
val result = cryptoService.decryptEvent(latestEvent.root, latestEvent.root.roomId + UUID.randomUUID().toString())
|
||||
latestEvent.root.mxDecryptionResult = OlmDecryptionResult(
|
||||
payload = result.clearEvent,
|
||||
senderKey = result.senderCurve25519Key,
|
||||
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
|
||||
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
|
||||
)
|
||||
latestEvent.root.mxDecryptionResult = OlmDecryptionResult(
|
||||
payload = result.clearEvent,
|
||||
senderKey = result.senderCurve25519Key,
|
||||
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
|
||||
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
|
||||
)
|
||||
} catch (e: MXCryptoError) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return RoomSummary(
|
||||
roomId = roomSummaryEntity.roomId,
|
||||
displayName = roomSummaryEntity.displayName ?: "",
|
||||
topic = roomSummaryEntity.topic ?: "",
|
||||
avatarUrl = roomSummaryEntity.avatarUrl ?: "",
|
||||
isDirect = roomSummaryEntity.isDirect,
|
||||
latestEvent = latestEvent,
|
||||
latestPreviewableEvent = latestEvent,
|
||||
otherMemberIds = roomSummaryEntity.otherMemberIds.toList(),
|
||||
highlightCount = roomSummaryEntity.highlightCount,
|
||||
notificationCount = roomSummaryEntity.notificationCount,
|
||||
hasUnreadMessages = roomSummaryEntity.hasUnreadMessages,
|
||||
tags = tags,
|
||||
membership = roomSummaryEntity.membership,
|
||||
versioningState = roomSummaryEntity.versioningState
|
||||
versioningState = roomSummaryEntity.versioningState,
|
||||
userDrafts = roomSummaryEntity.userDrafts?.userDrafts?.map { DraftMapper.map(it) } ?: emptyList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
|
||||
internal open class DraftEntity(var content: String = "",
|
||||
var draftMode: String = MODE_REGULAR,
|
||||
var linkedEventId: String = ""
|
||||
|
||||
) : RealmObject() {
|
||||
|
||||
companion object {
|
||||
const val MODE_REGULAR = "REGULAR"
|
||||
const val MODE_EDIT = "EDIT"
|
||||
const val MODE_REPLY = "REPLY"
|
||||
const val MODE_QUOTE = "QUOTE"
|
||||
}
|
||||
}
|
||||
|
|
@ -20,9 +20,13 @@ import im.vector.matrix.android.api.session.room.model.Membership
|
|||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
internal open class GroupEntity(@PrimaryKey var groupId: String = ""
|
||||
|
||||
) : RealmObject() {
|
||||
/**
|
||||
* This class is used to store group info (groupId and membership) from the sync response.
|
||||
* Then [im.vector.matrix.android.internal.session.group.GroupSummaryUpdater] observes change and
|
||||
* makes requests to fetch group information from the homeserver
|
||||
*/
|
||||
internal open class GroupEntity(@PrimaryKey var groupId: String = "")
|
||||
: RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
var membership: Membership
|
||||
|
|
|
@ -16,18 +16,28 @@
|
|||
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.PrimaryKey
|
||||
|
||||
internal open class GroupSummaryEntity(@PrimaryKey var groupId: String = "",
|
||||
var displayName: String = "",
|
||||
var shortDescription: String = "",
|
||||
var avatarUrl: String = "",
|
||||
var roomIds: RealmList<String> = RealmList(),
|
||||
var userIds: RealmList<String> = RealmList()
|
||||
var displayName: String = "",
|
||||
var shortDescription: String = "",
|
||||
var avatarUrl: String = "",
|
||||
var roomIds: RealmList<String> = RealmList(),
|
||||
var userIds: RealmList<String> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
var membership: Membership
|
||||
get() {
|
||||
return Membership.valueOf(membershipStr)
|
||||
}
|
||||
set(value) {
|
||||
membershipStr = value.name
|
||||
}
|
||||
|
||||
companion object
|
||||
|
||||
}
|
|
@ -15,17 +15,24 @@
|
|||
*/
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
|
||||
|
||||
internal open class PushRulesEntity(
|
||||
@Index var userId: String = "",
|
||||
var scope: String = "",
|
||||
// "content", etc.
|
||||
var rulesetKey: String = "",
|
||||
var pushRules: RealmList<PushRuleEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
private var kindStr: String = RuleKind.CONTENT.name
|
||||
var kind: RuleKind
|
||||
get() {
|
||||
return RuleKind.valueOf(kindStr)
|
||||
}
|
||||
set(value) {
|
||||
kindStr = value.name
|
||||
}
|
||||
|
||||
companion object
|
||||
}
|
|
@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.database.model
|
|||
|
||||
import im.vector.matrix.android.api.session.pushers.PusherState
|
||||
import io.realm.RealmObject
|
||||
import io.realm.annotations.Index
|
||||
|
||||
//TODO
|
||||
// at java.lang.Thread.run(Thread.java:764)
|
||||
|
@ -29,7 +28,6 @@ import io.realm.annotations.Index
|
|||
// at im.vector.matrix.android.internal.session.pushers.AddHttpPusherWorker$doWork$$inlined$fold$lambda$2.execute(AddHttpPusherWorker.kt:70)
|
||||
// at io.realm.Realm.executeTransaction(Realm.java:1493)
|
||||
internal open class PusherEntity(
|
||||
@Index var userId: String = "",
|
||||
var pushKey: String = "",
|
||||
var kind: String? = null,
|
||||
var appId: String = "",
|
||||
|
|
|
@ -26,7 +26,7 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
|||
var displayName: String? = "",
|
||||
var avatarUrl: String? = "",
|
||||
var topic: String? = "",
|
||||
var latestEvent: TimelineEventEntity? = null,
|
||||
var latestPreviewableEvent: TimelineEventEntity? = null,
|
||||
var heroes: RealmList<String> = RealmList(),
|
||||
var joinedMembersCount: Int? = 0,
|
||||
var invitedMembersCount: Int? = 0,
|
||||
|
@ -35,7 +35,9 @@ internal open class RoomSummaryEntity(@PrimaryKey var roomId: String = "",
|
|||
var otherMemberIds: RealmList<String> = RealmList(),
|
||||
var notificationCount: Int = 0,
|
||||
var highlightCount: Int = 0,
|
||||
var tags: RealmList<RoomTagEntity> = RealmList()
|
||||
var hasUnreadMessages: Boolean = false,
|
||||
var tags: RealmList<RoomTagEntity> = RealmList(),
|
||||
var userDrafts: UserDraftsEntity? = null
|
||||
) : RealmObject() {
|
||||
|
||||
private var membershipStr: String = Membership.NONE.name
|
||||
|
|
|
@ -43,6 +43,8 @@ import io.realm.annotations.RealmModule
|
|||
PushConditionEntity::class,
|
||||
PusherEntity::class,
|
||||
PusherDataEntity::class,
|
||||
ReadReceiptsSummaryEntity::class
|
||||
ReadReceiptsSummaryEntity::class,
|
||||
UserDraftsEntity::class,
|
||||
DraftEntity::class
|
||||
])
|
||||
internal class SessionRealmModule
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.database.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
import io.realm.RealmResults
|
||||
import io.realm.annotations.LinkingObjects
|
||||
|
||||
/**
|
||||
* Create a specific table to be able to do direct query on it and keep the draft ordered
|
||||
*/
|
||||
internal open class UserDraftsEntity(var userDrafts: RealmList<DraftEntity> = RealmList()
|
||||
) : RealmObject() {
|
||||
|
||||
// Link to RoomSummaryEntity
|
||||
@LinkingObjects("userDrafts")
|
||||
val roomSummaryEntity: RealmResults<RoomSummaryEntity>? = null
|
||||
|
||||
companion object
|
||||
|
||||
}
|
|
@ -23,9 +23,9 @@ import io.realm.Realm
|
|||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.where
|
||||
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<GroupEntity> {
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, groupId: String): RealmQuery<GroupEntity> {
|
||||
return realm.where<GroupEntity>()
|
||||
.equalTo(GroupEntityFields.GROUP_ID, roomId)
|
||||
.equalTo(GroupEntityFields.GROUP_ID, groupId)
|
||||
}
|
||||
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery<GroupEntity> {
|
||||
|
|
|
@ -30,3 +30,7 @@ internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupId: String? =
|
|||
return query
|
||||
}
|
||||
|
||||
internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupIds: List<String>): RealmQuery<GroupSummaryEntity> {
|
||||
return realm.where<GroupSummaryEntity>()
|
||||
.`in`(GroupSummaryEntityFields.GROUP_ID, groupIds.toTypedArray())
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntity
|
||||
|
@ -24,10 +25,8 @@ import io.realm.RealmQuery
|
|||
import io.realm.kotlin.where
|
||||
|
||||
internal fun PusherEntity.Companion.where(realm: Realm,
|
||||
userId: String,
|
||||
pushKey: String? = null): RealmQuery<PusherEntity> {
|
||||
return realm.where<PusherEntity>()
|
||||
.equalTo(PusherEntityFields.USER_ID, userId)
|
||||
.apply {
|
||||
if (pushKey != null) {
|
||||
equalTo(PusherEntityFields.PUSH_KEY, pushKey)
|
||||
|
@ -36,11 +35,9 @@ internal fun PusherEntity.Companion.where(realm: Realm,
|
|||
}
|
||||
|
||||
internal fun PushRulesEntity.Companion.where(realm: Realm,
|
||||
userId: String,
|
||||
scope: String,
|
||||
ruleSetKey: String): RealmQuery<PushRulesEntity> {
|
||||
kind: RuleKind): RealmQuery<PushRulesEntity> {
|
||||
return realm.where<PushRulesEntity>()
|
||||
.equalTo(PushRulesEntityFields.USER_ID, userId)
|
||||
.equalTo(PushRulesEntityFields.SCOPE, scope)
|
||||
.equalTo(PushRulesEntityFields.RULESET_KEY, ruleSetKey)
|
||||
.equalTo(PushRulesEntityFields.KIND_STR, kind.name)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||
|
||||
internal fun isEventRead(monarchy: Monarchy,
|
||||
userId: String?,
|
||||
roomId: String?,
|
||||
eventId: String?): Boolean {
|
||||
if (userId.isNullOrBlank() || roomId.isNullOrBlank() || eventId.isNullOrBlank()) {
|
||||
return false
|
||||
}
|
||||
|
||||
var isEventRead = false
|
||||
|
||||
monarchy.doWithRealm { realm ->
|
||||
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) ?: return@doWithRealm
|
||||
val eventToCheck = liveChunk.timelineEvents.find(eventId)?.root
|
||||
|
||||
isEventRead = if (eventToCheck?.sender == userId) {
|
||||
true
|
||||
} else {
|
||||
val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() ?: return@doWithRealm
|
||||
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex ?: Int.MIN_VALUE
|
||||
val eventToCheckIndex = eventToCheck?.displayIndex ?: Int.MAX_VALUE
|
||||
|
||||
eventToCheckIndex <= readReceiptIndex
|
||||
}
|
||||
}
|
||||
|
||||
return isEventRead
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.database.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.UserDraftsEntity
|
||||
import im.vector.matrix.android.internal.database.model.UserDraftsEntityFields
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.where
|
||||
|
||||
internal fun UserDraftsEntity.Companion.where(realm: Realm, roomId: String? = null): RealmQuery<UserDraftsEntity> {
|
||||
val query = realm.where<UserDraftsEntity>()
|
||||
if (roomId != null) {
|
||||
query.equalTo(UserDraftsEntityFields.ROOM_SUMMARY_ENTITY + "." + RoomSummaryEntityFields.ROOM_ID, roomId)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
|||
import im.vector.matrix.android.internal.session.sync.model.UserAccountData
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules
|
||||
|
||||
|
||||
object MoshiProvider {
|
||||
|
@ -31,6 +32,7 @@ object MoshiProvider {
|
|||
.add(UriMoshiAdapter())
|
||||
.add(RuntimeJsonAdapterFactory.of(UserAccountData::class.java, "type", UserAccountDataFallback::class.java)
|
||||
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
|
||||
.registerSubtype(UserAccountDataPushRules::class.java, UserAccountData.TYPE_PUSH_RULES)
|
||||
)
|
||||
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)
|
||||
.registerSubtype(MessageTextContent::class.java, MessageType.MSGTYPE_TEXT)
|
||||
|
|
|
@ -18,6 +18,16 @@ package im.vector.matrix.android.internal.di
|
|||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
/**
|
||||
* Used to inject the userId
|
||||
*/
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class UserMd5
|
||||
internal annotation class UserId
|
||||
|
||||
/**
|
||||
* Used to inject the md5 of the userId
|
||||
*/
|
||||
@Qualifier
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
internal annotation class UserMd5
|
||||
|
|
|
@ -18,7 +18,9 @@ package im.vector.matrix.android.internal.network
|
|||
|
||||
import android.content.Context
|
||||
import com.novoda.merlin.Merlin
|
||||
import com.novoda.merlin.MerlinsBeard
|
||||
import im.vector.matrix.android.internal.di.MatrixScope
|
||||
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -26,7 +28,9 @@ import kotlin.coroutines.resume
|
|||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@MatrixScope
|
||||
internal class NetworkConnectivityChecker @Inject constructor(context: Context) {
|
||||
internal class NetworkConnectivityChecker @Inject constructor(context: Context,
|
||||
backgroundDetectionObserver: BackgroundDetectionObserver)
|
||||
: BackgroundDetectionObserver.Listener {
|
||||
|
||||
private val merlin = Merlin.Builder()
|
||||
.withConnectableCallbacks()
|
||||
|
@ -36,11 +40,16 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context)
|
|||
private val listeners = Collections.synchronizedSet(LinkedHashSet<Listener>())
|
||||
|
||||
// True when internet is available
|
||||
var hasInternetAccess = false
|
||||
var hasInternetAccess = MerlinsBeard.Builder().build(context).isConnected
|
||||
private set
|
||||
|
||||
init {
|
||||
backgroundDetectionObserver.register(this)
|
||||
}
|
||||
|
||||
override fun onMoveToForeground() {
|
||||
merlin.bind()
|
||||
|
||||
merlin.registerDisconnectable {
|
||||
if (hasInternetAccess) {
|
||||
Timber.v("On Disconnect")
|
||||
|
@ -63,6 +72,10 @@ internal class NetworkConnectivityChecker @Inject constructor(context: Context)
|
|||
}
|
||||
}
|
||||
|
||||
override fun onMoveToBackground() {
|
||||
merlin.unbind()
|
||||
}
|
||||
|
||||
suspend fun waitUntilConnected() {
|
||||
if (hasInternetAccess) {
|
||||
return
|
||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.matrix.android.api.failure.ConsentNotGivenError
|
|||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.failure.MatrixError
|
||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import okhttp3.ResponseBody
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import retrofit2.Call
|
||||
|
@ -49,6 +50,7 @@ internal class Request<DATA> {
|
|||
is IOException -> Failure.NetworkConnection(exception)
|
||||
is Failure.ServerError,
|
||||
is Failure.OtherServerError -> exception
|
||||
is CancellationException -> Failure.Cancelled(exception)
|
||||
else -> Failure.Unknown(exception)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
@MatrixScope
|
||||
internal class UserAgentHolder @Inject constructor(val context: Context) {
|
||||
internal class UserAgentHolder @Inject constructor(private val context: Context) {
|
||||
|
||||
var userAgent: String = ""
|
||||
private set
|
||||
|
|
|
@ -20,11 +20,11 @@ import android.content.Context
|
|||
import android.os.Environment
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.content.ContentUrlResolver
|
||||
import im.vector.matrix.android.api.session.file.FileService
|
||||
import im.vector.matrix.android.internal.crypto.attachments.ElementToDecrypt
|
||||
import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments
|
||||
import im.vector.matrix.android.internal.di.UserMd5
|
||||
import im.vector.matrix.android.internal.extensions.foldToCallback
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import im.vector.matrix.android.internal.util.md5
|
||||
|
@ -40,7 +40,7 @@ import java.io.IOException
|
|||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultFileService @Inject constructor(private val context: Context,
|
||||
private val sessionParams: SessionParams,
|
||||
@UserMd5 private val userMd5: String,
|
||||
private val contentUrlResolver: ContentUrlResolver,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) : FileService {
|
||||
|
||||
|
@ -105,7 +105,7 @@ internal class DefaultFileService @Inject constructor(private val context: Conte
|
|||
// Create dir tree (MF stands for Matrix File):
|
||||
// <cache>/MF/<md5(userId)>/<md5(id)>/
|
||||
val tmpFolderRoot = File(context.cacheDir, "MF")
|
||||
val tmpFolderUser = File(tmpFolderRoot, sessionParams.credentials.userId.md5())
|
||||
val tmpFolderUser = File(tmpFolderRoot, userMd5)
|
||||
File(tmpFolderUser, id.md5())
|
||||
}
|
||||
FileService.DownloadMode.TO_EXPORT -> {
|
||||
|
|
|
@ -67,11 +67,18 @@ internal abstract class SessionModule {
|
|||
return sessionParams.credentials
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@UserId
|
||||
@Provides
|
||||
fun providesUserId(credentials: Credentials): String {
|
||||
return credentials.userId
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@UserMd5
|
||||
@Provides
|
||||
fun providesUserMd5(sessionParams: SessionParams): String {
|
||||
return sessionParams.credentials.userId.md5()
|
||||
fun providesUserMd5(@UserId userId: String): String {
|
||||
return userId.md5()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.filter
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
@ -33,7 +33,7 @@ internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
|
|||
|
||||
}
|
||||
|
||||
internal class DefaultSaveFilterTask @Inject constructor(private val sessionParams: SessionParams,
|
||||
internal class DefaultSaveFilterTask @Inject constructor(@UserId private val userId: String,
|
||||
private val filterAPI: FilterApi,
|
||||
private val filterRepository: FilterRepository
|
||||
) : SaveFilterTask {
|
||||
|
@ -41,7 +41,7 @@ internal class DefaultSaveFilterTask @Inject constructor(private val sessionPara
|
|||
override suspend fun execute(params: SaveFilterTask.Params) {
|
||||
val filterResponse = executeRequest<FilterResponse> {
|
||||
// TODO auto retry
|
||||
apiCall = filterAPI.uploadFilter(sessionParams.credentials.userId, params.filter)
|
||||
apiCall = filterAPI.uploadFilter(userId, params.filter)
|
||||
}
|
||||
filterRepository.storeFilterId(params.filter, filterResponse.filterId)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.matrix.android.internal.session.group
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
|
@ -64,8 +65,7 @@ internal class DefaultGetGroupDataTask @Inject constructor(
|
|||
groupSummaryEntity.avatarUrl = groupSummary.profile?.avatarUrl ?: ""
|
||||
val name = groupSummary.profile?.name
|
||||
groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupId else name
|
||||
groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription
|
||||
?: ""
|
||||
groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription ?: ""
|
||||
|
||||
val roomIds = groupRooms.rooms.map { it.roomId }
|
||||
groupSummaryEntity.roomIds.clear()
|
||||
|
@ -74,8 +74,12 @@ internal class DefaultGetGroupDataTask @Inject constructor(
|
|||
val userIds = groupUsers.users.map { it.userId }
|
||||
groupSummaryEntity.userIds.clear()
|
||||
groupSummaryEntity.userIds.addAll(userIds)
|
||||
|
||||
groupSummaryEntity.membership = when (groupSummary.user?.membership) {
|
||||
Membership.JOIN.value -> Membership.JOIN
|
||||
Membership.INVITE.value -> Membership.INVITE
|
||||
else -> Membership.LEAVE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -20,35 +20,48 @@ import android.content.Context
|
|||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.model.GroupEntity
|
||||
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil
|
||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import io.realm.OrderedCollectionChangeSet
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.RealmResults
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
|
||||
|
||||
internal class GroupSummaryUpdater @Inject constructor(private val context: Context,
|
||||
private val credentials: Credentials,
|
||||
@SessionDatabase realmConfiguration: RealmConfiguration)
|
||||
: RealmLiveEntityObserver<GroupEntity>(realmConfiguration) {
|
||||
@UserId private val userId: String,
|
||||
private val monarchy: Monarchy)
|
||||
: RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) {
|
||||
|
||||
override val query = Monarchy.Query<GroupEntity> { GroupEntity.where(it) }
|
||||
override val query = Monarchy.Query { GroupEntity.where(it) }
|
||||
|
||||
override fun onChange(results: RealmResults<GroupEntity>, changeSet: OrderedCollectionChangeSet) {
|
||||
val newGroupIds = changeSet.insertions
|
||||
// `insertions` for new groups and `changes` to handle left groups
|
||||
val modifiedGroupEntity = (changeSet.insertions + changeSet.changes)
|
||||
.asSequence()
|
||||
.mapNotNull { results[it]?.groupId}
|
||||
.toList()
|
||||
.mapNotNull { results[it] }
|
||||
|
||||
fetchGroupsData(modifiedGroupEntity
|
||||
.filter { it.membership == Membership.JOIN || it.membership == Membership.INVITE }
|
||||
.map { it.groupId }
|
||||
.toList())
|
||||
|
||||
deleteGroups(modifiedGroupEntity
|
||||
.filter { it.membership == Membership.LEAVE }
|
||||
.map { it.groupId }
|
||||
.toList())
|
||||
}
|
||||
|
||||
private fun fetchGroupsData(groupIds: List<String>) {
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(userId, groupIds)
|
||||
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, newGroupIds)
|
||||
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
|
||||
|
||||
val sendWork = matrixOneTimeWorkRequestBuilder<GetGroupDataWorker>()
|
||||
|
@ -61,4 +74,15 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont
|
|||
.enqueue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the GroupSummaryEntity of left groups
|
||||
*/
|
||||
private fun deleteGroups(groupIds: List<String>) {
|
||||
monarchy
|
||||
.writeAsync { realm ->
|
||||
GroupSummaryEntity.where(realm, groupIds)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,9 +17,10 @@ package im.vector.matrix.android.internal.session.notification
|
|||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.pushrules.Action
|
||||
import im.vector.matrix.android.api.pushrules.PushRuleService
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.api.pushrules.RuleSetKey
|
||||
import im.vector.matrix.android.api.pushrules.getActions
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
@ -35,53 +36,60 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
@SessionScope
|
||||
internal class DefaultPushRuleService @Inject constructor(
|
||||
private val sessionParams: SessionParams,
|
||||
private val pushRulesTask: GetPushRulesTask,
|
||||
private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val monarchy: Monarchy
|
||||
internal class DefaultPushRuleService @Inject constructor(private val getPushRulesTask: GetPushRulesTask,
|
||||
private val updatePushRuleEnableStatusTask: UpdatePushRuleEnableStatusTask,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val monarchy: Monarchy
|
||||
) : PushRuleService {
|
||||
|
||||
private var listeners = ArrayList<PushRuleService.PushRuleListener>()
|
||||
|
||||
override fun fetchPushRules(scope: String) {
|
||||
pushRulesTask
|
||||
getPushRulesTask
|
||||
.configureWith(GetPushRulesTask.Params(scope))
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
|
||||
override fun getPushRules(scope: String): List<PushRule> {
|
||||
|
||||
var contentRules: List<PushRule> = emptyList()
|
||||
var overrideRules: List<PushRule> = emptyList()
|
||||
var roomRules: List<PushRule> = emptyList()
|
||||
var senderRules: List<PushRule> = emptyList()
|
||||
var underrideRules: List<PushRule> = emptyList()
|
||||
|
||||
// TODO Create const for ruleSetKey
|
||||
monarchy.doWithRealm { realm ->
|
||||
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "content").findFirst()?.let { re ->
|
||||
contentRules = re.pushRules.map { PushRulesMapper.mapContentRule(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "override").findFirst()?.let { re ->
|
||||
overrideRules = re.pushRules.map { PushRulesMapper.map(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "room").findFirst()?.let { re ->
|
||||
roomRules = re.pushRules.map { PushRulesMapper.mapRoomRule(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "sender").findFirst()?.let { re ->
|
||||
senderRules = re.pushRules.map { PushRulesMapper.mapSenderRule(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "underride").findFirst()?.let { re ->
|
||||
underrideRules = re.pushRules.map { PushRulesMapper.map(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, scope, RuleSetKey.CONTENT)
|
||||
.findFirst()
|
||||
?.let { pushRulesEntity ->
|
||||
contentRules = pushRulesEntity.pushRules.map { PushRulesMapper.mapContentRule(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, scope, RuleSetKey.OVERRIDE)
|
||||
.findFirst()
|
||||
?.let { pushRulesEntity ->
|
||||
overrideRules = pushRulesEntity.pushRules.map { PushRulesMapper.map(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, scope, RuleSetKey.ROOM)
|
||||
.findFirst()
|
||||
?.let { pushRulesEntity ->
|
||||
roomRules = pushRulesEntity.pushRules.map { PushRulesMapper.mapRoomRule(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, scope, RuleSetKey.SENDER)
|
||||
.findFirst()
|
||||
?.let { pushRulesEntity ->
|
||||
senderRules = pushRulesEntity.pushRules.map { PushRulesMapper.mapSenderRule(it) }
|
||||
}
|
||||
PushRulesEntity.where(realm, scope, RuleSetKey.UNDERRIDE)
|
||||
.findFirst()
|
||||
?.let { pushRulesEntity ->
|
||||
underrideRules = pushRulesEntity.pushRules.map { PushRulesMapper.map(it) }
|
||||
}
|
||||
}
|
||||
|
||||
return contentRules + overrideRules + roomRules + senderRules + underrideRules
|
||||
// Ref. for the order: https://matrix.org/docs/spec/client_server/latest#push-rules
|
||||
return overrideRules + contentRules + roomRules + senderRules + underrideRules
|
||||
}
|
||||
|
||||
override fun updatePushRuleEnableStatus(kind: String, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable {
|
||||
override fun updatePushRuleEnableStatus(kind: RuleKind, pushRule: PushRule, enabled: Boolean, callback: MatrixCallback<Unit>): Cancelable {
|
||||
return updatePushRuleEnableStatusTask
|
||||
.configureWith(UpdatePushRuleEnableStatusTask.Params(kind, pushRule, enabled)) {
|
||||
this.callback = callback
|
||||
|
@ -114,8 +122,9 @@ internal class DefaultPushRuleService @Inject constructor(
|
|||
|
||||
fun dispatchBing(event: Event, rule: PushRule) {
|
||||
try {
|
||||
val actionsList = rule.getActions()
|
||||
listeners.forEach {
|
||||
it.onMatchRule(event, Action.mapFrom(rule) ?: emptyList())
|
||||
it.onMatchRule(event, actionsList)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Error while dispatching bing")
|
||||
|
@ -132,6 +141,16 @@ internal class DefaultPushRuleService @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun dispatchRedactedEventId(redactedEventId: String) {
|
||||
try {
|
||||
listeners.forEach {
|
||||
it.onEventRedacted(redactedEventId)
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Error while dispatching room left")
|
||||
}
|
||||
}
|
||||
|
||||
fun dispatchFinish() {
|
||||
try {
|
||||
listeners.forEach {
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.notification
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
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.room.RoomService
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.pushers.DefaultConditionResolver
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomsSyncResponse
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
|
@ -37,7 +37,7 @@ internal interface ProcessEventForPushTask : Task<ProcessEventForPushTask.Params
|
|||
internal class DefaultProcessEventForPushTask @Inject constructor(
|
||||
private val defaultPushRuleService: DefaultPushRuleService,
|
||||
private val roomService: RoomService,
|
||||
private val sessionParams: SessionParams
|
||||
@UserId private val userId: String
|
||||
) : ProcessEventForPushTask {
|
||||
|
||||
override suspend fun execute(params: ProcessEventForPushTask.Params) {
|
||||
|
@ -68,7 +68,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
|
|||
else -> false
|
||||
}
|
||||
}.filter {
|
||||
it.senderId != sessionParams.credentials.userId
|
||||
it.senderId != userId
|
||||
}
|
||||
Timber.v("[PushRules] Found ${allEvents.size} out of ${(newJoinEvents + inviteEvents).size}" +
|
||||
" to check for push rules with ${params.rules.size} rules")
|
||||
|
@ -78,11 +78,31 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
|
|||
defaultPushRuleService.dispatchBing(event, it)
|
||||
}
|
||||
}
|
||||
|
||||
val allRedactedEvents = params.syncResponse.join
|
||||
.map { entries ->
|
||||
entries.value.timeline?.events?.filter {
|
||||
it.type == EventType.REDACTION
|
||||
}
|
||||
.orEmpty()
|
||||
.mapNotNull { it.redacts }
|
||||
}
|
||||
.fold(emptyList<String>(), { acc, next ->
|
||||
acc + next
|
||||
})
|
||||
|
||||
Timber.v("[PushRules] Found ${allRedactedEvents.size} redacted events")
|
||||
|
||||
allRedactedEvents.forEach { redactedEventId ->
|
||||
defaultPushRuleService.dispatchRedactedEventId(redactedEventId)
|
||||
}
|
||||
|
||||
defaultPushRuleService.dispatchFinish()
|
||||
}
|
||||
|
||||
private fun fulfilledBingRule(event: Event, rules: List<PushRule>): PushRule? {
|
||||
val conditionResolver = DefaultConditionResolver(event, roomService, sessionParams)
|
||||
// TODO This should be injected
|
||||
val conditionResolver = DefaultConditionResolver(event, roomService, userId)
|
||||
rules.filter { it.enabled }.forEach { rule ->
|
||||
val isFullfilled = rule.conditions?.map {
|
||||
it.asExecutableCondition()?.isSatisfied(conditionResolver) ?: false
|
||||
|
|
|
@ -57,14 +57,14 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
|
|||
return Result.failure()
|
||||
}
|
||||
return try {
|
||||
setPusher(pusher, params.userId)
|
||||
setPusher(pusher)
|
||||
Result.success()
|
||||
} catch (exception: Throwable) {
|
||||
when (exception) {
|
||||
is Failure.NetworkConnection -> Result.retry()
|
||||
else -> {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
PusherEntity.where(realm, params.userId, pusher.pushKey).findFirst()?.let {
|
||||
PusherEntity.where(realm, pusher.pushKey).findFirst()?.let {
|
||||
//update it
|
||||
it.state = PusherState.FAILED_TO_REGISTER
|
||||
}
|
||||
|
@ -76,12 +76,12 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun setPusher(pusher: JsonPusher, userId: String) {
|
||||
private suspend fun setPusher(pusher: JsonPusher) {
|
||||
executeRequest<Unit> {
|
||||
apiCall = pushersAPI.setPusher(pusher)
|
||||
}
|
||||
monarchy.awaitTransaction { realm ->
|
||||
val echo = PusherEntity.where(realm, userId, pusher.pushKey).findFirst()
|
||||
val echo = PusherEntity.where(realm, pusher.pushKey).findFirst()
|
||||
if (echo != null) {
|
||||
//update it
|
||||
echo.appDisplayName = pusher.appDisplayName
|
||||
|
@ -93,7 +93,7 @@ internal class AddHttpPusherWorker(context: Context, params: WorkerParameters)
|
|||
echo.data?.url = pusher.data?.url
|
||||
echo.state = PusherState.REGISTERED
|
||||
} else {
|
||||
pusher.toEntity(userId).also {
|
||||
pusher.toEntity().also {
|
||||
it.state = PusherState.REGISTERED
|
||||
realm.insertOrUpdate(it)
|
||||
}
|
||||
|
|
|
@ -15,15 +15,16 @@
|
|||
*/
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.pushrules.*
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import timber.log.Timber
|
||||
|
||||
// TODO Inject constructor
|
||||
internal class DefaultConditionResolver(private val event: Event,
|
||||
private val roomService: RoomService,
|
||||
private val sessionParams: SessionParams) : ConditionResolver {
|
||||
@UserId private val userId: String) : ConditionResolver {
|
||||
|
||||
|
||||
override fun resolveEventMatchCondition(eventMatchCondition: EventMatchCondition): Boolean {
|
||||
|
@ -45,8 +46,7 @@ internal class DefaultConditionResolver(private val event: Event,
|
|||
override fun resolveContainsDisplayNameCondition(containsDisplayNameCondition: ContainsDisplayNameCondition): Boolean {
|
||||
val roomId = event.roomId ?: return false
|
||||
val room = roomService.getRoom(roomId) ?: return false
|
||||
val myDisplayName = room.getRoomMember(sessionParams.credentials.userId)?.displayName
|
||||
?: return false
|
||||
val myDisplayName = room.getRoomMember(userId)?.displayName ?: return false
|
||||
return containsDisplayNameCondition.isSatisfied(event, myDisplayName)
|
||||
}
|
||||
}
|
|
@ -21,29 +21,28 @@ import androidx.work.BackoffPolicy
|
|||
import androidx.work.WorkManager
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.pushers.Pusher
|
||||
import im.vector.matrix.android.api.session.pushers.PushersService
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil
|
||||
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
internal class DefaultPusherService @Inject constructor(
|
||||
private val context: Context,
|
||||
private val monarchy: Monarchy,
|
||||
private val sessionParam: SessionParams,
|
||||
private val getPusherTask: GetPushersTask,
|
||||
private val removePusherTask: RemovePusherTask,
|
||||
private val taskExecutor: TaskExecutor
|
||||
internal class DefaultPusherService @Inject constructor(private val context: Context,
|
||||
private val monarchy: Monarchy,
|
||||
@UserId private val userId: String,
|
||||
private val getPusherTask: GetPushersTask,
|
||||
private val removePusherTask: RemovePusherTask,
|
||||
private val taskExecutor: TaskExecutor
|
||||
) : PushersService {
|
||||
|
||||
|
||||
|
@ -70,7 +69,7 @@ internal class DefaultPusherService @Inject constructor(
|
|||
append = append)
|
||||
|
||||
|
||||
val params = AddHttpPusherWorker.Params(pusher, sessionParam.credentials.userId)
|
||||
val params = AddHttpPusherWorker.Params(pusher, userId)
|
||||
|
||||
val request = matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()
|
||||
.setConstraints(WorkManagerUtil.workConstraints)
|
||||
|
@ -82,7 +81,7 @@ internal class DefaultPusherService @Inject constructor(
|
|||
}
|
||||
|
||||
override fun removeHttpPusher(pushkey: String, appId: String, callback: MatrixCallback<Unit>) {
|
||||
val params = RemovePusherTask.Params(sessionParam.credentials.userId, pushkey, appId)
|
||||
val params = RemovePusherTask.Params(pushkey, appId)
|
||||
removePusherTask
|
||||
.configureWith(params) {
|
||||
this.callback = callback
|
||||
|
@ -93,12 +92,12 @@ internal class DefaultPusherService @Inject constructor(
|
|||
|
||||
override fun livePushers(): LiveData<List<Pusher>> {
|
||||
return monarchy.findAllMappedWithChanges(
|
||||
{ realm -> PusherEntity.where(realm, sessionParam.credentials.userId) },
|
||||
{ realm -> PusherEntity.where(realm) },
|
||||
{ it.asDomain() }
|
||||
)
|
||||
}
|
||||
|
||||
override fun pushers(): List<Pusher> {
|
||||
return monarchy.fetchAllCopiedSync { PusherEntity.where(it, sessionParam.credentials.userId) }.map { it.asDomain() }
|
||||
return monarchy.fetchAllCopiedSync { PusherEntity.where(it) }.map { it.asDomain() }
|
||||
}
|
||||
}
|
|
@ -15,80 +15,27 @@
|
|||
*/
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
|
||||
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
internal interface GetPushRulesTask : Task<GetPushRulesTask.Params, Unit> {
|
||||
|
||||
data class Params(val scope: String)
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* We keep this task, but it should not be used anymore, the push rules comes from the sync response
|
||||
*/
|
||||
internal class DefaultGetPushRulesTask @Inject constructor(private val pushRulesApi: PushRulesApi,
|
||||
private val monarchy: Monarchy,
|
||||
private val sessionParams: SessionParams) : GetPushRulesTask {
|
||||
private val savePushRulesTask: SavePushRulesTask) : GetPushRulesTask {
|
||||
|
||||
override suspend fun execute(params: GetPushRulesTask.Params) {
|
||||
val response = executeRequest<GetPushRulesResponse> {
|
||||
apiCall = pushRulesApi.getAllRules()
|
||||
}
|
||||
val scope = params.scope
|
||||
monarchy.awaitTransaction { realm ->
|
||||
//clear existings?
|
||||
//TODO
|
||||
realm.where(PushRulesEntity::class.java)
|
||||
.equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId)
|
||||
.findAll().deleteAllFromRealm()
|
||||
|
||||
val content = PushRulesEntity(sessionParams.credentials.userId, scope, "content")
|
||||
response.global.content?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
content.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(content)
|
||||
|
||||
val override = PushRulesEntity(sessionParams.credentials.userId, scope, "override")
|
||||
response.global.override?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
override.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(override)
|
||||
|
||||
val rooms = PushRulesEntity(sessionParams.credentials.userId, scope, "room")
|
||||
response.global.room?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
rooms.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(rooms)
|
||||
|
||||
val senders = PushRulesEntity(sessionParams.credentials.userId, scope, "sender")
|
||||
response.global.sender?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
senders.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(senders)
|
||||
|
||||
val underrides = PushRulesEntity(sessionParams.credentials.userId, scope, "underride")
|
||||
response.global.underride?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
underrides.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(underrides)
|
||||
}
|
||||
savePushRulesTask.execute(SavePushRulesTask.Params(response))
|
||||
}
|
||||
}
|
|
@ -16,11 +16,9 @@
|
|||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.pushers.PusherState
|
||||
import im.vector.matrix.android.internal.database.mapper.toEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntity
|
||||
import im.vector.matrix.android.internal.database.model.PusherEntityFields
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
|
@ -29,8 +27,7 @@ import javax.inject.Inject
|
|||
internal interface GetPushersTask : Task<Unit, Unit>
|
||||
|
||||
internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI: PushersAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val sessionParams: SessionParams) : GetPushersTask {
|
||||
private val monarchy: Monarchy) : GetPushersTask {
|
||||
|
||||
override suspend fun execute(params: Unit) {
|
||||
val response = executeRequest<GetPushersResponse> {
|
||||
|
@ -39,10 +36,9 @@ internal class DefaultGetPusherTask @Inject constructor(private val pushersAPI:
|
|||
monarchy.awaitTransaction { realm ->
|
||||
//clear existings?
|
||||
realm.where(PusherEntity::class.java)
|
||||
.equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId)
|
||||
.findAll().deleteAllFromRealm()
|
||||
response.pushers?.forEach { jsonPusher ->
|
||||
jsonPusher.toEntity(sessionParams.credentials.userId).also {
|
||||
jsonPusher.toEntity().also {
|
||||
it.state = PusherState.REGISTERED
|
||||
realm.insertOrUpdate(it)
|
||||
}
|
||||
|
|
|
@ -59,6 +59,9 @@ internal abstract class PushersModule {
|
|||
@Binds
|
||||
abstract fun bindGetPushRulesTask(getPushRulesTask: DefaultGetPushRulesTask): GetPushRulesTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindSavePushRulesTask(savePushRulesTask: DefaultSavePushRulesTask): SavePushRulesTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindRemovePusherTask(removePusherTask: DefaultRemovePusherTask): RemovePusherTask
|
||||
|
||||
|
|
|
@ -28,8 +28,7 @@ import io.realm.Realm
|
|||
import javax.inject.Inject
|
||||
|
||||
internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
|
||||
data class Params(val userId: String,
|
||||
val pushKey: String,
|
||||
data class Params(val pushKey: String,
|
||||
val pushAppId: String)
|
||||
}
|
||||
|
||||
|
@ -40,12 +39,12 @@ internal class DefaultRemovePusherTask @Inject constructor(
|
|||
|
||||
override suspend fun execute(params: RemovePusherTask.Params) {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
val existingEntity = PusherEntity.where(realm, params.userId, params.pushKey).findFirst()
|
||||
val existingEntity = PusherEntity.where(realm, params.pushKey).findFirst()
|
||||
existingEntity?.state = PusherState.UNREGISTERING
|
||||
}
|
||||
|
||||
val existing = Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
PusherEntity.where(realm, params.userId, params.pushKey).findFirst()?.asDomain()
|
||||
PusherEntity.where(realm, params.pushKey).findFirst()?.asDomain()
|
||||
} ?: throw Exception("No existing pusher")
|
||||
|
||||
val deleteBody = JsonPusher(
|
||||
|
@ -64,7 +63,7 @@ internal class DefaultRemovePusherTask @Inject constructor(
|
|||
apiCall = pushersAPI.setPusher(deleteBody)
|
||||
}
|
||||
monarchy.awaitTransaction {
|
||||
PusherEntity.where(it, params.userId, params.pushKey).findFirst()?.deleteFromRealm()
|
||||
PusherEntity.where(it, params.pushKey).findFirst()?.deleteFromRealm()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.pushrules.RuleScope
|
||||
import im.vector.matrix.android.api.pushrules.RuleSetKey
|
||||
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
|
||||
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
|
||||
import im.vector.matrix.android.internal.database.model.PushRulesEntity
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
/**
|
||||
* Save the push rules in DB
|
||||
*/
|
||||
internal interface SavePushRulesTask : Task<SavePushRulesTask.Params, Unit> {
|
||||
data class Params(val pushRules: GetPushRulesResponse)
|
||||
}
|
||||
|
||||
internal class DefaultSavePushRulesTask @Inject constructor(private val monarchy: Monarchy) : SavePushRulesTask {
|
||||
|
||||
override suspend fun execute(params: SavePushRulesTask.Params) {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
// clear current push rules
|
||||
realm.where(PushRulesEntity::class.java)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
|
||||
// Save only global rules for the moment
|
||||
val globalRules = params.pushRules.global
|
||||
|
||||
val content = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.CONTENT }
|
||||
globalRules.content?.forEach { rule ->
|
||||
content.pushRules.add(PushRulesMapper.map(rule))
|
||||
}
|
||||
realm.insertOrUpdate(content)
|
||||
|
||||
val override = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.OVERRIDE }
|
||||
globalRules.override?.forEach { rule ->
|
||||
PushRulesMapper.map(rule).also {
|
||||
override.pushRules.add(it)
|
||||
}
|
||||
}
|
||||
realm.insertOrUpdate(override)
|
||||
|
||||
val rooms = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.ROOM }
|
||||
globalRules.room?.forEach { rule ->
|
||||
rooms.pushRules.add(PushRulesMapper.map(rule))
|
||||
}
|
||||
realm.insertOrUpdate(rooms)
|
||||
|
||||
val senders = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.SENDER }
|
||||
globalRules.sender?.forEach { rule ->
|
||||
senders.pushRules.add(PushRulesMapper.map(rule))
|
||||
}
|
||||
realm.insertOrUpdate(senders)
|
||||
|
||||
val underrides = PushRulesEntity(RuleScope.GLOBAL).apply { kind = RuleSetKey.UNDERRIDE }
|
||||
globalRules.underride?.forEach { rule ->
|
||||
underrides.pushRules.add(PushRulesMapper.map(rule))
|
||||
}
|
||||
realm.insertOrUpdate(underrides)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package im.vector.matrix.android.internal.session.pushers
|
||||
|
||||
import im.vector.matrix.android.api.pushrules.RuleKind
|
||||
import im.vector.matrix.android.api.pushrules.rest.PushRule
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
|
@ -22,7 +23,7 @@ import javax.inject.Inject
|
|||
|
||||
|
||||
internal interface UpdatePushRuleEnableStatusTask : Task<UpdatePushRuleEnableStatusTask.Params, Unit> {
|
||||
data class Params(val kind: String,
|
||||
data class Params(val kind: RuleKind,
|
||||
val pushRule: PushRule,
|
||||
val enabled: Boolean)
|
||||
}
|
||||
|
@ -32,7 +33,7 @@ internal class DefaultUpdatePushRuleEnableStatusTask @Inject constructor(private
|
|||
|
||||
override suspend fun execute(params: UpdatePushRuleEnableStatusTask.Params) {
|
||||
return executeRequest {
|
||||
apiCall = pushRulesApi.updateEnableRuleStatus(params.kind, params.pushRule.ruleId, params.enabled)
|
||||
apiCall = pushRulesApi.updateEnableRuleStatus(params.kind.value, params.pushRule.ruleId, params.enabled)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import im.vector.matrix.android.api.session.room.members.MembershipService
|
|||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.relation.RelationService
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.api.session.room.send.DraftService
|
||||
import im.vector.matrix.android.api.session.room.send.SendService
|
||||
import im.vector.matrix.android.api.session.room.state.StateService
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
|
@ -40,6 +41,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
|||
private val roomSummaryMapper: RoomSummaryMapper,
|
||||
private val timelineService: TimelineService,
|
||||
private val sendService: SendService,
|
||||
private val draftService: DraftService,
|
||||
private val stateService: StateService,
|
||||
private val readService: ReadService,
|
||||
private val cryptoService: CryptoService,
|
||||
|
@ -48,6 +50,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
|
|||
) : Room,
|
||||
TimelineService by timelineService,
|
||||
SendService by sendService,
|
||||
DraftService by draftService,
|
||||
StateService by stateService,
|
||||
ReadService by readService,
|
||||
RelationService by relationService,
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.query.types
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import io.realm.OrderedCollectionChangeSet
|
||||
|
@ -38,7 +38,7 @@ import javax.inject.Inject
|
|||
*/
|
||||
|
||||
internal class EventRelationsAggregationUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val task: EventRelationsAggregationTask,
|
||||
private val taskExecutor: TaskExecutor) :
|
||||
RealmLiveEntityObserver<EventEntity>(realmConfiguration) {
|
||||
|
@ -61,7 +61,7 @@ internal class EventRelationsAggregationUpdater @Inject constructor(@SessionData
|
|||
.toList()
|
||||
val params = EventRelationsAggregationTask.Params(
|
||||
insertedDomains,
|
||||
credentials.userId
|
||||
userId
|
||||
)
|
||||
task.configureWith(params).executeBy(taskExecutor)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.RoomAvatarContent
|
||||
|
@ -27,11 +26,12 @@ import im.vector.matrix.android.internal.database.model.EventEntity
|
|||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.prev
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomAvatarResolver @Inject constructor(private val monarchy: Monarchy,
|
||||
private val credentials: Credentials) {
|
||||
@UserId private val userId: String) {
|
||||
|
||||
/**
|
||||
* Compute the room avatar url
|
||||
|
@ -52,7 +52,7 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona
|
|||
if (members.size == 1) {
|
||||
res = members.firstOrNull()?.toRoomMember()?.avatarUrl
|
||||
} else if (members.size == 2) {
|
||||
val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, credentials.userId).findFirst()
|
||||
val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, userId).findFirst()
|
||||
res = firstOtherMember?.toRoomMember()?.avatarUrl
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import com.zhuinden.monarchy.Monarchy
|
|||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper
|
||||
import im.vector.matrix.android.internal.session.room.draft.DefaultDraftService
|
||||
import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService
|
||||
import im.vector.matrix.android.internal.session.room.read.DefaultReadService
|
||||
import im.vector.matrix.android.internal.session.room.relation.DefaultRelationService
|
||||
|
@ -38,6 +39,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
|
|||
private val cryptoService: CryptoService,
|
||||
private val timelineServiceFactory: DefaultTimelineService.Factory,
|
||||
private val sendServiceFactory: DefaultSendService.Factory,
|
||||
private val draftServiceFactory: DefaultDraftService.Factory,
|
||||
private val stateServiceFactory: DefaultStateService.Factory,
|
||||
private val readServiceFactory: DefaultReadService.Factory,
|
||||
private val relationServiceFactory: DefaultRelationService.Factory,
|
||||
|
@ -51,6 +53,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
|
|||
roomSummaryMapper,
|
||||
timelineServiceFactory.create(roomId),
|
||||
sendServiceFactory.create(roomId),
|
||||
draftServiceFactory.create(roomId),
|
||||
stateServiceFactory.create(roomId),
|
||||
readServiceFactory.create(roomId),
|
||||
cryptoService,
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.room
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
|
@ -26,9 +26,11 @@ import im.vector.matrix.android.internal.database.model.EventEntity
|
|||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
import im.vector.matrix.android.internal.database.query.isEventRead
|
||||
import im.vector.matrix.android.internal.database.query.latestEvent
|
||||
import im.vector.matrix.android.internal.database.query.prev
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary
|
||||
|
@ -37,9 +39,10 @@ import io.realm.Realm
|
|||
import io.realm.kotlin.createObject
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class RoomSummaryUpdater @Inject constructor(private val credentials: Credentials,
|
||||
internal class RoomSummaryUpdater @Inject constructor(@UserId private val userId: String,
|
||||
private val roomDisplayNameResolver: RoomDisplayNameResolver,
|
||||
private val roomAvatarResolver: RoomAvatarResolver) {
|
||||
private val roomAvatarResolver: RoomAvatarResolver,
|
||||
private val monarchy: Monarchy) {
|
||||
|
||||
// TODO: maybe allow user of SDK to give that list
|
||||
private val PREVIEWABLE_TYPES = listOf(
|
||||
|
@ -63,8 +66,7 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
|||
membership: Membership? = null,
|
||||
roomSummary: RoomSyncSummary? = null,
|
||||
unreadNotifications: RoomSyncUnreadNotifications? = null) {
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst()
|
||||
?: realm.createObject(roomId)
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
||||
|
||||
if (roomSummary != null) {
|
||||
if (roomSummary.heroes.isNotEmpty()) {
|
||||
|
@ -85,12 +87,16 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
|||
roomSummaryEntity.membership = membership
|
||||
}
|
||||
|
||||
val latestEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES)
|
||||
val latestPreviewableEvent = TimelineEventEntity.latestEvent(realm, roomId, includesSending = true, includedTypes = PREVIEWABLE_TYPES)
|
||||
val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain()
|
||||
|
||||
roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0
|
||||
//avoid this call if we are sure there are unread events
|
||||
|| !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId)
|
||||
|
||||
val otherRoomMembers = RoomMembers(realm, roomId)
|
||||
.queryRoomMembersEvent()
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, credentials.userId)
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, userId)
|
||||
.findAll()
|
||||
.asSequence()
|
||||
.map { it.stateKey }
|
||||
|
@ -98,9 +104,8 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C
|
|||
roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString()
|
||||
roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId)
|
||||
roomSummaryEntity.topic = lastTopicEvent?.content.toModel<RoomTopicContent>()?.topic
|
||||
roomSummaryEntity.latestEvent = latestEvent
|
||||
roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent
|
||||
roomSummaryEntity.otherMemberIds.clear()
|
||||
roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers)
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.draft
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.BuildConfig
|
||||
import im.vector.matrix.android.api.session.room.send.DraftService
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||
import im.vector.matrix.android.internal.database.mapper.DraftMapper
|
||||
import im.vector.matrix.android.internal.database.model.DraftEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.UserDraftsEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import io.realm.kotlin.createObject
|
||||
import timber.log.Timber
|
||||
|
||||
internal class DefaultDraftService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||
private val monarchy: Monarchy
|
||||
) : DraftService {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(roomId: String): DraftService
|
||||
}
|
||||
|
||||
/**
|
||||
* The draft stack can contain several drafts. Depending of the draft to save, it will update the top draft, or create a new draft,
|
||||
* or even move an existing draft to the top of the list
|
||||
*/
|
||||
override fun saveDraft(draft: UserDraft) {
|
||||
Timber.d("Draft: saveDraft ${privacySafe(draft)}")
|
||||
|
||||
monarchy.writeAsync { realm ->
|
||||
|
||||
val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: realm.createObject(roomId)
|
||||
|
||||
val userDraftsEntity = roomSummaryEntity.userDrafts
|
||||
?: realm.createObject<UserDraftsEntity>().also {
|
||||
roomSummaryEntity.userDrafts = it
|
||||
}
|
||||
|
||||
userDraftsEntity.let { userDraftEntity ->
|
||||
// Save only valid draft
|
||||
if (draft.isValid()) {
|
||||
// Add a new draft or update the current one?
|
||||
val newDraft = DraftMapper.map(draft)
|
||||
|
||||
// Is it an update of the top draft?
|
||||
val topDraft = userDraftEntity.userDrafts.lastOrNull()
|
||||
|
||||
if (topDraft == null) {
|
||||
Timber.d("Draft: create a new draft ${privacySafe(draft)}")
|
||||
userDraftEntity.userDrafts.add(newDraft)
|
||||
} else if (topDraft.draftMode == DraftEntity.MODE_EDIT) {
|
||||
// top draft is an edit
|
||||
if (newDraft.draftMode == DraftEntity.MODE_EDIT) {
|
||||
if (topDraft.linkedEventId == newDraft.linkedEventId) {
|
||||
// Update the top draft
|
||||
Timber.d("Draft: update the top edit draft ${privacySafe(draft)}")
|
||||
topDraft.content = newDraft.content
|
||||
} else {
|
||||
// Check a previously EDIT draft with the same id
|
||||
val existingEditDraftOfSameEvent = userDraftEntity.userDrafts.find {
|
||||
it.draftMode == DraftEntity.MODE_EDIT && it.linkedEventId == newDraft.linkedEventId
|
||||
}
|
||||
|
||||
if (existingEditDraftOfSameEvent != null) {
|
||||
// Ignore the new text, restore what was typed before, by putting the draft to the top
|
||||
Timber.d("Draft: restore a previously edit draft ${privacySafe(draft)}")
|
||||
userDraftEntity.userDrafts.remove(existingEditDraftOfSameEvent)
|
||||
userDraftEntity.userDrafts.add(existingEditDraftOfSameEvent)
|
||||
} else {
|
||||
Timber.d("Draft: add a new edit draft ${privacySafe(draft)}")
|
||||
userDraftEntity.userDrafts.add(newDraft)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Add a new regular draft to the top
|
||||
Timber.d("Draft: add a new draft ${privacySafe(draft)}")
|
||||
userDraftEntity.userDrafts.add(newDraft)
|
||||
}
|
||||
} else {
|
||||
// Top draft is not an edit
|
||||
if (newDraft.draftMode == DraftEntity.MODE_EDIT) {
|
||||
Timber.d("Draft: create a new edit draft ${privacySafe(draft)}")
|
||||
userDraftEntity.userDrafts.add(newDraft)
|
||||
} else {
|
||||
// Update the top draft
|
||||
Timber.d("Draft: update the top draft ${privacySafe(draft)}")
|
||||
topDraft.draftMode = newDraft.draftMode
|
||||
topDraft.content = newDraft.content
|
||||
topDraft.linkedEventId = newDraft.linkedEventId
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// There is no draft to save, so the composer was clear
|
||||
Timber.d("Draft: delete a draft")
|
||||
|
||||
val topDraft = userDraftEntity.userDrafts.lastOrNull()
|
||||
|
||||
if (topDraft == null) {
|
||||
Timber.d("Draft: nothing to do")
|
||||
} else {
|
||||
// Remove the top draft
|
||||
Timber.d("Draft: remove the top draft")
|
||||
userDraftEntity.userDrafts.remove(topDraft)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun privacySafe(o: Any): Any {
|
||||
if (BuildConfig.LOG_PRIVATE_DATA) {
|
||||
return o
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
override fun deleteDraft() {
|
||||
Timber.d("Draft: deleteDraft()")
|
||||
|
||||
monarchy.writeAsync { realm ->
|
||||
UserDraftsEntity.where(realm, roomId).findFirst()?.let { userDraftsEntity ->
|
||||
if (userDraftsEntity.userDrafts.isNotEmpty()) {
|
||||
userDraftsEntity.userDrafts.removeAt(userDraftsEntity.userDrafts.size - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDraftsLive(): LiveData<List<UserDraft>> {
|
||||
val liveData = RealmLiveData(monarchy.realmConfiguration) {
|
||||
UserDraftsEntity.where(it, roomId)
|
||||
}
|
||||
|
||||
return Transformations.map(liveData) { userDraftsEntities ->
|
||||
userDraftsEntities.firstOrNull()?.let { userDraftEntity ->
|
||||
userDraftEntity.userDrafts.map { draftEntity ->
|
||||
DraftMapper.map(draftEntity)
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.room.membership
|
|||
import android.content.Context
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.*
|
||||
|
@ -30,6 +29,7 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
|
|||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.prev
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ import javax.inject.Inject
|
|||
*/
|
||||
internal class RoomDisplayNameResolver @Inject constructor(private val context: Context,
|
||||
private val monarchy: Monarchy,
|
||||
private val credentials: Credentials
|
||||
@UserId private val userId: String
|
||||
) {
|
||||
|
||||
/**
|
||||
|
@ -79,7 +79,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
|||
|
||||
|
||||
if (roomEntity?.membership == Membership.INVITE) {
|
||||
val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst()
|
||||
val inviteMeEvent = roomMembers.queryRoomMemberEvent(userId).findFirst()
|
||||
val inviterId = inviteMeEvent?.sender
|
||||
name = if (inviterId != null) {
|
||||
val inviterMemberEvent = loadedMembers.where()
|
||||
|
@ -97,7 +97,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context:
|
|||
}
|
||||
} else {
|
||||
loadedMembers.where()
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, credentials.userId)
|
||||
.notEqualTo(EventEntityFields.STATE_KEY, userId)
|
||||
.limit(3)
|
||||
.findAll()
|
||||
}
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
package im.vector.matrix.android.internal.session.room.prune
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.query.types
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import io.realm.OrderedCollectionChangeSet
|
||||
|
@ -37,7 +37,7 @@ import javax.inject.Inject
|
|||
* As it will actually delete the content, it should be called last in the list of listener.
|
||||
*/
|
||||
internal class EventsPruner @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val pruneEventTask: PruneEventTask,
|
||||
private val taskExecutor: TaskExecutor) :
|
||||
RealmLiveEntityObserver<EventEntity>(realmConfiguration) {
|
||||
|
@ -54,7 +54,7 @@ internal class EventsPruner @Inject constructor(@SessionDatabase realmConfigurat
|
|||
|
||||
val params = PruneEventTask.Params(
|
||||
insertedDomains,
|
||||
credentials.userId
|
||||
userId
|
||||
)
|
||||
pruneEventTask.configureWith(params).executeBy(taskExecutor)
|
||||
}
|
||||
|
|
|
@ -22,17 +22,14 @@ import com.squareup.inject.assisted.Assisted
|
|||
import com.squareup.inject.assisted.AssistedInject
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.room.model.ReadReceipt
|
||||
import im.vector.matrix.android.api.session.room.read.ReadService
|
||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||
import im.vector.matrix.android.internal.database.mapper.ReadReceiptsSummaryMapper
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.find
|
||||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.isEventRead
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
|
||||
|
@ -41,7 +38,7 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private
|
|||
private val taskExecutor: TaskExecutor,
|
||||
private val setReadMarkersTask: SetReadMarkersTask,
|
||||
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper,
|
||||
private val credentials: Credentials
|
||||
@UserId private val userId: String
|
||||
) : ReadService {
|
||||
|
||||
@AssistedInject.Factory
|
||||
|
@ -78,19 +75,7 @@ internal class DefaultReadService @AssistedInject constructor(@Assisted private
|
|||
|
||||
|
||||
override fun isEventRead(eventId: String): Boolean {
|
||||
var isEventRead = false
|
||||
monarchy.doWithRealm {
|
||||
val readReceipt = ReadReceiptEntity.where(it, roomId, credentials.userId).findFirst()
|
||||
?: return@doWithRealm
|
||||
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
|
||||
?: return@doWithRealm
|
||||
val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.root?.displayIndex
|
||||
?: Int.MIN_VALUE
|
||||
val eventToCheckIndex = liveChunk.timelineEvents.find(eventId)?.root?.displayIndex
|
||||
?: Int.MAX_VALUE
|
||||
isEventRead = eventToCheckIndex <= readReceiptIndex
|
||||
}
|
||||
return isEventRead
|
||||
return isEventRead(monarchy, userId, roomId, eventId)
|
||||
}
|
||||
|
||||
override fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package im.vector.matrix.android.internal.session.room.read
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.ReadReceiptEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
|
@ -26,6 +25,7 @@ import im.vector.matrix.android.internal.database.query.find
|
|||
import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
|
||||
import im.vector.matrix.android.internal.database.query.latestEvent
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
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.session.room.send.LocalEchoEventFactory
|
||||
|
@ -48,7 +48,7 @@ private const val READ_MARKER = "m.fully_read"
|
|||
private const val READ_RECEIPT = "m.read"
|
||||
|
||||
internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI: RoomAPI,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val monarchy: Monarchy
|
||||
) : SetReadMarkersTask {
|
||||
|
||||
|
@ -101,6 +101,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
|
|||
?: return@writeAsync
|
||||
roomSummary.notificationCount = 0
|
||||
roomSummary.highlightCount = 0
|
||||
roomSummary.hasUnreadMessages = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +109,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor(private val roomAPI
|
|||
private fun isEventRead(roomId: String, eventId: String): Boolean {
|
||||
var isEventRead = false
|
||||
monarchy.doWithRealm {
|
||||
val readReceipt = ReadReceiptEntity.where(it, roomId, credentials.userId).findFirst()
|
||||
val readReceipt = ReadReceiptEntity.where(it, roomId, userId).findFirst()
|
||||
?: return@doWithRealm
|
||||
val liveChunk = ChunkEntity.findLastLiveChunkFromRoom(it, roomId)
|
||||
?: return@doWithRealm
|
||||
|
|
|
@ -23,7 +23,6 @@ import com.squareup.inject.assisted.Assisted
|
|||
import com.squareup.inject.assisted.AssistedInject
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
|
@ -37,6 +36,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
|
|||
import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.room.send.EncryptEventWorker
|
||||
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
|
||||
import im.vector.matrix.android.internal.session.room.send.RedactEventWorker
|
||||
|
@ -50,7 +50,7 @@ import timber.log.Timber
|
|||
|
||||
internal class DefaultRelationService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||
private val context: Context,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val eventFactory: LocalEchoEventFactory,
|
||||
private val cryptoService: CryptoService,
|
||||
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
|
||||
|
@ -111,7 +111,7 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
|||
//TODO duplicate with send service?
|
||||
private fun createRedactEventWork(localEvent: Event, eventId: String, reason: String?): OneTimeWorkRequest {
|
||||
val sendContentWorkerParams = RedactEventWorker.Params(
|
||||
credentials.userId,
|
||||
userId,
|
||||
localEvent.eventId!!,
|
||||
roomId,
|
||||
eventId,
|
||||
|
@ -199,13 +199,13 @@ internal class DefaultRelationService @AssistedInject constructor(@Assisted priv
|
|||
|
||||
private fun createEncryptEventWork(event: Event, keepKeys: List<String>?): OneTimeWorkRequest {
|
||||
// Same parameter
|
||||
val params = EncryptEventWorker.Params(credentials.userId, roomId, event, keepKeys)
|
||||
val params = EncryptEventWorker.Params(userId, roomId, event, keepKeys)
|
||||
val sendWorkData = WorkerParamsFactory.toData(params)
|
||||
return TimelineSendEventWorkCommon.createWork<EncryptEventWorker>(sendWorkData, true)
|
||||
}
|
||||
|
||||
private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest {
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendContentWorkerParams = SendEventWorker.Params(userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
|
||||
}
|
||||
|
|
|
@ -17,22 +17,13 @@
|
|||
package im.vector.matrix.android.internal.session.room.send
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.BackoffPolicy
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.Operation
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.*
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.matrix.android.api.session.crypto.CryptoService
|
||||
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.isImageMessage
|
||||
import im.vector.matrix.android.api.session.events.model.isTextMessage
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.events.model.*
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageType
|
||||
import im.vector.matrix.android.api.session.room.send.SendService
|
||||
|
@ -46,6 +37,7 @@ import im.vector.matrix.android.internal.database.model.RoomEntity
|
|||
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
|
||||
import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
|
||||
import im.vector.matrix.android.internal.util.CancelableWork
|
||||
|
@ -63,7 +55,7 @@ private const val BACKOFF_DELAY = 10_000L
|
|||
|
||||
internal class DefaultSendService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||
private val context: Context,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val localEchoEventFactory: LocalEchoEventFactory,
|
||||
private val cryptoService: CryptoService,
|
||||
private val monarchy: Monarchy
|
||||
|
@ -75,6 +67,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private
|
|||
}
|
||||
|
||||
private val workerFutureListenerExecutor = Executors.newSingleThreadExecutor()
|
||||
|
||||
override fun sendTextMessage(text: String, msgType: String, autoMarkdown: Boolean): Cancelable {
|
||||
val event = localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown).also {
|
||||
saveLocalEcho(it)
|
||||
|
@ -165,12 +158,10 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private
|
|||
|
||||
override fun deleteFailedEcho(localEcho: TimelineEvent) {
|
||||
monarchy.writeAsync { realm ->
|
||||
TimelineEventEntity.where(realm, eventId = localEcho.root.eventId
|
||||
?: "").findFirst()?.let {
|
||||
TimelineEventEntity.where(realm, eventId = localEcho.root.eventId ?: "").findFirst()?.let {
|
||||
it.deleteFromRealm()
|
||||
}
|
||||
EventEntity.where(realm, eventId = localEcho.root.eventId
|
||||
?: "").findFirst()?.let {
|
||||
EventEntity.where(realm, eventId = localEcho.root.eventId ?: "").findFirst()?.let {
|
||||
it.deleteFromRealm()
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +288,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private
|
|||
|
||||
private fun createEncryptEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest {
|
||||
// Same parameter
|
||||
val params = EncryptEventWorker.Params(credentials.userId, roomId, event)
|
||||
val params = EncryptEventWorker.Params(userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(params)
|
||||
|
||||
return matrixOneTimeWorkRequestBuilder<EncryptEventWorker>()
|
||||
|
@ -309,7 +300,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private
|
|||
}
|
||||
|
||||
private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest {
|
||||
val sendContentWorkerParams = SendEventWorker.Params(credentials.userId, roomId, event)
|
||||
val sendContentWorkerParams = SendEventWorker.Params(userId, roomId, event)
|
||||
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
|
||||
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
|
||||
|
@ -319,7 +310,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private
|
|||
val redactEvent = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason).also {
|
||||
saveLocalEcho(it)
|
||||
}
|
||||
val sendContentWorkerParams = RedactEventWorker.Params(credentials.userId, redactEvent.eventId!!, roomId, event.eventId, reason)
|
||||
val sendContentWorkerParams = RedactEventWorker.Params(userId, redactEvent.eventId!!, roomId, event.eventId, reason)
|
||||
val redactWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
|
||||
return TimelineSendEventWorkCommon.createWork<RedactEventWorker>(redactWorkData, true)
|
||||
}
|
||||
|
@ -328,7 +319,7 @@ internal class DefaultSendService @AssistedInject constructor(@Assisted private
|
|||
attachment: ContentAttachmentData,
|
||||
isRoomEncrypted: Boolean,
|
||||
startChain: Boolean): OneTimeWorkRequest {
|
||||
val uploadMediaWorkerParams = UploadContentWorker.Params(credentials.userId, roomId, event, attachment, isRoomEncrypted)
|
||||
val uploadMediaWorkerParams = UploadContentWorker.Params(userId, roomId, event, attachment, isRoomEncrypted)
|
||||
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)
|
||||
|
||||
return matrixOneTimeWorkRequestBuilder<UploadContentWorker>()
|
||||
|
|
|
@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.session.room.send
|
|||
import android.media.MediaMetadataRetriever
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.permalinks.PermalinkFactory
|
||||
import im.vector.matrix.android.api.session.content.ContentAttachmentData
|
||||
import im.vector.matrix.android.api.session.events.model.*
|
||||
|
@ -33,12 +32,13 @@ import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
|||
import im.vector.matrix.android.internal.database.helper.addSendingEvent
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.content.ThumbnailExtractor
|
||||
import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
|
||||
import im.vector.matrix.android.internal.util.StringProvider
|
||||
import org.commonmark.parser.Parser
|
||||
import org.commonmark.renderer.html.HtmlRenderer
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -50,7 +50,7 @@ import javax.inject.Inject
|
|||
*
|
||||
* The transactionID is used as loc
|
||||
*/
|
||||
internal class LocalEchoEventFactory @Inject constructor(private val credentials: Credentials,
|
||||
internal class LocalEchoEventFactory @Inject constructor(@UserId private val userId: String,
|
||||
private val stringProvider: StringProvider,
|
||||
private val roomSummaryUpdater: RoomSummaryUpdater) {
|
||||
// TODO Inject
|
||||
|
@ -163,7 +163,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
|
|||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
senderId = credentials.userId,
|
||||
senderId = userId,
|
||||
eventId = localId,
|
||||
type = EventType.REACTION,
|
||||
content = content.toContent(),
|
||||
|
@ -255,7 +255,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
|
|||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
senderId = credentials.userId,
|
||||
senderId = userId,
|
||||
eventId = localID,
|
||||
type = EventType.MESSAGE,
|
||||
content = content.toContent(),
|
||||
|
@ -373,7 +373,7 @@ internal class LocalEchoEventFactory @Inject constructor(private val credentials
|
|||
return Event(
|
||||
roomId = roomId,
|
||||
originServerTs = dummyOriginServerTs(),
|
||||
senderId = credentials.userId,
|
||||
senderId = userId,
|
||||
eventId = localID,
|
||||
type = EventType.REDACTION,
|
||||
redacts = eventId,
|
||||
|
|
|
@ -32,8 +32,8 @@ internal interface GetContextOfEventTask : Task<GetContextOfEventTask.Params, To
|
|||
}
|
||||
|
||||
internal class DefaultGetContextOfEventTask @Inject constructor(private val roomAPI: RoomAPI,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val tokenChunkEventPersistor: TokenChunkEventPersistor
|
||||
private val filterRepository: FilterRepository,
|
||||
private val tokenChunkEventPersistor: TokenChunkEventPersistor
|
||||
) : GetContextOfEventTask {
|
||||
|
||||
override suspend fun execute(params: GetContextOfEventTask.Params): TokenChunkEventPersistor.Result {
|
||||
|
|
|
@ -106,7 +106,7 @@ internal class TimelineEventDecryptor(
|
|||
Timber.v("Successfully decrypted event ${eventId}")
|
||||
eventEntity.setDecryptionResult(result)
|
||||
} catch (e: MXCryptoError) {
|
||||
Timber.v("Failed to decrypte event ${eventId} ${e}")
|
||||
Timber.v("Failed to decrypt event ${eventId} ${e}")
|
||||
if (e is MXCryptoError.Base && e.errorType == MXCryptoError.ErrorType.UNKNOWN_INBOUND_SESSION_ID) {
|
||||
//Keep track of unknown sessions to automatically try to decrypt on new session
|
||||
eventEntity.decryptionErrorCode = e.errorType.name
|
||||
|
|
|
@ -17,15 +17,11 @@
|
|||
package im.vector.matrix.android.internal.session.signout
|
||||
|
||||
import android.content.Context
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.SessionManager
|
||||
import im.vector.matrix.android.internal.auth.SessionParamsStore
|
||||
import im.vector.matrix.android.internal.crypto.CryptoModule
|
||||
import im.vector.matrix.android.internal.database.RealmKeysUtils
|
||||
import im.vector.matrix.android.internal.di.CryptoDatabase
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.di.UserCacheDirectory
|
||||
import im.vector.matrix.android.internal.di.UserMd5
|
||||
import im.vector.matrix.android.internal.di.*
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.SessionModule
|
||||
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
|
||||
|
@ -38,7 +34,7 @@ import javax.inject.Inject
|
|||
internal interface SignOutTask : Task<Unit, Unit>
|
||||
|
||||
internal class DefaultSignOutTask @Inject constructor(private val context: Context,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val signOutAPI: SignOutAPI,
|
||||
private val sessionManager: SessionManager,
|
||||
private val sessionParamsStore: SessionParamsStore,
|
||||
|
@ -55,13 +51,13 @@ internal class DefaultSignOutTask @Inject constructor(private val context: Conte
|
|||
}
|
||||
|
||||
Timber.d("SignOut: release session...")
|
||||
sessionManager.releaseSession(credentials.userId)
|
||||
sessionManager.releaseSession(userId)
|
||||
|
||||
Timber.d("SignOut: cancel pending works...")
|
||||
WorkManagerUtil.cancelAllWorks(context)
|
||||
|
||||
Timber.d("SignOut: delete session params...")
|
||||
sessionParamsStore.delete(credentials.userId)
|
||||
sessionParamsStore.delete(userId)
|
||||
|
||||
Timber.d("SignOut: clear session data...")
|
||||
clearSessionDataTask.execute(Unit)
|
||||
|
|
|
@ -64,12 +64,13 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
/** Note: [im.vector.matrix.android.internal.session.group.GroupSummaryUpdater] is observing changes */
|
||||
realm.insertOrUpdate(groups)
|
||||
}
|
||||
|
||||
private fun handleJoinedGroup(realm: Realm,
|
||||
groupId: String): GroupEntity {
|
||||
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
groupEntity.membership = Membership.JOIN
|
||||
return groupEntity
|
||||
|
@ -77,21 +78,16 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc
|
|||
|
||||
private fun handleInvitedGroup(realm: Realm,
|
||||
groupId: String): GroupEntity {
|
||||
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
groupEntity.membership = Membership.INVITE
|
||||
return groupEntity
|
||||
|
||||
}
|
||||
|
||||
// TODO : handle it
|
||||
private fun handleLeftGroup(realm: Realm,
|
||||
groupId: String): GroupEntity {
|
||||
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
groupEntity.membership = Membership.LEAVE
|
||||
return groupEntity
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.sync
|
|||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.api.pushrules.RuleScope
|
||||
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
|
||||
|
@ -77,11 +78,11 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
private fun checkPushRules(roomsSyncResponse: RoomsSyncResponse) {
|
||||
Timber.v("[PushRules] --> checkPushRules")
|
||||
if (tokenStore.getLastToken() == null) {
|
||||
Timber.v("[PushRules] <-- No push tule check on initial sync")
|
||||
Timber.v("[PushRules] <-- No push rule check on initial sync")
|
||||
return
|
||||
} //nothing on initial sync
|
||||
|
||||
val rules = pushRuleService.getPushRules("global")
|
||||
val rules = pushRuleService.getPushRules(RuleScope.GLOBAL)
|
||||
processForPushTask.configureWith(ProcessEventForPushTask.Params(roomsSyncResponse, rules))
|
||||
.executeBy(taskExecutor)
|
||||
Timber.v("[PushRules] <-- Push task scheduled")
|
||||
|
@ -113,12 +114,12 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch
|
|||
private fun handleJoinedRoom(realm: Realm,
|
||||
roomId: String,
|
||||
roomSync: RoomSync,
|
||||
isInitalSync: Boolean): RoomEntity {
|
||||
isInitialSync: Boolean): RoomEntity {
|
||||
|
||||
Timber.v("Handle join sync for room $roomId")
|
||||
|
||||
if (roomSync.ephemeral != null && roomSync.ephemeral.events.isNotEmpty()) {
|
||||
handleEphemeral(realm, roomId, roomSync.ephemeral, isInitalSync)
|
||||
handleEphemeral(realm, roomId, roomSync.ephemeral, isInitialSync)
|
||||
}
|
||||
|
||||
if (roomSync.accountData != null && roomSync.accountData.events.isNullOrEmpty().not()) {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.sync
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
||||
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
|
||||
|
@ -33,73 +32,70 @@ internal class SyncResponseHandler @Inject constructor(private val roomSyncHandl
|
|||
private val cryptoService: DefaultCryptoService,
|
||||
private val initialSyncProgressService: DefaultInitialSyncProgressService) {
|
||||
|
||||
fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try<SyncResponse> {
|
||||
return Try {
|
||||
val isInitialSync = fromToken == null
|
||||
Timber.v("Start handling sync, is InitialSync: $isInitialSync")
|
||||
val reporter = initialSyncProgressService.takeIf { isInitialSync }
|
||||
suspend fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean) {
|
||||
val isInitialSync = fromToken == null
|
||||
Timber.v("Start handling sync, is InitialSync: $isInitialSync")
|
||||
val reporter = initialSyncProgressService.takeIf { isInitialSync }
|
||||
|
||||
measureTimeMillis {
|
||||
if (!cryptoService.isStarted()) {
|
||||
Timber.v("Should start cryptoService")
|
||||
cryptoService.start(isInitialSync)
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling start cryptoService in $it ms")
|
||||
}
|
||||
val measure = measureTimeMillis {
|
||||
// Handle the to device events before the room ones
|
||||
// to ensure to decrypt them properly
|
||||
measureTimeMillis {
|
||||
if (!cryptoService.isStarted()) {
|
||||
Timber.v("Should start cryptoService")
|
||||
cryptoService.start(isInitialSync)
|
||||
Timber.v("Handle toDevice")
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_crypto, 100, 0.1f) {
|
||||
if (syncResponse.toDevice != null) {
|
||||
cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling start cryptoService in $it ms")
|
||||
Timber.v("Finish handling toDevice in $it ms")
|
||||
}
|
||||
val measure = measureTimeMillis {
|
||||
// Handle the to device events before the room ones
|
||||
// to ensure to decrypt them properly
|
||||
measureTimeMillis {
|
||||
Timber.v("Handle toDevice")
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_crypto, 100, 0.1f) {
|
||||
if (syncResponse.toDevice != null) {
|
||||
cryptoSyncHandler.handleToDevice(syncResponse.toDevice, reporter)
|
||||
}
|
||||
|
||||
measureTimeMillis {
|
||||
Timber.v("Handle rooms")
|
||||
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_rooms, 100, 0.7f) {
|
||||
if (syncResponse.rooms != null) {
|
||||
roomSyncHandler.handle(syncResponse.rooms, isInitialSync, reporter)
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling toDevice in $it ms")
|
||||
}
|
||||
|
||||
measureTimeMillis {
|
||||
Timber.v("Handle rooms")
|
||||
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_rooms, 100, 0.7f) {
|
||||
if (syncResponse.rooms != null) {
|
||||
roomSyncHandler.handle(syncResponse.rooms, isInitialSync, reporter)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling rooms in $it ms")
|
||||
}
|
||||
|
||||
|
||||
measureTimeMillis {
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_groups, 100, 0.1f) {
|
||||
Timber.v("Handle groups")
|
||||
if (syncResponse.groups != null) {
|
||||
groupSyncHandler.handle(syncResponse.groups, reporter)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling groups in $it ms")
|
||||
}
|
||||
|
||||
measureTimeMillis {
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_data, 100, 0.1f) {
|
||||
Timber.v("Handle accountData")
|
||||
userAccountDataSyncHandler.handle(syncResponse.accountData, syncResponse.rooms?.invite)
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling accountData in $it ms")
|
||||
}
|
||||
|
||||
Timber.v("On sync completed")
|
||||
cryptoSyncHandler.onSyncCompleted(syncResponse)
|
||||
}.also {
|
||||
Timber.v("Finish handling rooms in $it ms")
|
||||
}
|
||||
Timber.v("Finish handling sync in $measure ms")
|
||||
syncResponse
|
||||
|
||||
|
||||
measureTimeMillis {
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_groups, 100, 0.1f) {
|
||||
Timber.v("Handle groups")
|
||||
if (syncResponse.groups != null) {
|
||||
groupSyncHandler.handle(syncResponse.groups, reporter)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling groups in $it ms")
|
||||
}
|
||||
|
||||
measureTimeMillis {
|
||||
reportSubtask(reporter, R.string.initial_sync_start_importing_account_data, 100, 0.1f) {
|
||||
Timber.v("Handle accountData")
|
||||
userAccountDataSyncHandler.handle(syncResponse.accountData, syncResponse.rooms?.invite)
|
||||
}
|
||||
}.also {
|
||||
Timber.v("Finish handling accountData in $it ms")
|
||||
}
|
||||
|
||||
Timber.v("On sync completed")
|
||||
cryptoSyncHandler.onSyncCompleted(syncResponse)
|
||||
}
|
||||
Timber.v("Finish handling sync in $measure ms")
|
||||
}
|
||||
|
||||
}
|
|
@ -18,10 +18,10 @@ package im.vector.matrix.android.internal.session.sync
|
|||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.failure.MatrixError
|
||||
import im.vector.matrix.android.internal.auth.SessionParamsStore
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
|
||||
import im.vector.matrix.android.internal.session.filter.FilterRepository
|
||||
|
@ -36,7 +36,7 @@ internal interface SyncTask : Task<SyncTask.Params, Unit> {
|
|||
}
|
||||
|
||||
internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val syncResponseHandler: SyncResponseHandler,
|
||||
private val sessionParamsStore: SessionParamsStore,
|
||||
|
@ -70,7 +70,7 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI,
|
|||
// Intercept 401
|
||||
if (throwable is Failure.ServerError
|
||||
&& throwable.error.code == MatrixError.UNKNOWN_TOKEN) {
|
||||
sessionParamsStore.delete(credentials.userId)
|
||||
sessionParamsStore.delete(userId)
|
||||
}
|
||||
throw throwable
|
||||
}
|
||||
|
|
|
@ -17,16 +17,18 @@
|
|||
package im.vector.matrix.android.internal.session.sync
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.getDirectRooms
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.session.pushers.SavePushRulesTask
|
||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataSync
|
||||
import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHelper
|
||||
import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask
|
||||
|
@ -37,15 +39,17 @@ import timber.log.Timber
|
|||
import javax.inject.Inject
|
||||
|
||||
internal class UserAccountDataSyncHandler @Inject constructor(private val monarchy: Monarchy,
|
||||
private val credentials: Credentials,
|
||||
@UserId private val userId: String,
|
||||
private val directChatsHelper: DirectChatsHelper,
|
||||
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
|
||||
private val savePushRulesTask: SavePushRulesTask,
|
||||
private val taskExecutor: TaskExecutor) {
|
||||
|
||||
fun handle(accountData: UserAccountDataSync?, invites: Map<String, InvitedRoomSync>?) {
|
||||
suspend fun handle(accountData: UserAccountDataSync?, invites: Map<String, InvitedRoomSync>?) {
|
||||
accountData?.list?.forEach {
|
||||
when (it) {
|
||||
is UserAccountDataDirectMessages -> handleDirectChatRooms(it)
|
||||
is UserAccountDataPushRules -> handlePushRules(it)
|
||||
else -> return@forEach
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +58,10 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun handlePushRules(userAccountDataPushRules: UserAccountDataPushRules) {
|
||||
savePushRulesTask.execute(SavePushRulesTask.Params(userAccountDataPushRules.content))
|
||||
}
|
||||
|
||||
private fun handleDirectChatRooms(directMessages: UserAccountDataDirectMessages) {
|
||||
monarchy.runTransactionSync { realm ->
|
||||
val oldDirectRooms = RoomSummaryEntity.getDirectRooms(realm)
|
||||
|
@ -81,11 +89,11 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
|
|||
val directChats = directChatsHelper.getLocalUserAccount()
|
||||
var hasUpdate = false
|
||||
invites.forEach { (roomId, _) ->
|
||||
val myUserStateEvent = RoomMembers(realm, roomId).getStateEvent(credentials.userId)
|
||||
val myUserStateEvent = RoomMembers(realm, roomId).getStateEvent(userId)
|
||||
val inviterId = myUserStateEvent?.sender
|
||||
val myUserRoomMember: RoomMember? = myUserStateEvent?.let { it.asDomain().content?.toModel() }
|
||||
val isDirect = myUserRoomMember?.isDirect
|
||||
if (inviterId != null && inviterId != credentials.userId && isDirect == true) {
|
||||
if (inviterId != null && inviterId != userId && isDirect == true) {
|
||||
directChats
|
||||
.getOrPut(inviterId, { arrayListOf() })
|
||||
.apply {
|
||||
|
|
|
@ -30,7 +30,6 @@ import im.vector.matrix.android.internal.task.TaskExecutor
|
|||
import im.vector.matrix.android.internal.task.TaskThread
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.BackgroundDetectionObserver
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import timber.log.Timber
|
||||
import java.net.SocketTimeoutException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
@ -140,7 +139,7 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
|
|||
if (failure is Failure.NetworkConnection && failure.cause is SocketTimeoutException) {
|
||||
// Timeout are not critical
|
||||
Timber.v("Timeout")
|
||||
} else if (failure is Failure.Unknown && failure.throwable is CancellationException) {
|
||||
} else if (failure is Failure.Cancelled) {
|
||||
Timber.v("Cancelled")
|
||||
} else if (failure is Failure.ServerError
|
||||
&& (failure.error.code == MatrixError.UNKNOWN_TOKEN || failure.error.code == MatrixError.MISSING_TOKEN)) {
|
||||
|
|
|
@ -23,5 +23,6 @@ internal interface UserAccountData {
|
|||
const val TYPE_DIRECT_MESSAGES = "m.direct"
|
||||
const val TYPE_PREVIEW_URLS = "org.matrix.preview_urls"
|
||||
const val TYPE_WIDGETS = "m.widgets"
|
||||
const val TYPE_PUSH_RULES = "m.push_rules"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.sync.model
|
||||
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class UserAccountDataPushRules(
|
||||
@Json(name = "content") val content: GetPushRulesResponse
|
||||
) : UserAccountData
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.user.accountdata
|
||||
|
||||
import im.vector.matrix.android.api.auth.data.Credentials
|
||||
import im.vector.matrix.android.internal.di.UserId
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.sync.model.UserAccountData
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
|
@ -42,11 +42,11 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
|
|||
}
|
||||
|
||||
internal class DefaultUpdateUserAccountDataTask @Inject constructor(private val accountDataApi: AccountDataAPI,
|
||||
private val credentials: Credentials) : UpdateUserAccountDataTask {
|
||||
@UserId private val userId: String) : UpdateUserAccountDataTask {
|
||||
|
||||
override suspend fun execute(params: UpdateUserAccountDataTask.Params) {
|
||||
return executeRequest {
|
||||
apiCall = accountDataApi.setAccountData(credentials.userId, params.type, params.getData())
|
||||
apiCall = accountDataApi.setAccountData(userId, params.type, params.getData())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,14 +24,13 @@ import im.vector.matrix.android.api.session.events.model.Event
|
|||
import im.vector.matrix.android.api.session.events.model.toContent
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomMember
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.*
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageTextContent
|
||||
import im.vector.matrix.android.api.session.room.send.UserDraft
|
||||
import im.vector.matrix.android.api.session.room.timeline.Timeline
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineSettings
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
@ -164,10 +163,29 @@ class PushrulesConditionTest {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun test_notice_condition() {
|
||||
val conditionEqual = EventMatchCondition("content.msgtype", "m.notice")
|
||||
|
||||
Event(
|
||||
type = "m.room.message",
|
||||
eventId = "mx0",
|
||||
content = MessageTextContent("m.notice", "A").toContent(),
|
||||
originServerTs = 0,
|
||||
roomId = "2joined").also {
|
||||
Assert.assertTrue("Notice", conditionEqual.isSatisfied(it))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MockRoomService() : RoomService {
|
||||
|
||||
override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>) {
|
||||
override fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun joinRoom(roomId: String, viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getRoom(roomId: String): Room? {
|
||||
|
@ -184,6 +202,53 @@ class PushrulesConditionTest {
|
|||
}
|
||||
|
||||
class MockRoom(override val roomId: String, val _numberOfJoinedMembers: Int) : Room {
|
||||
override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun deleteFailedEcho(localEcho: TimelineEvent) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun clearSendingQueue() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun resendAllFailedMessages() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun saveDraft(draft: UserDraft) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun deleteDraft() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getDraftsLive(): LiveData<List<UserDraft>> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getEventReadReceiptsLive(eventId: String): LiveData<List<ReadReceipt>> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun getStateEvent(eventType: String): Event? {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun editReply(replyToEdit: TimelineEvent, originalTimelineEvent: TimelineEvent, newBodyText: String, compatibilityBodyText: String): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun fetchEditHistory(eventId: String, callback: MatrixCallback<List<Event>>) {
|
||||
}
|
||||
|
||||
override fun liveTimeLineEvent(eventId: String): LiveData<TimelineEvent> {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
@ -201,7 +266,7 @@ class PushrulesConditionTest {
|
|||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun createTimeline(eventId: String?, allowedTypes: List<String>?): Timeline {
|
||||
override fun createTimeline(eventId: String?, settings: TimelineSettings): Timeline {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
|
@ -245,7 +310,7 @@ class PushrulesConditionTest {
|
|||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun loadRoomMembersIfNeeded(): Cancelable {
|
||||
override fun loadRoomMembersIfNeeded(matrixCallback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
|
@ -257,15 +322,15 @@ class PushrulesConditionTest {
|
|||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun invite(userId: String, callback: MatrixCallback<Unit>) {
|
||||
override fun invite(userId: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun join(callback: MatrixCallback<Unit>) {
|
||||
override fun join(viaServers: List<String>, callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun leave(callback: MatrixCallback<Unit>) {
|
||||
override fun leave(callback: MatrixCallback<Unit>): Cancelable {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ androidExtensions {
|
|||
}
|
||||
|
||||
ext.versionMajor = 0
|
||||
ext.versionMinor = 5
|
||||
ext.versionMinor = 6
|
||||
ext.versionPatch = 0
|
||||
|
||||
static def getGitTimestamp() {
|
||||
|
@ -252,8 +252,9 @@ dependencies {
|
|||
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
|
||||
implementation 'com.jakewharton.rxrelay2:rxrelay:2.1.0'
|
||||
// RXBinding
|
||||
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2'
|
||||
implementation 'com.jakewharton.rxbinding3:rxbinding-appcompat:3.0.0-alpha2'
|
||||
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0'
|
||||
implementation 'com.jakewharton.rxbinding3:rxbinding-appcompat:3.0.0'
|
||||
implementation 'com.jakewharton.rxbinding3:rxbinding-material:3.0.0'
|
||||
|
||||
implementation("com.airbnb.android:epoxy:$epoxy_version")
|
||||
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
|
||||
|
|
|
@ -21,11 +21,19 @@ import android.content.Intent
|
|||
import android.os.Build
|
||||
import im.vector.matrix.android.internal.session.sync.job.SyncService
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.extensions.vectorComponent
|
||||
import im.vector.riotx.features.notifications.NotificationUtils
|
||||
import timber.log.Timber
|
||||
|
||||
class VectorSyncService : SyncService() {
|
||||
|
||||
private lateinit var notificationUtils: NotificationUtils
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
notificationUtils = vectorComponent().notificationUtils()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
removeForegroundNotif()
|
||||
super.onDestroy()
|
||||
|
@ -43,7 +51,7 @@ class VectorSyncService : SyncService() {
|
|||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Timber.v("VectorSyncService - onStartCommand ")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val notification = NotificationUtils.buildForegroundServiceNotification(applicationContext, R.string.notification_listening_for_events, false)
|
||||
val notification = notificationUtils.buildForegroundServiceNotification(R.string.notification_listening_for_events, false)
|
||||
startForeground(NotificationUtils.NOTIFICATION_ID_FOREGROUND_SERVICE, notification)
|
||||
}
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
|
|
|
@ -196,13 +196,13 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||
// This ID can and should be used to detect duplicate notification requests.
|
||||
val eventId = data["event_id"] ?: return //Just ignore
|
||||
|
||||
|
||||
val eventType = data["type"]
|
||||
if (eventType == null) {
|
||||
//Just add a generic unknown event
|
||||
val simpleNotifiableEvent = SimpleNotifiableEvent(
|
||||
session.myUserId,
|
||||
eventId,
|
||||
null,
|
||||
true, //It's an issue in this case, all event will bing even if expected to be silent.
|
||||
title = getString(R.string.notification_unknown_new_event),
|
||||
description = "",
|
||||
|
@ -213,10 +213,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||
)
|
||||
notificationDrawerManager.onNotifiableEventReceived(simpleNotifiableEvent)
|
||||
notificationDrawerManager.refreshNotificationDrawer()
|
||||
|
||||
return
|
||||
} else {
|
||||
|
||||
val event = parseEvent(data) ?: return
|
||||
|
||||
val notifiableEvent = notifiableEventResolver.resolveEvent(event, session)
|
||||
|
@ -227,8 +224,6 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||
Timber.e("--> ${event}")
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
if (notifiableEvent is NotifiableMessageEvent) {
|
||||
if (TextUtils.isEmpty(notifiableEvent.senderName)) {
|
||||
notifiableEvent.senderName = data["sender_display_name"]
|
||||
|
@ -245,7 +240,6 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||
notificationDrawerManager.refreshNotificationDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun findRoomNameBestEffort(data: Map<String, String>, session: Session?): String? {
|
||||
|
|
|
@ -48,7 +48,6 @@ import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks
|
|||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
import im.vector.riotx.features.notifications.NotificationUtils
|
||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||
import im.vector.riotx.features.rageshake.VectorFileLogger
|
||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||
import im.vector.riotx.features.settings.VectorPreferences
|
||||
import im.vector.riotx.features.version.VersionProvider
|
||||
|
@ -73,6 +72,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||
@Inject lateinit var pushRuleTriggerListener: PushRuleTriggerListener
|
||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||
@Inject lateinit var versionProvider: VersionProvider
|
||||
@Inject lateinit var notificationUtils: NotificationUtils
|
||||
lateinit var vectorComponent: VectorComponent
|
||||
private var fontThreadHandler: Handler? = null
|
||||
|
||||
|
@ -112,7 +112,7 @@ class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.
|
|||
|
||||
emojiCompatWrapper.init(fontRequest)
|
||||
|
||||
NotificationUtils.createNotificationChannels(applicationContext)
|
||||
notificationUtils.createNotificationChannels()
|
||||
if (authenticator.hasAuthenticatedSessions() && !activeSessionHolder.hasActiveSession()) {
|
||||
val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!!
|
||||
activeSessionHolder.setActiveSession(lastAuthenticatedSession)
|
||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.riotx.EmojiCompatFontProvider
|
|||
import im.vector.riotx.EmojiCompatWrapper
|
||||
import im.vector.riotx.VectorApplication
|
||||
import im.vector.riotx.core.pushers.PushersManager
|
||||
import im.vector.riotx.core.utils.DimensionConverter
|
||||
import im.vector.riotx.features.configuration.VectorConfiguration
|
||||
import im.vector.riotx.features.crypto.keysrequest.KeyRequestHandler
|
||||
import im.vector.riotx.features.crypto.verification.IncomingVerificationRequestHandler
|
||||
|
@ -36,10 +37,7 @@ import im.vector.riotx.features.home.HomeRoomListObservableStore
|
|||
import im.vector.riotx.features.home.group.SelectedGroupStore
|
||||
import im.vector.riotx.features.html.EventHtmlRenderer
|
||||
import im.vector.riotx.features.navigation.Navigator
|
||||
import im.vector.riotx.features.notifications.NotifiableEventResolver
|
||||
import im.vector.riotx.features.notifications.NotificationBroadcastReceiver
|
||||
import im.vector.riotx.features.notifications.NotificationDrawerManager
|
||||
import im.vector.riotx.features.notifications.PushRuleTriggerListener
|
||||
import im.vector.riotx.features.notifications.*
|
||||
import im.vector.riotx.features.rageshake.BugReporter
|
||||
import im.vector.riotx.features.rageshake.VectorFileLogger
|
||||
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
|
||||
|
@ -58,12 +56,16 @@ interface VectorComponent {
|
|||
|
||||
fun currentSession(): Session
|
||||
|
||||
fun notificationUtils(): NotificationUtils
|
||||
|
||||
fun notificationDrawerManager(): NotificationDrawerManager
|
||||
|
||||
fun appContext(): Context
|
||||
|
||||
fun resources(): Resources
|
||||
|
||||
fun dimensionUtils(): DimensionConverter
|
||||
|
||||
fun vectorConfiguration(): VectorConfiguration
|
||||
|
||||
fun avatarRenderer(): AvatarRenderer
|
||||
|
@ -72,7 +74,7 @@ interface VectorComponent {
|
|||
|
||||
fun emojiCompatFontProvider(): EmojiCompatFontProvider
|
||||
|
||||
fun emojiCompatWrapper() : EmojiCompatWrapper
|
||||
fun emojiCompatWrapper(): EmojiCompatWrapper
|
||||
|
||||
fun eventHtmlRenderer(): EventHtmlRenderer
|
||||
|
||||
|
|
|
@ -20,9 +20,10 @@ import im.vector.matrix.android.api.failure.Failure
|
|||
import im.vector.matrix.android.api.failure.MatrixError
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import java.net.SocketTimeoutException
|
||||
import javax.inject.Inject
|
||||
|
||||
class ErrorFormatter @Inject constructor(val stringProvider: StringProvider) {
|
||||
class ErrorFormatter @Inject constructor(private val stringProvider: StringProvider) {
|
||||
|
||||
|
||||
fun toHumanReadable(failure: Failure): String {
|
||||
|
@ -33,7 +34,13 @@ class ErrorFormatter @Inject constructor(val stringProvider: StringProvider) {
|
|||
fun toHumanReadable(throwable: Throwable?): String {
|
||||
return when (throwable) {
|
||||
null -> null
|
||||
is Failure.NetworkConnection -> stringProvider.getString(R.string.error_no_network)
|
||||
is Failure.NetworkConnection -> {
|
||||
if (throwable.ioException is SocketTimeoutException) {
|
||||
stringProvider.getString(R.string.error_network_timeout)
|
||||
} else {
|
||||
stringProvider.getString(R.string.error_no_network)
|
||||
}
|
||||
}
|
||||
is Failure.ServerError -> {
|
||||
if (throwable.error.code == MatrixError.M_CONSENT_NOT_GIVEN) {
|
||||
// Special case for terms and conditions
|
||||
|
|
|
@ -32,7 +32,6 @@ fun Session.configureAndStart(pushRuleTriggerListener: PushRuleTriggerListener)
|
|||
startSync(isAtLeastStarted)
|
||||
refreshPushers()
|
||||
pushRuleTriggerListener.startWithSession(this)
|
||||
fetchPushRules()
|
||||
|
||||
// TODO P1 From HomeActivity
|
||||
// @Inject lateinit var incomingVerificationRequestHandler: IncomingVerificationRequestHandler
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.riotx.core.services
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.content.ContextCompat
|
||||
import im.vector.riotx.core.extensions.vectorComponent
|
||||
import im.vector.riotx.features.notifications.NotificationUtils
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -32,11 +33,18 @@ class CallService : VectorService() {
|
|||
*/
|
||||
private var mCallIdInProgress: String? = null
|
||||
|
||||
private lateinit var notificationUtils: NotificationUtils
|
||||
|
||||
/**
|
||||
* incoming (foreground notification)
|
||||
*/
|
||||
private var mIncomingCallId: String? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
notificationUtils = vectorComponent().notificationUtils()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (intent == null) {
|
||||
// Service started again by the system.
|
||||
|
@ -120,7 +128,7 @@ class CallService : VectorService() {
|
|||
private fun displayCallInProgressNotification(intent: Intent) {
|
||||
val callId = intent.getStringExtra(EXTRA_CALL_ID)
|
||||
|
||||
val notification = NotificationUtils.buildPendingCallNotification(applicationContext,
|
||||
val notification = notificationUtils.buildPendingCallNotification(
|
||||
intent.getBooleanExtra(EXTRA_IS_VIDEO, false),
|
||||
intent.getStringExtra(EXTRA_ROOM_NAME),
|
||||
intent.getStringExtra(EXTRA_ROOM_ID),
|
||||
|
@ -136,7 +144,7 @@ class CallService : VectorService() {
|
|||
* Hide the permanent call notifications
|
||||
*/
|
||||
private fun hideCallNotifications() {
|
||||
val notification = NotificationUtils.buildCallEndedNotification(applicationContext)
|
||||
val notification = notificationUtils.buildCallEndedNotification()
|
||||
|
||||
// It's mandatory to startForeground to avoid crash
|
||||
startForeground(NOTIFICATION_ID, notification)
|
||||
|
|
|
@ -15,25 +15,26 @@
|
|||
*/
|
||||
package im.vector.riotx.core.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.util.TypedValue
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
object DimensionUtils {
|
||||
class DimensionConverter @Inject constructor(val resources: Resources) {
|
||||
|
||||
fun dpToPx(dp: Int, context: Context): Int {
|
||||
fun dpToPx(dp: Int): Int {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.toFloat(),
|
||||
context.resources.displayMetrics
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
|
||||
fun spToPx(sp: Int, context: Context): Int {
|
||||
fun spToPx(sp: Int): Int {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_SP,
|
||||
sp.toFloat(),
|
||||
context.resources.displayMetrics
|
||||
resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
}
|
|
@ -18,11 +18,7 @@ package im.vector.riotx.core.utils
|
|||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.*
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
|
@ -32,7 +28,7 @@ import androidx.annotation.StringRes
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.Fragment
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.features.notifications.supportNotificationChannels
|
||||
import im.vector.riotx.features.notifications.NotificationUtils
|
||||
import im.vector.riotx.features.settings.VectorLocale
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
|
@ -138,7 +134,7 @@ fun startNotificationSettingsIntent(activity: AppCompatActivity, requestCode: In
|
|||
*/
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
fun startNotificationChannelSettingsIntent(fragment: Fragment, channelID: String) {
|
||||
if (!supportNotificationChannels()) return
|
||||
if (!NotificationUtils.supportNotificationChannels()) return
|
||||
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).apply {
|
||||
putExtra(Settings.EXTRA_APP_PACKAGE, fragment.context?.packageName)
|
||||
putExtra(Settings.EXTRA_CHANNEL_ID, channelID)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue