Merge pull request #2001 from element-hq/feature/bma/fixNotificationAvatar
Fix notification avatar
This commit is contained in:
@@ -33,13 +33,12 @@ import dagger.assisted.AssistedInject
|
|||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.appnav.di.SessionComponentFactory
|
import io.element.android.appnav.di.SessionComponentFactory
|
||||||
import io.element.android.libraries.architecture.NodeInputs
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.bindings
|
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
import io.element.android.libraries.architecture.inputs
|
import io.element.android.libraries.architecture.inputs
|
||||||
import io.element.android.libraries.di.AppScope
|
import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.di.DaggerComponentOwner
|
import io.element.android.libraries.di.DaggerComponentOwner
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.ui.di.MatrixUIBindings
|
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -52,6 +51,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
|
|||||||
@Assisted buildContext: BuildContext,
|
@Assisted buildContext: BuildContext,
|
||||||
@Assisted plugins: List<Plugin>,
|
@Assisted plugins: List<Plugin>,
|
||||||
sessionComponentFactory: SessionComponentFactory,
|
sessionComponentFactory: SessionComponentFactory,
|
||||||
|
private val imageLoaderHolder: ImageLoaderHolder,
|
||||||
) : ParentNode<LoggedInAppScopeFlowNode.NavTarget>(
|
) : ParentNode<LoggedInAppScopeFlowNode.NavTarget>(
|
||||||
navModel = PermanentNavModel(
|
navModel = PermanentNavModel(
|
||||||
navTargets = setOf(NavTarget),
|
navTargets = setOf(NavTarget),
|
||||||
@@ -78,8 +78,7 @@ class LoggedInAppScopeFlowNode @AssistedInject constructor(
|
|||||||
super.onBuilt()
|
super.onBuilt()
|
||||||
lifecycle.subscribe(
|
lifecycle.subscribe(
|
||||||
onCreate = {
|
onCreate = {
|
||||||
val imageLoaderFactory = bindings<MatrixUIBindings>().loggedInImageLoaderFactory()
|
Coil.setImageLoader(imageLoaderHolder.get(inputs.matrixClient))
|
||||||
Coil.setImageLoader(imageLoaderFactory)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
1
changelog.d/1991.bugfix
Normal file
1
changelog.d/1991.bugfix
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Fix avatar not displayed in notification when the app is not in background
|
||||||
@@ -33,7 +33,7 @@ data class InviteListInviteSummary(
|
|||||||
val isNew: Boolean = false,
|
val isNew: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
data class InviteSender constructor(
|
data class InviteSender(
|
||||||
val userId: UserId,
|
val userId: UserId,
|
||||||
val displayName: String,
|
val displayName: String,
|
||||||
val avatarData: AvatarData = AvatarData(userId.value, displayName, size = AvatarSize.InviteSender),
|
val avatarData: AvatarData = AvatarData(userId.value, displayName, size = AvatarSize.InviteSender),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package io.element.android.features.login.impl.resolver
|
package io.element.android.features.login.impl.resolver
|
||||||
|
|
||||||
data class HomeserverData constructor(
|
data class HomeserverData(
|
||||||
// The computed homeserver url, for which a wellknown file has been retrieved, or just a valid Url
|
// The computed homeserver url, for which a wellknown file has been retrieved, or just a valid Url
|
||||||
val homeserverUrl: String,
|
val homeserverUrl: String,
|
||||||
// True if a wellknown file has been found and is valid. If false, it means that the [homeserverUrl] is valid
|
// True if a wellknown file has been found and is valid. If false, it means that the [homeserverUrl] is valid
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ import org.matrix.rustcomponents.sdk.RoomVisibility as RustRoomVisibility
|
|||||||
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
|
import org.matrix.rustcomponents.sdk.SyncService as ClientSyncService
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class RustMatrixClient constructor(
|
class RustMatrixClient(
|
||||||
private val client: Client,
|
private val client: Client,
|
||||||
private val syncService: ClientSyncService,
|
private val syncService: ClientSyncService,
|
||||||
private val sessionStore: SessionStore,
|
private val sessionStore: SessionStore,
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ import okhttp3.OkHttpClient
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Provider
|
import javax.inject.Provider
|
||||||
|
|
||||||
class LoggedInImageLoaderFactory @Inject constructor(
|
class LoggedInImageLoaderFactory(
|
||||||
@ApplicationContext private val context: Context,
|
private val context: Context,
|
||||||
private val matrixClient: MatrixClient,
|
private val matrixClient: MatrixClient,
|
||||||
private val okHttpClient: Provider<OkHttpClient>,
|
private val okHttpClient: Provider<OkHttpClient>,
|
||||||
) : ImageLoaderFactory {
|
) : ImageLoaderFactory {
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 io.element.android.libraries.matrix.ui.media
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import coil.ImageLoader
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import io.element.android.libraries.di.ApplicationContext
|
||||||
|
import io.element.android.libraries.di.SingleIn
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
|
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
|
||||||
|
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Provider
|
||||||
|
|
||||||
|
interface ImageLoaderHolder {
|
||||||
|
fun get(client: MatrixClient): ImageLoader
|
||||||
|
}
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
@SingleIn(AppScope::class)
|
||||||
|
class DefaultImageLoaderHolder @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val okHttpClient: Provider<OkHttpClient>,
|
||||||
|
private val sessionObserver: SessionObserver,
|
||||||
|
) : ImageLoaderHolder {
|
||||||
|
private val map = mutableMapOf<SessionId, ImageLoader>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
observeSessions()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeSessions() {
|
||||||
|
sessionObserver.addListener(object : SessionListener {
|
||||||
|
override suspend fun onSessionCreated(userId: String) = Unit
|
||||||
|
|
||||||
|
override suspend fun onSessionDeleted(userId: String) {
|
||||||
|
map.remove(SessionId(userId))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(client: MatrixClient): ImageLoader {
|
||||||
|
return synchronized(map) {
|
||||||
|
map.getOrPut(client.sessionId) {
|
||||||
|
LoggedInImageLoaderFactory(
|
||||||
|
context = context,
|
||||||
|
matrixClient = client,
|
||||||
|
okHttpClient = okHttpClient,
|
||||||
|
).newImageLoader()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,7 +37,7 @@ import java.util.UUID
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ContributesBinding(AppScope::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class PickerProviderImpl constructor(private val isInTest: Boolean) : PickerProvider {
|
class PickerProviderImpl(private val isInTest: Boolean) : PickerProvider {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
constructor(): this(false)
|
constructor(): this(false)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
|||||||
import com.google.accompanist.permissions.PermissionState
|
import com.google.accompanist.permissions.PermissionState
|
||||||
import com.google.accompanist.permissions.PermissionStatus
|
import com.google.accompanist.permissions.PermissionStatus
|
||||||
|
|
||||||
class FakeComposablePermissionStateProvider constructor(
|
class FakeComposablePermissionStateProvider(
|
||||||
private val permissionState: FakePermissionState
|
private val permissionState: FakePermissionState
|
||||||
) : ComposablePermissionStateProvider {
|
) : ComposablePermissionStateProvider {
|
||||||
private lateinit var onPermissionResult: (Boolean) -> Unit
|
private lateinit var onPermissionResult: (Boolean) -> Unit
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
|||||||
import io.element.android.libraries.matrix.api.core.SessionId
|
import io.element.android.libraries.matrix.api.core.SessionId
|
||||||
import io.element.android.libraries.matrix.api.core.ThreadId
|
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
|
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||||
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
|
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||||
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
import io.element.android.services.appnavstate.api.AppNavigationStateService
|
||||||
@@ -61,6 +62,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
|
|||||||
private val dispatchers: CoroutineDispatchers,
|
private val dispatchers: CoroutineDispatchers,
|
||||||
private val buildMeta: BuildMeta,
|
private val buildMeta: BuildMeta,
|
||||||
private val matrixClientProvider: MatrixClientProvider,
|
private val matrixClientProvider: MatrixClientProvider,
|
||||||
|
private val imageLoaderHolder: ImageLoaderHolder,
|
||||||
) : NotificationDrawerManager {
|
) : NotificationDrawerManager {
|
||||||
private var appNavigationStateObserver: Job? = null
|
private var appNavigationStateObserver: Job? = null
|
||||||
|
|
||||||
@@ -288,10 +290,11 @@ class DefaultNotificationDrawerManager @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventsForSessions.forEach { (sessionId, notifiableEvents) ->
|
eventsForSessions.forEach { (sessionId, notifiableEvents) ->
|
||||||
|
val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow()
|
||||||
|
val imageLoader = imageLoaderHolder.get(client)
|
||||||
val currentUser = tryOrNull(
|
val currentUser = tryOrNull(
|
||||||
onError = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
|
onError = { Timber.tag(loggerTag.value).e(it, "Unable to retrieve info for user ${sessionId.value}") },
|
||||||
operation = {
|
operation = {
|
||||||
val client = matrixClientProvider.getOrRestore(sessionId).getOrThrow()
|
|
||||||
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
|
// myUserDisplayName cannot be empty else NotificationCompat.MessagingStyle() will crash
|
||||||
val myUserDisplayName = client.loadUserDisplayName().getOrNull() ?: sessionId.value
|
val myUserDisplayName = client.loadUserDisplayName().getOrNull() ?: sessionId.value
|
||||||
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
||||||
@@ -307,7 +310,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
|
|||||||
avatarUrl = null
|
avatarUrl = null
|
||||||
)
|
)
|
||||||
|
|
||||||
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents)
|
notificationRenderer.render(currentUser, useCompleteNotificationFormat, notifiableEvents, imageLoader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import android.graphics.Bitmap
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import coil.imageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.transform.CircleCropTransformation
|
import coil.transform.CircleCropTransformation
|
||||||
import io.element.android.libraries.di.ApplicationContext
|
import io.element.android.libraries.di.ApplicationContext
|
||||||
@@ -39,21 +39,22 @@ class NotificationBitmapLoader @Inject constructor(
|
|||||||
/**
|
/**
|
||||||
* Get icon of a room.
|
* Get icon of a room.
|
||||||
* @param path mxc url
|
* @param path mxc url
|
||||||
|
* @param imageLoader Coil image loader
|
||||||
*/
|
*/
|
||||||
suspend fun getRoomBitmap(path: String?): Bitmap? {
|
suspend fun getRoomBitmap(path: String?, imageLoader: ImageLoader): Bitmap? {
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return loadRoomBitmap(path)
|
return loadRoomBitmap(path, imageLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadRoomBitmap(path: String): Bitmap? {
|
private suspend fun loadRoomBitmap(path: String, imageLoader: ImageLoader): Bitmap? {
|
||||||
return try {
|
return try {
|
||||||
val imageRequest = ImageRequest.Builder(context)
|
val imageRequest = ImageRequest.Builder(context)
|
||||||
.data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(1024)))
|
.data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(1024)))
|
||||||
.transformations(CircleCropTransformation())
|
.transformations(CircleCropTransformation())
|
||||||
.build()
|
.build()
|
||||||
val result = context.imageLoader.execute(imageRequest)
|
val result = imageLoader.execute(imageRequest)
|
||||||
result.drawable?.toBitmap()
|
result.drawable?.toBitmap()
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
Timber.e(e, "Unable to load room bitmap")
|
Timber.e(e, "Unable to load room bitmap")
|
||||||
@@ -65,22 +66,23 @@ class NotificationBitmapLoader @Inject constructor(
|
|||||||
* Get icon of a user.
|
* Get icon of a user.
|
||||||
* Before Android P, this does nothing because the icon won't be used
|
* Before Android P, this does nothing because the icon won't be used
|
||||||
* @param path mxc url
|
* @param path mxc url
|
||||||
|
* @param imageLoader Coil image loader
|
||||||
*/
|
*/
|
||||||
suspend fun getUserIcon(path: String?): IconCompat? {
|
suspend fun getUserIcon(path: String?, imageLoader: ImageLoader): IconCompat? {
|
||||||
if (path == null || sdkIntProvider.get() < Build.VERSION_CODES.P) {
|
if (path == null || sdkIntProvider.get() < Build.VERSION_CODES.P) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadUserIcon(path)
|
return loadUserIcon(path, imageLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadUserIcon(path: String): IconCompat? {
|
private suspend fun loadUserIcon(path: String, imageLoader: ImageLoader): IconCompat? {
|
||||||
return try {
|
return try {
|
||||||
val imageRequest = ImageRequest.Builder(context)
|
val imageRequest = ImageRequest.Builder(context)
|
||||||
.data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(1024)))
|
.data(MediaRequestData(MediaSource(path), MediaRequestData.Kind.Thumbnail(1024)))
|
||||||
.transformations(CircleCropTransformation())
|
.transformations(CircleCropTransformation())
|
||||||
.build()
|
.build()
|
||||||
val result = context.imageLoader.execute(imageRequest)
|
val result = imageLoader.execute(imageRequest)
|
||||||
val bitmap = result.drawable?.toBitmap()
|
val bitmap = result.drawable?.toBitmap()
|
||||||
return bitmap?.let { IconCompat.createWithBitmap(it) }
|
return bitmap?.let { IconCompat.createWithBitmap(it) }
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
|
import coil.ImageLoader
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
|
||||||
@@ -36,6 +37,7 @@ class NotificationFactory @Inject constructor(
|
|||||||
|
|
||||||
suspend fun Map<RoomId, ProcessedMessageEvents>.toNotifications(
|
suspend fun Map<RoomId, ProcessedMessageEvents>.toNotifications(
|
||||||
currentUser: MatrixUser,
|
currentUser: MatrixUser,
|
||||||
|
imageLoader: ImageLoader,
|
||||||
): List<RoomNotification> {
|
): List<RoomNotification> {
|
||||||
return map { (roomId, events) ->
|
return map { (roomId, events) ->
|
||||||
when {
|
when {
|
||||||
@@ -46,6 +48,7 @@ class NotificationFactory @Inject constructor(
|
|||||||
currentUser = currentUser,
|
currentUser = currentUser,
|
||||||
events = messageEvents,
|
events = messageEvents,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
imageLoader = imageLoader,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
|
import coil.ImageLoader
|
||||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
@@ -38,11 +39,12 @@ class NotificationRenderer @Inject constructor(
|
|||||||
suspend fun render(
|
suspend fun render(
|
||||||
currentUser: MatrixUser,
|
currentUser: MatrixUser,
|
||||||
useCompleteNotificationFormat: Boolean,
|
useCompleteNotificationFormat: Boolean,
|
||||||
eventsToProcess: List<ProcessedEvent<NotifiableEvent>>
|
eventsToProcess: List<ProcessedEvent<NotifiableEvent>>,
|
||||||
|
imageLoader: ImageLoader,
|
||||||
) {
|
) {
|
||||||
val groupedEvents = eventsToProcess.groupByType()
|
val groupedEvents = eventsToProcess.groupByType()
|
||||||
with(notificationFactory) {
|
with(notificationFactory) {
|
||||||
val roomNotifications = groupedEvents.roomEvents.toNotifications(currentUser)
|
val roomNotifications = groupedEvents.roomEvents.toNotifications(currentUser, imageLoader)
|
||||||
val invitationNotifications = groupedEvents.invitationEvents.toNotifications()
|
val invitationNotifications = groupedEvents.invitationEvents.toNotifications()
|
||||||
val simpleNotifications = groupedEvents.simpleEvents.toNotifications()
|
val simpleNotifications = groupedEvents.simpleEvents.toNotifications()
|
||||||
val fallbackNotifications = groupedEvents.fallbackEvents.toNotifications()
|
val fallbackNotifications = groupedEvents.fallbackEvents.toNotifications()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import androidx.core.app.NotificationCompat
|
|||||||
import androidx.core.app.Person
|
import androidx.core.app.Person
|
||||||
import androidx.core.text.buildSpannedString
|
import androidx.core.text.buildSpannedString
|
||||||
import androidx.core.text.inSpans
|
import androidx.core.text.inSpans
|
||||||
|
import coil.ImageLoader
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.push.impl.R
|
import io.element.android.libraries.push.impl.R
|
||||||
@@ -42,6 +43,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||||||
currentUser: MatrixUser,
|
currentUser: MatrixUser,
|
||||||
events: List<NotifiableMessageEvent>,
|
events: List<NotifiableMessageEvent>,
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
|
imageLoader: ImageLoader,
|
||||||
): RoomNotification.Message {
|
): RoomNotification.Message {
|
||||||
val lastKnownRoomEvent = events.last()
|
val lastKnownRoomEvent = events.last()
|
||||||
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderName ?: "Room name (${roomId.value.take(8)}…)"
|
val roomName = lastKnownRoomEvent.roomName ?: lastKnownRoomEvent.senderName ?: "Room name (${roomId.value.take(8)}…)"
|
||||||
@@ -49,13 +51,13 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||||||
val style = NotificationCompat.MessagingStyle(
|
val style = NotificationCompat.MessagingStyle(
|
||||||
Person.Builder()
|
Person.Builder()
|
||||||
.setName(currentUser.displayName?.annotateForDebug(50))
|
.setName(currentUser.displayName?.annotateForDebug(50))
|
||||||
.setIcon(bitmapLoader.getUserIcon(currentUser.avatarUrl))
|
.setIcon(bitmapLoader.getUserIcon(currentUser.avatarUrl, imageLoader))
|
||||||
.setKey(lastKnownRoomEvent.sessionId.value)
|
.setKey(lastKnownRoomEvent.sessionId.value)
|
||||||
.build()
|
.build()
|
||||||
).also {
|
).also {
|
||||||
it.conversationTitle = roomName.takeIf { roomIsGroup }?.annotateForDebug(51)
|
it.conversationTitle = roomName.takeIf { roomIsGroup }?.annotateForDebug(51)
|
||||||
it.isGroupConversation = roomIsGroup
|
it.isGroupConversation = roomIsGroup
|
||||||
it.addMessagesFromEvents(events)
|
it.addMessagesFromEvents(events, imageLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
val tickerText = if (roomIsGroup) {
|
val tickerText = if (roomIsGroup) {
|
||||||
@@ -64,7 +66,7 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||||||
stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderName, events.last().description)
|
stringProvider.getString(R.string.notification_ticker_text_dm, events.last().senderName, events.last().description)
|
||||||
}
|
}
|
||||||
|
|
||||||
val largeBitmap = getRoomBitmap(events)
|
val largeBitmap = getRoomBitmap(events, imageLoader)
|
||||||
|
|
||||||
val lastMessageTimestamp = events.last().timestamp
|
val lastMessageTimestamp = events.last().timestamp
|
||||||
val smartReplyErrors = events.filter { it.isSmartReplyError() }
|
val smartReplyErrors = events.filter { it.isSmartReplyError() }
|
||||||
@@ -98,14 +100,17 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun NotificationCompat.MessagingStyle.addMessagesFromEvents(events: List<NotifiableMessageEvent>) {
|
private suspend fun NotificationCompat.MessagingStyle.addMessagesFromEvents(
|
||||||
|
events: List<NotifiableMessageEvent>,
|
||||||
|
imageLoader: ImageLoader,
|
||||||
|
) {
|
||||||
events.forEach { event ->
|
events.forEach { event ->
|
||||||
val senderPerson = if (event.outGoingMessage) {
|
val senderPerson = if (event.outGoingMessage) {
|
||||||
null
|
null
|
||||||
} else {
|
} else {
|
||||||
Person.Builder()
|
Person.Builder()
|
||||||
.setName(event.senderName?.annotateForDebug(70))
|
.setName(event.senderName?.annotateForDebug(70))
|
||||||
.setIcon(bitmapLoader.getUserIcon(event.senderAvatarPath))
|
.setIcon(bitmapLoader.getUserIcon(event.senderAvatarPath, imageLoader))
|
||||||
.setKey(event.senderId.value)
|
.setKey(event.senderId.value)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@@ -167,10 +172,13 @@ class RoomGroupMessageCreator @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getRoomBitmap(events: List<NotifiableMessageEvent>): Bitmap? {
|
private suspend fun getRoomBitmap(
|
||||||
|
events: List<NotifiableMessageEvent>,
|
||||||
|
imageLoader: ImageLoader,
|
||||||
|
): Bitmap? {
|
||||||
// Use the last event (most recent?)
|
// Use the last event (most recent?)
|
||||||
return events.reversed().firstNotNullOfOrNull { it.roomAvatarPath }
|
return events.reversed().firstNotNullOfOrNull { it.roomAvatarPath }
|
||||||
?.let { bitmapLoader.getRoomBitmap(it) }
|
?.let { bitmapLoader.getRoomBitmap(it, imageLoader) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.test.A_THREAD_ID
|
|||||||
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
|
||||||
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
import io.element.android.libraries.matrix.test.core.aBuildMeta
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeAndroidNotificationFactory
|
import io.element.android.libraries.push.impl.notifications.fake.FakeAndroidNotificationFactory
|
||||||
|
import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoaderHolder
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
@@ -129,6 +130,7 @@ class DefaultNotificationDrawerManagerTest {
|
|||||||
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
|
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
|
||||||
buildMeta = aBuildMeta(),
|
buildMeta = aBuildMeta(),
|
||||||
matrixClientProvider = FakeMatrixClientProvider(),
|
matrixClientProvider = FakeMatrixClientProvider(),
|
||||||
|
imageLoaderHolder = FakeImageLoaderHolder(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
|||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeAndroidNotificationFactory
|
import io.element.android.libraries.push.impl.notifications.fake.FakeAndroidNotificationFactory
|
||||||
|
import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoader
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
@@ -30,12 +31,15 @@ import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNoti
|
|||||||
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
|
||||||
private val MY_AVATAR_URL: String? = null
|
private val MY_AVATAR_URL: String? = null
|
||||||
private val AN_INVITATION_EVENT = anInviteNotifiableEvent(roomId = A_ROOM_ID)
|
private val AN_INVITATION_EVENT = anInviteNotifiableEvent(roomId = A_ROOM_ID)
|
||||||
private val A_SIMPLE_EVENT = aSimpleNotifiableEvent(eventId = AN_EVENT_ID)
|
private val A_SIMPLE_EVENT = aSimpleNotifiableEvent(eventId = AN_EVENT_ID)
|
||||||
private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)
|
private val A_MESSAGE_EVENT = aNotifiableMessageEvent(eventId = AN_EVENT_ID, roomId = A_ROOM_ID)
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
class NotificationFactoryTest {
|
class NotificationFactoryTest {
|
||||||
|
|
||||||
private val androidNotificationFactory = FakeAndroidNotificationFactory()
|
private val androidNotificationFactory = FakeAndroidNotificationFactory()
|
||||||
@@ -130,11 +134,14 @@ class NotificationFactoryTest {
|
|||||||
)
|
)
|
||||||
val roomWithMessage = mapOf(A_ROOM_ID to listOf(ProcessedEvent(ProcessedEvent.Type.KEEP, A_MESSAGE_EVENT)))
|
val roomWithMessage = mapOf(A_ROOM_ID to listOf(ProcessedEvent(ProcessedEvent.Type.KEEP, A_MESSAGE_EVENT)))
|
||||||
|
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = roomWithMessage.toNotifications(
|
val result = roomWithMessage.toNotifications(
|
||||||
MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL)
|
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result).isEqualTo(listOf(expectedNotification))
|
assertThat(result).isEqualTo(listOf(expectedNotification))
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -142,8 +149,10 @@ class NotificationFactoryTest {
|
|||||||
val events = listOf(ProcessedEvent(ProcessedEvent.Type.REMOVE, A_MESSAGE_EVENT))
|
val events = listOf(ProcessedEvent(ProcessedEvent.Type.REMOVE, A_MESSAGE_EVENT))
|
||||||
val emptyRoom = mapOf(A_ROOM_ID to events)
|
val emptyRoom = mapOf(A_ROOM_ID to events)
|
||||||
|
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = emptyRoom.toNotifications(
|
val result = emptyRoom.toNotifications(
|
||||||
MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL)
|
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).isEqualTo(
|
||||||
@@ -153,14 +162,17 @@ class NotificationFactoryTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationFactory) {
|
fun `given a room with only redacted events when mapping to notification then is Empty`() = testWith(notificationFactory) {
|
||||||
val redactedRoom = mapOf(A_ROOM_ID to listOf(ProcessedEvent(ProcessedEvent.Type.KEEP, A_MESSAGE_EVENT.copy(isRedacted = true))))
|
val redactedRoom = mapOf(A_ROOM_ID to listOf(ProcessedEvent(ProcessedEvent.Type.KEEP, A_MESSAGE_EVENT.copy(isRedacted = true))))
|
||||||
|
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = redactedRoom.toNotifications(
|
val result = redactedRoom.toNotifications(
|
||||||
MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL)
|
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result).isEqualTo(
|
assertThat(result).isEqualTo(
|
||||||
@@ -170,6 +182,7 @@ class NotificationFactoryTest {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -189,11 +202,14 @@ class NotificationFactoryTest {
|
|||||||
A_ROOM_ID,
|
A_ROOM_ID,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = roomWithRedactedMessage.toNotifications(
|
val result = roomWithRedactedMessage.toNotifications(
|
||||||
MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL)
|
currentUser = MatrixUser(A_SESSION_ID, A_SESSION_ID.value, MY_AVATAR_URL),
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(result).isEqualTo(listOf(expectedNotification))
|
assertThat(result).isEqualTo(listOf(expectedNotification))
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,15 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
|||||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||||
|
import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoader
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
|
||||||
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationFactory
|
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationFactory
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
|
||||||
private const val MY_USER_DISPLAY_NAME = "display-name"
|
private const val MY_USER_DISPLAY_NAME = "display-name"
|
||||||
private const val MY_USER_AVATAR_URL = "avatar-url"
|
private const val MY_USER_AVATAR_URL = "avatar-url"
|
||||||
@@ -42,6 +45,7 @@ private val MESSAGE_META = RoomNotification.Message.Meta(
|
|||||||
)
|
)
|
||||||
private val ONE_SHOT_META = OneShotNotification.Append.Meta(key = "ignored", summaryLine = "ignored", isNoisy = false, timestamp = -1)
|
private val ONE_SHOT_META = OneShotNotification.Append.Meta(key = "ignored", summaryLine = "ignored", isNoisy = false, timestamp = -1)
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
class NotificationRendererTest {
|
class NotificationRendererTest {
|
||||||
|
|
||||||
private val notificationDisplayer = FakeNotificationDisplayer()
|
private val notificationDisplayer = FakeNotificationDisplayer()
|
||||||
@@ -197,7 +201,8 @@ class NotificationRendererTest {
|
|||||||
notificationRenderer.render(
|
notificationRenderer.render(
|
||||||
MatrixUser(A_SESSION_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR_URL),
|
MatrixUser(A_SESSION_ID, MY_USER_DISPLAY_NAME, MY_USER_AVATAR_URL),
|
||||||
useCompleteNotificationFormat = USE_COMPLETE_NOTIFICATION_FORMAT,
|
useCompleteNotificationFormat = USE_COMPLETE_NOTIFICATION_FORMAT,
|
||||||
eventsToProcess = AN_EVENT_LIST
|
eventsToProcess = AN_EVENT_LIST,
|
||||||
|
imageLoader = FakeImageLoader().getImageLoader(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,19 +17,15 @@
|
|||||||
package io.element.android.libraries.push.impl.notifications
|
package io.element.android.libraries.push.impl.notifications
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.drawable.ColorDrawable
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import coil.Coil
|
|
||||||
import coil.ImageLoader
|
|
||||||
import coil.annotation.ExperimentalCoilApi
|
import coil.annotation.ExperimentalCoilApi
|
||||||
import coil.test.FakeImageLoaderEngine
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||||
import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator
|
import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator
|
||||||
|
import io.element.android.libraries.push.impl.notifications.fake.FakeImageLoader
|
||||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||||
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
|
||||||
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
||||||
@@ -50,6 +46,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `test createRoomMessage with one Event`() = runTest {
|
fun `test createRoomMessage with one Event`() = runTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
currentUser = aMatrixUser(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
@@ -58,6 +55,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
val resultMetaWithoutFormatting = result.meta.copy(
|
val resultMetaWithoutFormatting = result.meta.copy(
|
||||||
summaryLine = result.meta.summaryLine.toString()
|
summaryLine = result.meta.summaryLine.toString()
|
||||||
@@ -71,11 +69,13 @@ class RoomGroupMessageCreatorTest {
|
|||||||
shouldBing = false,
|
shouldBing = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test createRoomMessage with one noisy Event`() = runTest {
|
fun `test createRoomMessage with one noisy Event`() = runTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
currentUser = aMatrixUser(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
@@ -84,6 +84,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
val resultMetaWithoutFormatting = result.meta.copy(
|
val resultMetaWithoutFormatting = result.meta.copy(
|
||||||
summaryLine = result.meta.summaryLine.toString()
|
summaryLine = result.meta.summaryLine.toString()
|
||||||
@@ -97,6 +98,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
shouldBing = true,
|
shouldBing = true,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -141,20 +143,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
api: Int,
|
api: Int,
|
||||||
expectedCoilRequests: List<Any>,
|
expectedCoilRequests: List<Any>,
|
||||||
) = runTest {
|
) = runTest {
|
||||||
val coilRequests = mutableListOf<Any>()
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val engine = FakeImageLoaderEngine.Builder()
|
|
||||||
.intercept(
|
|
||||||
predicate = {
|
|
||||||
coilRequests.add(it)
|
|
||||||
true
|
|
||||||
},
|
|
||||||
drawable = ColorDrawable(Color.BLUE)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
val imageLoader = ImageLoader.Builder(RuntimeEnvironment.getApplication())
|
|
||||||
.components { add(engine) }
|
|
||||||
.build()
|
|
||||||
Coil.setImageLoader(imageLoader)
|
|
||||||
val sut = createRoomGroupMessageCreator(
|
val sut = createRoomGroupMessageCreator(
|
||||||
sdkIntProvider = FakeBuildVersionSdkIntProvider(api)
|
sdkIntProvider = FakeBuildVersionSdkIntProvider(api)
|
||||||
)
|
)
|
||||||
@@ -170,6 +159,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
val resultMetaWithoutFormatting = result.meta.copy(
|
val resultMetaWithoutFormatting = result.meta.copy(
|
||||||
summaryLine = result.meta.summaryLine.toString()
|
summaryLine = result.meta.summaryLine.toString()
|
||||||
@@ -183,12 +173,13 @@ class RoomGroupMessageCreatorTest {
|
|||||||
shouldBing = false,
|
shouldBing = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assertThat(coilRequests.toList()).isEqualTo(expectedCoilRequests)
|
assertThat(fakeImageLoader.getCoilRequests()).isEqualTo(expectedCoilRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test createRoomMessage with two Events`() = runTest {
|
fun `test createRoomMessage with two Events`() = runTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
currentUser = aMatrixUser(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
@@ -196,6 +187,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
aNotifiableMessageEvent(timestamp = A_TIMESTAMP + 10),
|
aNotifiableMessageEvent(timestamp = A_TIMESTAMP + 10),
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
val resultMetaWithoutFormatting = result.meta.copy(
|
val resultMetaWithoutFormatting = result.meta.copy(
|
||||||
summaryLine = result.meta.summaryLine.toString()
|
summaryLine = result.meta.summaryLine.toString()
|
||||||
@@ -209,11 +201,13 @@ class RoomGroupMessageCreatorTest {
|
|||||||
shouldBing = false,
|
shouldBing = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test createRoomMessage with smart reply error`() = runTest {
|
fun `test createRoomMessage with smart reply error`() = runTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
currentUser = aMatrixUser(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
@@ -223,6 +217,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
val resultMetaWithoutFormatting = result.meta.copy(
|
val resultMetaWithoutFormatting = result.meta.copy(
|
||||||
summaryLine = result.meta.summaryLine.toString()
|
summaryLine = result.meta.summaryLine.toString()
|
||||||
@@ -236,11 +231,13 @@ class RoomGroupMessageCreatorTest {
|
|||||||
shouldBing = false,
|
shouldBing = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test createRoomMessage for direct room`() = runTest {
|
fun `test createRoomMessage for direct room`() = runTest {
|
||||||
val sut = createRoomGroupMessageCreator()
|
val sut = createRoomGroupMessageCreator()
|
||||||
|
val fakeImageLoader = FakeImageLoader()
|
||||||
val result = sut.createRoomMessage(
|
val result = sut.createRoomMessage(
|
||||||
currentUser = aMatrixUser(),
|
currentUser = aMatrixUser(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
@@ -249,6 +246,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
|
imageLoader = fakeImageLoader.getImageLoader(),
|
||||||
)
|
)
|
||||||
val resultMetaWithoutFormatting = result.meta.copy(
|
val resultMetaWithoutFormatting = result.meta.copy(
|
||||||
summaryLine = result.meta.summaryLine.toString()
|
summaryLine = result.meta.summaryLine.toString()
|
||||||
@@ -262,6 +260,7 @@ class RoomGroupMessageCreatorTest {
|
|||||||
shouldBing = false,
|
shouldBing = false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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 io.element.android.libraries.push.impl.notifications.fake
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.annotation.ExperimentalCoilApi
|
||||||
|
import coil.test.FakeImageLoaderEngine
|
||||||
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoilApi::class)
|
||||||
|
class FakeImageLoader {
|
||||||
|
private val coilRequests = mutableListOf<Any>()
|
||||||
|
|
||||||
|
private var cache: ImageLoader? = null
|
||||||
|
|
||||||
|
fun getImageLoader(): ImageLoader {
|
||||||
|
return cache ?: ImageLoader.Builder(RuntimeEnvironment.getApplication())
|
||||||
|
.components {
|
||||||
|
val engine = FakeImageLoaderEngine.Builder()
|
||||||
|
.intercept(
|
||||||
|
predicate = {
|
||||||
|
coilRequests.add(it)
|
||||||
|
true
|
||||||
|
},
|
||||||
|
drawable = ColorDrawable(Color.BLUE)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
add(engine)
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
.also {
|
||||||
|
cache = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCoilRequests(): List<Any> {
|
||||||
|
return coilRequests.toList()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,13 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.ui.di
|
package io.element.android.libraries.push.impl.notifications.fake
|
||||||
|
|
||||||
import com.squareup.anvil.annotations.ContributesTo
|
import coil.ImageLoader
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.ui.media.LoggedInImageLoaderFactory
|
import io.element.android.libraries.matrix.ui.media.ImageLoaderHolder
|
||||||
|
|
||||||
@ContributesTo(SessionScope::class)
|
class FakeImageLoaderHolder : ImageLoaderHolder {
|
||||||
interface MatrixUIBindings {
|
private val fakeImageLoader = FakeImageLoader()
|
||||||
fun loggedInImageLoaderFactory(): LoggedInImageLoaderFactory
|
override fun get(client: MatrixClient): ImageLoader {
|
||||||
|
return fakeImageLoader.getImageLoader()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ class FakeNotificationFactory {
|
|||||||
summaryNotification: SummaryNotification
|
summaryNotification: SummaryNotification
|
||||||
) {
|
) {
|
||||||
with(instance) {
|
with(instance) {
|
||||||
coEvery { groupedEvents.roomEvents.toNotifications(matrixUser) } returns roomNotifications
|
coEvery { groupedEvents.roomEvents.toNotifications(matrixUser, any()) } returns roomNotifications
|
||||||
every { groupedEvents.invitationEvents.toNotifications() } returns invitationNotifications
|
every { groupedEvents.invitationEvents.toNotifications() } returns invitationNotifications
|
||||||
every { groupedEvents.simpleEvents.toNotifications() } returns simpleNotifications
|
every { groupedEvents.simpleEvents.toNotifications() } returns simpleNotifications
|
||||||
every { groupedEvents.fallbackEvents.toNotifications() } returns fallbackNotifications
|
every { groupedEvents.fallbackEvents.toNotifications() } returns fallbackNotifications
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class FakeRoomGroupMessageCreator {
|
|||||||
currentUser = matrixUser,
|
currentUser = matrixUser,
|
||||||
events = events,
|
events = events,
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
imageLoader = any(),
|
||||||
)
|
)
|
||||||
} returns mockMessage
|
} returns mockMessage
|
||||||
return mockMessage
|
return mockMessage
|
||||||
|
|||||||
Reference in New Issue
Block a user