Cleanup the PR about presence

This commit is contained in:
Benoit Marty 2021-10-12 16:45:31 +02:00
parent 923bc00dcd
commit 6c915ea4d1
23 changed files with 101 additions and 76 deletions

View File

@ -17,25 +17,25 @@
package org.matrix.android.sdk.api.session.presence
import org.matrix.android.sdk.internal.session.presence.model.GetPresenceResponse
import org.matrix.android.sdk.internal.session.presence.model.PresenceEnum
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
import org.matrix.android.sdk.api.session.presence.model.UserPresence
/**
* This interface defines methods for handling user presence information.
*/
interface PresenceService {
/**
* Update the presence status for the current user
* @param presence the new presence state
* @param message the status message to attach to this state
* @param statusMsg the status message to attach to this state
*/
suspend fun setMyPresence(presence: PresenceEnum, message: String? = null)
suspend fun setMyPresence(presence: PresenceEnum, statusMsg: String? = null)
/**
* Fetch the given user's presence state.
* @param userId the userId whose presence state to get.
*/
suspend fun fetchPresence(userId: String): GetPresenceResponse
suspend fun fetchPresence(userId: String): UserPresence
// TODO Add live data (of Flow) of the presence of a userId
}

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -14,16 +14,11 @@
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.presence.model
package org.matrix.android.sdk.api.session.presence.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
/**
* Annotate enums with @JsonClass(generateAdapter = false) to prevent
* them from being removed/obfuscated from your code by R8/ProGuard.
*/
@JsonClass(generateAdapter = false)
enum class PresenceEnum(val value: String) {
@Json(name = "online")

View File

@ -5,7 +5,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.matrix.android.sdk.internal.session.presence.model
package org.matrix.android.sdk.api.session.presence.model
data class UserPresence(
val lastActiveAgo: Long? = null,

View File

@ -16,7 +16,7 @@
package org.matrix.android.sdk.api.session.room.model
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
import org.matrix.android.sdk.api.session.presence.model.UserPresence
/**
* Class representing a simplified version of EventType.STATE_ROOM_MEMBER state event content

View File

@ -17,11 +17,11 @@
package org.matrix.android.sdk.api.session.room.model
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.presence.model.UserPresence
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
import org.matrix.android.sdk.api.session.room.send.UserDraft
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
/**
* This class holds some data of a room.

View File

@ -355,6 +355,7 @@ internal object RealmSessionStoreMigration : RealmMigration {
?.addField(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, Boolean::class.java)
?.setNullable(UserPresenceEntityFields.IS_CURRENTLY_ACTIVE, true)
?.addField(UserPresenceEntityFields.AVATAR_URL, String::class.java)
?.addField(UserPresenceEntityFields.DISPLAY_NAME, String::class.java)
val userPresenceEntity = realm.schema.get("UserPresenceEntity") ?: return
realm.schema.get("RoomSummaryEntity")

View File

@ -46,7 +46,6 @@ internal open class RoomMemberSummaryEntity(@PrimaryKey var primaryKey: String =
if (value != field) field = value
}
fun getBestName() = displayName?.takeIf { it.isNotBlank() } ?: userId
fun toMatrixItem() = MatrixItem.UserItem(userId, displayName, avatarUrl)
companion object

View File

@ -18,14 +18,15 @@ package org.matrix.android.sdk.internal.database.model.presence
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import org.matrix.android.sdk.internal.session.presence.model.PresenceEnum
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
import org.matrix.android.sdk.api.session.presence.model.UserPresence
internal open class UserPresenceEntity(@PrimaryKey var userId: String = "",
var lastActiveAgo: Long? = null,
var statusMessage: String? = null,
var isCurrentlyActive: Boolean? = null,
var avatarUrl: String? = null
var avatarUrl: String? = null,
var displayName: String? = null
) : RealmObject() {
var presence: PresenceEnum
@ -46,4 +47,5 @@ internal fun UserPresenceEntity.toUserPresence() =
lastActiveAgo,
statusMessage,
isCurrentlyActive,
presence)
presence
)

View File

@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.session.presence.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
@JsonClass(generateAdapter = true)
data class GetPresenceResponse(

View File

@ -18,15 +18,35 @@ package org.matrix.android.sdk.internal.session.presence.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
/**
* Class representing the EventType.PRESENCE event content
*/
@JsonClass(generateAdapter = true)
data class PresenceContent(
/**
* Required. The presence state for this user. One of: ["online", "offline", "unavailable"]
*/
@Json(name = "presence") val presence: PresenceEnum,
/**
* The last time since this used performed some action, in milliseconds.
*/
@Json(name = "last_active_ago") val lastActiveAgo: Long? = null,
/**
* An optional description to accompany the presence.
*/
@Json(name = "status_msg") val statusMessage: String? = null,
/**
* Whether the user is currently active
*/
@Json(name = "currently_active") val isCurrentlyActive: Boolean = false,
@Json(name = "avatar_url") val avatarUrl: String? = null
/**
* The current avatar URL for this user, if any.
*/
@Json(name = "avatar_url") val avatarUrl: String? = null,
/**
* The current display name for this user, if any.
*/
@Json(name = "displayname") val displayName: String? = null
)

View File

@ -17,11 +17,12 @@ package org.matrix.android.sdk.internal.session.presence.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
@JsonClass(generateAdapter = true)
internal data class SetPresenceBody(
@Json(name = "presence")
val presence: PresenceEnum,
@Json(name = "status_msg")
val message: String?
val statusMsg: String?
)

View File

@ -18,19 +18,31 @@
package org.matrix.android.sdk.internal.session.presence.service
import org.matrix.android.sdk.api.session.presence.PresenceService
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
import org.matrix.android.sdk.api.session.presence.model.UserPresence
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.presence.model.PresenceEnum
import org.matrix.android.sdk.internal.session.presence.service.task.GetPresenceTask
import org.matrix.android.sdk.internal.session.presence.service.task.SetPresenceTask
import javax.inject.Inject
internal class DefaultPresenceService @Inject constructor(@UserId private val userId: String,
private val setPresenceTask: SetPresenceTask,
private val getPresenceTask: GetPresenceTask) : PresenceService {
internal class DefaultPresenceService @Inject constructor(
@UserId private val userId: String,
private val setPresenceTask: SetPresenceTask,
private val getPresenceTask: GetPresenceTask
) : PresenceService {
override suspend fun setMyPresence(presence: PresenceEnum, message: String?) {
setPresenceTask.execute(SetPresenceTask.Params(userId, presence, message))
override suspend fun setMyPresence(presence: PresenceEnum, statusMsg: String?) {
setPresenceTask.execute(SetPresenceTask.Params(userId, presence, statusMsg))
}
override suspend fun fetchPresence(userId: String) = getPresenceTask.execute(GetPresenceTask.Params(userId))
override suspend fun fetchPresence(userId: String): UserPresence {
val result = getPresenceTask.execute(GetPresenceTask.Params(userId))
return UserPresence(
lastActiveAgo = result.lastActiveAgo,
statusMessage = result.message,
isCurrentlyActive = result.isCurrentlyActive,
presence = result.presence
)
}
}

View File

@ -17,10 +17,10 @@
package org.matrix.android.sdk.internal.session.presence.service.task
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
import org.matrix.android.sdk.internal.network.executeRequest
import org.matrix.android.sdk.internal.session.presence.PresenceAPI
import org.matrix.android.sdk.internal.session.presence.model.PresenceEnum
import org.matrix.android.sdk.internal.session.presence.model.SetPresenceBody
import org.matrix.android.sdk.internal.task.Task
import javax.inject.Inject
@ -29,7 +29,7 @@ internal abstract class SetPresenceTask : Task<SetPresenceTask.Params, Any> {
data class Params(
val userId: String,
val presence: PresenceEnum,
val message: String?
val statusMsg: String?
)
}
@ -40,7 +40,7 @@ internal class DefaultSetPresenceTask @Inject constructor(
override suspend fun execute(params: Params): Any {
return executeRequest(globalErrorReceiver) {
val setPresenceBody = SetPresenceBody(params.presence, params.message)
val setPresenceBody = SetPresenceBody(params.presence, params.statusMsg)
presenceAPI.setPresence(params.userId, setPresenceBody)
}
}

View File

@ -1,11 +1,11 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,

View File

@ -30,23 +30,24 @@ import javax.inject.Inject
internal class PresenceSyncHandler @Inject constructor() {
fun handle(realm: Realm, presenceSyncResponse: PresenceSyncResponse?) {
presenceSyncResponse?.events?.filter { event ->
event.type == EventType.PRESENCE
}?.forEach { event ->
val content = event.getPresenceContent() ?: return@forEach
val userId = event.senderId ?: return@forEach
val userPresenceEntity = UserPresenceEntity(
userId = userId,
lastActiveAgo = content.lastActiveAgo,
statusMessage = content.statusMessage,
isCurrentlyActive = content.isCurrentlyActive,
avatarUrl = content.avatarUrl
).also {
it.presence = content.presence
}
presenceSyncResponse?.events
?.filter { event -> event.type == EventType.PRESENCE }
?.forEach { event ->
val content = event.getPresenceContent() ?: return@forEach
val userId = event.senderId ?: return@forEach
val userPresenceEntity = UserPresenceEntity(
userId = userId,
lastActiveAgo = content.lastActiveAgo,
statusMessage = content.statusMessage,
isCurrentlyActive = content.isCurrentlyActive,
avatarUrl = content.avatarUrl,
displayName = content.displayName
).also {
it.presence = content.presence
}
storePresenceToDB(realm, userPresenceEntity)
}
storePresenceToDB(realm, userPresenceEntity)
}
}
/**

View File

@ -1,11 +1,11 @@
/*
* Copyright 2020 The Matrix.org Foundation C.I.C.
* Copyright (c) 2021 The Matrix.org Foundation C.I.C.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* 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,

View File

@ -17,28 +17,18 @@
package im.vector.app.core.epoxy.profiles
import android.widget.TextView
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.extensions.setTextOrHide
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
import org.matrix.android.sdk.api.session.presence.model.UserPresence
@EpoxyModelClass(layout = R.layout.item_profile_matrix_item)
abstract class ProfileMatrixItemWithPresence : BaseProfileMatrixItem<ProfileMatrixItemWithPresence.Holder>() {
abstract class ProfileMatrixItemWithPowerLevelWithPresence : ProfileMatrixItemWithPowerLevel() {
@EpoxyAttribute var powerLevelLabel: CharSequence? = null
@EpoxyAttribute var userPresence: UserPresence? = null
override fun bind(holder: Holder) {
super.bind(holder)
holder.powerLabel.setTextOrHide(powerLevelLabel)
holder.presenceImageView.render(userPresence = userPresence)
holder.editableView.isVisible = false
}
class Holder : ProfileMatrixItem.Holder() {
val powerLabel by bind<TextView>(R.id.matrixItemPowerLevelLabel)
}
}

View File

@ -21,8 +21,8 @@ import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.view.isVisible
import im.vector.app.R
import org.matrix.android.sdk.internal.session.presence.model.PresenceEnum
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
import org.matrix.android.sdk.api.session.presence.model.PresenceEnum
import org.matrix.android.sdk.api.session.presence.model.UserPresence
/**
* Custom ImageView to dynamically render Presence state in multiple screens

View File

@ -38,8 +38,8 @@ import im.vector.app.features.displayname.getBestName
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.themes.ThemeUtils
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.presence.model.UserPresence
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
@EpoxyModelClass(layout = R.layout.item_room)
abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {

View File

@ -21,7 +21,7 @@ import im.vector.app.R
import im.vector.app.core.epoxy.dividerItem
import im.vector.app.core.epoxy.profiles.buildProfileSection
import im.vector.app.core.epoxy.profiles.profileMatrixItem
import im.vector.app.core.epoxy.profiles.profileMatrixItemWithPresence
import im.vector.app.core.epoxy.profiles.profileMatrixItemWithPowerLevelWithPresence
import im.vector.app.core.extensions.join
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider
@ -29,11 +29,11 @@ import im.vector.app.features.home.AvatarRenderer
import me.gujun.android.span.span
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.presence.model.UserPresence
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary
import org.matrix.android.sdk.api.session.room.model.RoomThirdPartyInviteContent
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.internal.session.presence.model.UserPresence
import javax.inject.Inject
class RoomMemberListController @Inject constructor(
@ -130,7 +130,7 @@ class RoomMemberListController @Inject constructor(
) {
val powerLabel = stringProvider.getString(powerLevelCategory.titleRes)
profileMatrixItemWithPresence {
profileMatrixItemWithPowerLevelWithPresence {
id(roomMember.userId)
matrixItem(roomMember.toMatrixItem())
avatarRenderer(host.avatarRenderer)

View File

@ -64,6 +64,7 @@
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="20dp"
tools:ignore="MissingConstraints"
tools:layout_constraintCircleRadius="8dp"
tools:src="@drawable/ic_presence_offline"
tools:visibility="visible" />
@ -97,8 +98,8 @@
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/roomToolbarDecorationImageView"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginStart="7dp"
app:layout_constraintVertical_chainStyle="packed"
app:layout_goneMarginStart="7dp"
tools:text="@sample/rooms.json/data/name" />
<TextView

View File

@ -84,7 +84,7 @@
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="28dp"
tools:ignore="MissingConstraints"
tools:visibility="gone" />
tools:visibility="visible" />
<im.vector.app.core.ui.views.PresenceStateImageView
android:id="@+id/roomAvatarPresenceImageView"
@ -98,6 +98,7 @@
app:layout_constraintCircleAngle="135"
app:layout_constraintCircleRadius="28dp"
tools:ignore="MissingConstraints"
tools:layout_constraintCircleRadius="8dp"
tools:src="@drawable/ic_presence_offline"
tools:visibility="visible" />

View File

@ -56,7 +56,7 @@
app:layout_constraintEnd_toStartOf="@+id/memberProfileNameView"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/memberProfileNameView"/>
app:layout_constraintTop_toTopOf="@+id/memberProfileNameView" />
<TextView
android:id="@+id/memberProfileNameView"