Merge pull request #3916 from element-hq/feature/bma/notificationActions
Enable all notification actions: quick reply, accept/decline invite, mark as read from notification.
This commit is contained in:
@@ -11,14 +11,20 @@ import android.graphics.Color
|
||||
import androidx.annotation.ColorInt
|
||||
|
||||
object NotificationConfig {
|
||||
// TODO EAx Implement and set to true at some point
|
||||
const val SUPPORT_MARK_AS_READ_ACTION = false
|
||||
/**
|
||||
* If set to true, the notification will have a "Mark as read" action.
|
||||
*/
|
||||
const val SHOW_MARK_AS_READ_ACTION = true
|
||||
|
||||
// TODO EAx Implement and set to true at some point
|
||||
const val SUPPORT_JOIN_DECLINE_INVITE = false
|
||||
/**
|
||||
* If set to true, the notification for invitation will have two actions to accept or decline the invite.
|
||||
*/
|
||||
const val SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS = true
|
||||
|
||||
// TODO EAx Implement and set to true at some point
|
||||
const val SUPPORT_QUICK_REPLY_ACTION = false
|
||||
/**
|
||||
* If set to true, the notification will have a "Quick reply" action, allow to compose and send a message to the room.
|
||||
*/
|
||||
const val SHOW_QUICK_REPLY_ACTION = true
|
||||
|
||||
@ColorInt
|
||||
val NOTIFICATION_ACCENT_COLOR: Int = Color.parseColor("#FF0DBD8B")
|
||||
|
||||
@@ -230,10 +230,8 @@ class DefaultNotificationCreator @Inject constructor(
|
||||
.setSmallIcon(smallIcon)
|
||||
.setColor(accentColor)
|
||||
.apply {
|
||||
if (NotificationConfig.SUPPORT_JOIN_DECLINE_INVITE) {
|
||||
addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent))
|
||||
addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent))
|
||||
}
|
||||
addAction(rejectInvitationActionFactory.create(inviteNotifiableEvent))
|
||||
addAction(acceptInvitationActionFactory.create(inviteNotifiableEvent))
|
||||
// Build the pending intent for when the notification is clicked
|
||||
setContentIntent(pendingIntentFactory.createOpenRoomPendingIntent(inviteNotifiableEvent.sessionId, inviteNotifiableEvent.roomId))
|
||||
|
||||
|
||||
@@ -11,12 +11,14 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.app.NotificationCompat
|
||||
import io.element.android.appconfig.NotificationConfig
|
||||
import io.element.android.libraries.androidutils.uri.createIgnoredUri
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationActionIds
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationBroadcastReceiver
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import javax.inject.Inject
|
||||
@@ -27,8 +29,8 @@ class AcceptInvitationActionFactory @Inject constructor(
|
||||
private val stringProvider: StringProvider,
|
||||
private val clock: SystemClock,
|
||||
) {
|
||||
// offer to type a quick accept button
|
||||
fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action {
|
||||
fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action? {
|
||||
if (!NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS) return null
|
||||
val sessionId = inviteNotifiableEvent.sessionId.value
|
||||
val roomId = inviteNotifiableEvent.roomId.value
|
||||
val intent = Intent(context, NotificationBroadcastReceiver::class.java)
|
||||
@@ -44,7 +46,7 @@ class AcceptInvitationActionFactory @Inject constructor(
|
||||
)
|
||||
return NotificationCompat.Action.Builder(
|
||||
R.drawable.vector_notification_accept_invitation,
|
||||
stringProvider.getString(R.string.notification_invitation_action_join),
|
||||
stringProvider.getString(CommonStrings.action_accept),
|
||||
pendingIntent
|
||||
).build()
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class MarkAsReadActionFactory @Inject constructor(
|
||||
private val clock: SystemClock,
|
||||
) {
|
||||
fun create(roomInfo: RoomEventGroupInfo): NotificationCompat.Action? {
|
||||
if (!NotificationConfig.SUPPORT_MARK_AS_READ_ACTION) return null
|
||||
if (!NotificationConfig.SHOW_MARK_AS_READ_ACTION) return null
|
||||
val sessionId = roomInfo.sessionId.value
|
||||
val roomId = roomInfo.roomId.value
|
||||
val intent = Intent(context, NotificationBroadcastReceiver::class.java)
|
||||
|
||||
@@ -34,7 +34,7 @@ class QuickReplyActionFactory @Inject constructor(
|
||||
private val clock: SystemClock,
|
||||
) {
|
||||
fun create(roomInfo: RoomEventGroupInfo, threadId: ThreadId?): NotificationCompat.Action? {
|
||||
if (!NotificationConfig.SUPPORT_QUICK_REPLY_ACTION) return null
|
||||
if (!NotificationConfig.SHOW_QUICK_REPLY_ACTION) return null
|
||||
val sessionId = roomInfo.sessionId
|
||||
val roomId = roomInfo.roomId
|
||||
val replyPendingIntent = buildQuickReplyIntent(sessionId, roomId, threadId)
|
||||
|
||||
@@ -11,12 +11,14 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.app.NotificationCompat
|
||||
import io.element.android.appconfig.NotificationConfig
|
||||
import io.element.android.libraries.androidutils.uri.createIgnoredUri
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.push.impl.R
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationActionIds
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationBroadcastReceiver
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||
import javax.inject.Inject
|
||||
@@ -28,6 +30,7 @@ class RejectInvitationActionFactory @Inject constructor(
|
||||
private val clock: SystemClock,
|
||||
) {
|
||||
fun create(inviteNotifiableEvent: InviteNotifiableEvent): NotificationCompat.Action? {
|
||||
if (!NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS) return null
|
||||
val sessionId = inviteNotifiableEvent.sessionId.value
|
||||
val roomId = inviteNotifiableEvent.roomId.value
|
||||
val intent = Intent(context, NotificationBroadcastReceiver::class.java)
|
||||
@@ -41,10 +44,9 @@ class RejectInvitationActionFactory @Inject constructor(
|
||||
intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
return NotificationCompat.Action.Builder(
|
||||
R.drawable.vector_notification_reject_invitation,
|
||||
stringProvider.getString(R.string.notification_invitation_action_reject),
|
||||
stringProvider.getString(CommonStrings.action_reject),
|
||||
pendingIntent
|
||||
).build()
|
||||
}
|
||||
|
||||
@@ -11,12 +11,15 @@ import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.appconfig.NotificationConfig
|
||||
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_TIMESTAMP
|
||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||
import io.element.android.libraries.matrix.ui.media.AVATAR_THUMBNAIL_SIZE_IN_PIXEL
|
||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||
import io.element.android.libraries.push.impl.notifications.factories.MARK_AS_READ_ACTION_TITLE
|
||||
import io.element.android.libraries.push.impl.notifications.factories.QUICK_REPLY_ACTION_TITLE
|
||||
import io.element.android.libraries.push.impl.notifications.factories.createNotificationCreator
|
||||
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
|
||||
import io.element.android.libraries.push.test.notifications.FakeImageLoader
|
||||
@@ -156,6 +159,13 @@ class DefaultRoomGroupMessageCreatorTest {
|
||||
)
|
||||
assertThat(result.number).isEqualTo(2)
|
||||
assertThat(result.`when`).isEqualTo(A_TIMESTAMP + 10)
|
||||
val actionTitles = result.actions?.map { it.title }
|
||||
assertThat(actionTitles).isEqualTo(
|
||||
listOfNotNull(
|
||||
MARK_AS_READ_ACTION_TITLE.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION },
|
||||
QUICK_REPLY_ACTION_TITLE.takeIf { NotificationConfig.SHOW_QUICK_REPLY_ACTION },
|
||||
)
|
||||
)
|
||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||
}
|
||||
|
||||
@@ -175,7 +185,12 @@ class DefaultRoomGroupMessageCreatorTest {
|
||||
imageLoader = fakeImageLoader.getImageLoader(),
|
||||
existingNotification = null,
|
||||
)
|
||||
assertThat(result.actions).isNull()
|
||||
val actionTitles = result.actions?.map { it.title }
|
||||
assertThat(actionTitles).isEqualTo(
|
||||
listOfNotNull(
|
||||
MARK_AS_READ_ACTION_TITLE.takeIf { NotificationConfig.SHOW_MARK_AS_READ_ACTION }
|
||||
)
|
||||
)
|
||||
assertThat(fakeImageLoader.getCoilRequests().size).isEqualTo(0)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.appconfig.NotificationConfig
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
@@ -151,6 +152,13 @@ class DefaultNotificationCreatorTest {
|
||||
result.commonAssertions(
|
||||
expectedCategory = null,
|
||||
)
|
||||
val actionTitles = result.actions?.map { it.title }
|
||||
assertThat(actionTitles).isEqualTo(
|
||||
listOfNotNull(
|
||||
REJECT_INVITATION_ACTION_TITLE.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS },
|
||||
ACCEPT_INVITATION_ACTION_TITLE.takeIf { NotificationConfig.SHOW_ACCEPT_AND_DECLINE_INVITE_ACTIONS },
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -271,6 +279,11 @@ class DefaultNotificationCreatorTest {
|
||||
}
|
||||
}
|
||||
|
||||
const val MARK_AS_READ_ACTION_TITLE = "MarkAsReadAction"
|
||||
const val QUICK_REPLY_ACTION_TITLE = "QuickReplyAction"
|
||||
const val ACCEPT_INVITATION_ACTION_TITLE = "AcceptInvitationAction"
|
||||
const val REJECT_INVITATION_ACTION_TITLE = "RejectInvitationAction"
|
||||
|
||||
fun createNotificationCreator(
|
||||
context: Context = RuntimeEnvironment.getApplication(),
|
||||
buildMeta: BuildMeta = aBuildMeta(),
|
||||
@@ -291,26 +304,26 @@ fun createNotificationCreator(
|
||||
markAsReadActionFactory = MarkAsReadActionFactory(
|
||||
context = context,
|
||||
actionIds = NotificationActionIds(buildMeta),
|
||||
stringProvider = FakeStringProvider("MarkAsReadActionFactory"),
|
||||
stringProvider = FakeStringProvider(MARK_AS_READ_ACTION_TITLE),
|
||||
clock = FakeSystemClock(),
|
||||
),
|
||||
quickReplyActionFactory = QuickReplyActionFactory(
|
||||
context = context,
|
||||
actionIds = NotificationActionIds(buildMeta),
|
||||
stringProvider = FakeStringProvider("QuickReplyActionFactory"),
|
||||
stringProvider = FakeStringProvider(QUICK_REPLY_ACTION_TITLE),
|
||||
clock = FakeSystemClock(),
|
||||
),
|
||||
bitmapLoader = bitmapLoader,
|
||||
acceptInvitationActionFactory = AcceptInvitationActionFactory(
|
||||
context = context,
|
||||
actionIds = NotificationActionIds(buildMeta),
|
||||
stringProvider = FakeStringProvider("AcceptInvitationActionFactory"),
|
||||
stringProvider = FakeStringProvider(ACCEPT_INVITATION_ACTION_TITLE),
|
||||
clock = FakeSystemClock(),
|
||||
),
|
||||
rejectInvitationActionFactory = RejectInvitationActionFactory(
|
||||
context = context,
|
||||
actionIds = NotificationActionIds(buildMeta),
|
||||
stringProvider = FakeStringProvider("RejectInvitationActionFactory"),
|
||||
stringProvider = FakeStringProvider(REJECT_INVITATION_ACTION_TITLE),
|
||||
clock = FakeSystemClock(),
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user