Add room notification settings (#807)
* Add room notification settings --------- Co-authored-by: ElementBot <benoitm+elementbot@element.io> Co-authored-by: Jorge Martín <jorgem@element.io> Co-authored-by: Benoit Marty <benoit@matrix.org> Co-authored-by: David Langley <langley.dave@gmail.com>
This commit is contained in:
parent
a40c9ef002
commit
4a5a01d710
68 changed files with 1381 additions and 70 deletions
|
|
@ -39,6 +39,8 @@ import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
|||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.toEnabledColor
|
||||
import io.element.android.libraries.designsystem.toSecondaryEnabledColor
|
||||
import io.element.android.libraries.theme.ElementTheme
|
||||
|
||||
/**
|
||||
|
|
@ -48,6 +50,7 @@ import io.element.android.libraries.theme.ElementTheme
|
|||
fun PreferenceText(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
subtitle: String? = null,
|
||||
currentValue: String? = null,
|
||||
loadingCurrentValue: Boolean = false,
|
||||
|
|
@ -68,8 +71,9 @@ fun PreferenceText(
|
|||
) {
|
||||
PreferenceIcon(
|
||||
icon = icon,
|
||||
enabled = enabled,
|
||||
isVisible = showIconAreaIfNoIcon,
|
||||
tintColor = tintColor ?: ElementTheme.materialColors.secondary
|
||||
tintColor = tintColor ?: enabled.toSecondaryEnabledColor(),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -79,13 +83,13 @@ fun PreferenceText(
|
|||
Text(
|
||||
style = ElementTheme.typography.fontBodyLgRegular,
|
||||
text = title,
|
||||
color = tintColor ?: ElementTheme.materialColors.primary,
|
||||
color = tintColor ?: enabled.toEnabledColor(),
|
||||
)
|
||||
if (subtitle != null) {
|
||||
Text(
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
text = subtitle,
|
||||
color = tintColor ?: ElementTheme.materialColors.secondary,
|
||||
color = tintColor ?: enabled.toSecondaryEnabledColor(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -96,7 +100,7 @@ fun PreferenceText(
|
|||
.padding(start = 16.dp, end = 8.dp),
|
||||
text = currentValue,
|
||||
style = ElementTheme.typography.fontBodyXsMedium,
|
||||
color = ElementTheme.materialColors.secondary,
|
||||
color = enabled.toSecondaryEnabledColor(),
|
||||
)
|
||||
} else if (loadingCurrentValue) {
|
||||
CircularProgressIndicator(
|
||||
|
|
@ -135,6 +139,13 @@ private fun ContentToPreview() {
|
|||
icon = Icons.Default.BugReport,
|
||||
currentValue = "123",
|
||||
)
|
||||
PreferenceText(
|
||||
title = "Title",
|
||||
subtitle = "Some content",
|
||||
icon = Icons.Default.BugReport,
|
||||
currentValue = "123",
|
||||
enabled = false,
|
||||
)
|
||||
PreferenceText(
|
||||
title = "Title",
|
||||
subtitle = "Some content",
|
||||
|
|
|
|||
|
|
@ -30,5 +30,11 @@ enum class FeatureFlags(
|
|||
key = "feature.polls",
|
||||
title = "Polls",
|
||||
description = "Create poll and render poll events in the timeline",
|
||||
defaultValue = false,
|
||||
),
|
||||
NotificationSettings(
|
||||
key = "feature.notificationsettings",
|
||||
title = "Show notification settings",
|
||||
defaultValue = false,
|
||||
),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class BuildtimeFeatureFlagProvider @Inject constructor() :
|
|||
when (feature) {
|
||||
FeatureFlags.LocationSharing -> true
|
||||
FeatureFlags.Polls -> false
|
||||
FeatureFlags.NotificationSettings -> false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.core.UserId
|
|||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
|
|
@ -49,6 +50,7 @@ interface MatrixClient : Closeable {
|
|||
fun sessionVerificationService(): SessionVerificationService
|
||||
fun pushersService(): PushersService
|
||||
fun notificationService(): NotificationService
|
||||
fun notificationSettingsService(): NotificationSettingsService
|
||||
suspend fun getCacheSize(): Long
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.api.notificationsettings
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
||||
interface NotificationSettingsService {
|
||||
/**
|
||||
* State of the current room notification settings flow ([MatrixRoomNotificationSettingsState.Unknown] if not started).
|
||||
*/
|
||||
val notificationSettingsChangeFlow : SharedFlow<Unit>
|
||||
suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationSettings>
|
||||
suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationMode>
|
||||
suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit>
|
||||
suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit>
|
||||
suspend fun muteRoom(roomId: RoomId): Result<Unit>
|
||||
suspend fun unmuteRoom(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<Unit>
|
||||
}
|
||||
|
|
@ -56,11 +56,15 @@ interface MatrixRoom : Closeable {
|
|||
*/
|
||||
val membersStateFlow: StateFlow<MatrixRoomMembersState>
|
||||
|
||||
val roomNotificationSettingsStateFlow: StateFlow<MatrixRoomNotificationSettingsState>
|
||||
|
||||
/**
|
||||
* Try to load the room members and update the membersFlow.
|
||||
*/
|
||||
suspend fun updateMembers(): Result<Unit>
|
||||
|
||||
suspend fun updateRoomNotificationSettings(): Result<Unit>
|
||||
|
||||
val syncUpdateFlow: StateFlow<Long>
|
||||
|
||||
val timeline: MatrixTimeline
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.api.room
|
||||
|
||||
sealed interface MatrixRoomNotificationSettingsState {
|
||||
object Unknown : MatrixRoomNotificationSettingsState
|
||||
data class Pending(val prevRoomNotificationSettings: RoomNotificationSettings? = null) : MatrixRoomNotificationSettingsState
|
||||
data class Error(val failure: Throwable, val prevRoomNotificationSettings: RoomNotificationSettings? = null) : MatrixRoomNotificationSettingsState
|
||||
data class Ready(val roomNotificationSettings: RoomNotificationSettings) : MatrixRoomNotificationSettingsState
|
||||
}
|
||||
|
||||
fun MatrixRoomNotificationSettingsState.roomNotificationSettings(): RoomNotificationSettings? {
|
||||
return when (this) {
|
||||
is MatrixRoomNotificationSettingsState.Ready -> roomNotificationSettings
|
||||
is MatrixRoomNotificationSettingsState.Pending -> prevRoomNotificationSettings
|
||||
is MatrixRoomNotificationSettingsState.Error -> prevRoomNotificationSettings
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.api.room
|
||||
|
||||
data class RoomNotificationSettings(
|
||||
val mode: RoomNotificationMode,
|
||||
val isDefault: Boolean,
|
||||
)
|
||||
|
||||
enum class RoomNotificationMode {
|
||||
ALL_MESSAGES, MENTIONS_AND_KEYWORDS_ONLY, MUTE
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
|||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
|
|
@ -42,6 +43,7 @@ import io.element.android.libraries.matrix.impl.core.toProgressWatcher
|
|||
import io.element.android.libraries.matrix.impl.mapper.toSessionData
|
||||
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
||||
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
||||
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
||||
import io.element.android.libraries.matrix.impl.room.RoomContentForwarder
|
||||
import io.element.android.libraries.matrix.impl.room.RustMatrixRoom
|
||||
|
|
@ -99,6 +101,7 @@ class RustMatrixClient constructor(
|
|||
client = client,
|
||||
dispatchers = dispatchers,
|
||||
)
|
||||
|
||||
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(syncService)
|
||||
private val notificationClient = client.notificationClient(notificationProcessSetup)
|
||||
.use { builder ->
|
||||
|
|
@ -106,8 +109,10 @@ class RustMatrixClient constructor(
|
|||
.filterByPushRules()
|
||||
.finish()
|
||||
}
|
||||
private val notificationSettings = client.getNotificationSettings()
|
||||
|
||||
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
|
||||
private val notificationSettingsService = RustNotificationSettingsService(notificationSettings, dispatchers)
|
||||
|
||||
private val isLoggingOut = AtomicBoolean(false)
|
||||
|
||||
|
|
@ -173,6 +178,7 @@ class RustMatrixClient constructor(
|
|||
sessionId = sessionId,
|
||||
roomListItem = roomListItem,
|
||||
innerRoom = fullRoom,
|
||||
roomNotificationSettingsService = notificationSettingsService,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
coroutineDispatchers = dispatchers,
|
||||
systemClock = clock,
|
||||
|
|
@ -277,9 +283,13 @@ class RustMatrixClient constructor(
|
|||
|
||||
override fun notificationService(): NotificationService = notificationService
|
||||
|
||||
override fun notificationSettingsService(): NotificationSettingsService = notificationSettingsService
|
||||
|
||||
override fun close() {
|
||||
sessionCoroutineScope.cancel()
|
||||
client.setDelegate(null)
|
||||
notificationSettings.setDelegate(null)
|
||||
notificationSettings.destroy()
|
||||
verificationService.destroy()
|
||||
syncService.destroy()
|
||||
innerRoomListService.destroy()
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import dagger.Provides
|
|||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
|
|
@ -34,6 +35,11 @@ object SessionMatrixModule {
|
|||
return matrixClient.sessionVerificationService()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun providesNotificationSettingsService(matrixClient: MatrixClient): NotificationSettingsService {
|
||||
return matrixClient.notificationSettingsService()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideRoomMembershipObserver(matrixClient: MatrixClient): RoomMembershipObserver {
|
||||
return matrixClient.roomMembershipObserver()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.impl.notificationsettings
|
||||
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationMode as RustRoomNotificationMode
|
||||
import org.matrix.rustcomponents.sdk.RoomNotificationSettings as RustRoomNotificationSettings
|
||||
|
||||
object RoomNotificationSettingsMapper {
|
||||
fun map(roomNotificationSettings: RustRoomNotificationSettings): RoomNotificationSettings =
|
||||
RoomNotificationSettings(
|
||||
mode = mapMode(roomNotificationSettings.mode),
|
||||
isDefault = roomNotificationSettings.isDefault
|
||||
)
|
||||
|
||||
fun mapMode(mode: RustRoomNotificationMode): RoomNotificationMode =
|
||||
when (mode) {
|
||||
RustRoomNotificationMode.ALL_MESSAGES -> RoomNotificationMode.ALL_MESSAGES
|
||||
RustRoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
RustRoomNotificationMode.MUTE -> RoomNotificationMode.MUTE
|
||||
}
|
||||
|
||||
fun mapMode(mode: RoomNotificationMode): RustRoomNotificationMode =
|
||||
when (mode) {
|
||||
RoomNotificationMode.ALL_MESSAGES -> RustRoomNotificationMode.ALL_MESSAGES
|
||||
RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> RustRoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||
RoomNotificationMode.MUTE -> RustRoomNotificationMode.MUTE
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.impl.notificationsettings
|
||||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.NotificationSettings
|
||||
import org.matrix.rustcomponents.sdk.NotificationSettingsDelegate
|
||||
|
||||
class RustNotificationSettingsService(
|
||||
private val notificationSettings: NotificationSettings,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : NotificationSettingsService {
|
||||
|
||||
private val _notificationSettingsChangeFlow = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
override val notificationSettingsChangeFlow: SharedFlow<Unit> = _notificationSettingsChangeFlow.asSharedFlow()
|
||||
|
||||
private var notificationSettingsDelegate = object : NotificationSettingsDelegate {
|
||||
override fun settingsDidChange() {
|
||||
_notificationSettingsChangeFlow.tryEmit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
notificationSettings.setDelegate(notificationSettingsDelegate)
|
||||
}
|
||||
|
||||
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationSettings> =
|
||||
runCatching {
|
||||
notificationSettings.getRoomNotificationSettings(roomId.value, isEncrypted, isOneToOne(membersCount)).let(RoomNotificationSettingsMapper::map)
|
||||
}
|
||||
|
||||
override suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationMode> =
|
||||
runCatching {
|
||||
notificationSettings.getDefaultRoomNotificationMode(isEncrypted, isOneToOne(membersCount)).let(RoomNotificationSettingsMapper::mapMode)
|
||||
}
|
||||
|
||||
override suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
notificationSettings.setRoomNotificationMode(roomId.value, mode.let(RoomNotificationSettingsMapper::mapMode))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
notificationSettings.restoreDefaultRoomNotificationMode(roomId.value)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun muteRoom(roomId: RoomId): Result<Unit> = setRoomNotificationMode(roomId, RoomNotificationMode.MUTE)
|
||||
|
||||
override suspend fun unmuteRoom(roomId: RoomId, isEncrypted: Boolean, membersCount: Long) = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
notificationSettings.unmuteRoom(roomId.value, isEncrypted, isOneToOne(membersCount))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A one-to-one is a room with exactly 2 members.
|
||||
* See [the Matrix spec](https://spec.matrix.org/latest/client-server-api/#default-underride-rules).
|
||||
* @param membersCount The active members count in a room
|
||||
*/
|
||||
private fun isOneToOne(membersCount: Long) = membersCount == 2L
|
||||
}
|
||||
|
|
@ -33,16 +33,19 @@ import io.element.android.libraries.matrix.api.media.VideoInfo
|
|||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.room.roomMembers
|
||||
import io.element.android.libraries.matrix.api.room.roomNotificationSettings
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventType
|
||||
import io.element.android.libraries.matrix.impl.core.toProgressWatcher
|
||||
import io.element.android.libraries.matrix.impl.media.MediaUploadHandlerImpl
|
||||
import io.element.android.libraries.matrix.impl.media.map
|
||||
import io.element.android.libraries.matrix.impl.poll.toInner
|
||||
import io.element.android.libraries.matrix.impl.notificationsettings.RustNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.impl.room.location.toInner
|
||||
import io.element.android.libraries.matrix.impl.timeline.RustMatrixTimeline
|
||||
import io.element.android.libraries.matrix.impl.util.destroyAll
|
||||
|
|
@ -72,6 +75,7 @@ class RustMatrixRoom(
|
|||
override val sessionId: SessionId,
|
||||
private val roomListItem: RoomListItem,
|
||||
private val innerRoom: Room,
|
||||
private val roomNotificationSettingsService: RustNotificationSettingsService,
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
private val systemClock: SystemClock,
|
||||
|
|
@ -90,6 +94,10 @@ class RustMatrixRoom(
|
|||
private val roomCoroutineScope = sessionCoroutineScope.childScope(coroutineDispatchers.main, "RoomScope-$roomId")
|
||||
private val _membersStateFlow = MutableStateFlow<MatrixRoomMembersState>(MatrixRoomMembersState.Unknown)
|
||||
private val _syncUpdateFlow = MutableStateFlow(0L)
|
||||
|
||||
private val _roomNotificationSettingsStateFlow = MutableStateFlow<MatrixRoomNotificationSettingsState>(MatrixRoomNotificationSettingsState.Unknown)
|
||||
override val roomNotificationSettingsStateFlow: StateFlow<MatrixRoomNotificationSettingsState> = _roomNotificationSettingsStateFlow
|
||||
|
||||
private val _timeline by lazy {
|
||||
RustMatrixTimeline(
|
||||
matrixRoom = this,
|
||||
|
|
@ -197,6 +205,22 @@ class RustMatrixRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = withContext(coroutineDispatchers.io) {
|
||||
val currentState = _roomNotificationSettingsStateFlow.value
|
||||
val currentRoomNotificationSettings = currentState.roomNotificationSettings()
|
||||
_roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Pending(prevRoomNotificationSettings = currentRoomNotificationSettings)
|
||||
runCatching {
|
||||
roomNotificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, activeMemberCount).getOrThrow()
|
||||
}.map {
|
||||
_roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(it)
|
||||
}.onFailure {
|
||||
_roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Error(
|
||||
prevRoomNotificationSettings = currentRoomNotificationSettings,
|
||||
failure = it
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun userAvatarUrl(userId: UserId): Result<String?> = withContext(roomDispatcher) {
|
||||
runCatching {
|
||||
innerRoom.memberAvatarUrl(userId.value)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import io.element.android.libraries.matrix.api.core.UserId
|
|||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.media.MatrixMediaLoader
|
||||
import io.element.android.libraries.matrix.api.notification.NotificationService
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
|
|
@ -33,6 +34,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
|||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaLoader
|
||||
import io.element.android.libraries.matrix.test.notification.FakeNotificationService
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.test.pushers.FakePushersService
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||
|
|
@ -50,6 +52,7 @@ class FakeMatrixClient(
|
|||
private val sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
|
||||
private val pushersService: FakePushersService = FakePushersService(),
|
||||
private val notificationService: FakeNotificationService = FakeNotificationService(),
|
||||
private val notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
private val syncService: FakeSyncService = FakeSyncService(),
|
||||
private val accountManagementUrlString: Result<String?> = Result.success(null),
|
||||
) : MatrixClient {
|
||||
|
|
@ -142,6 +145,7 @@ class FakeMatrixClient(
|
|||
override fun pushersService(): PushersService = pushersService
|
||||
|
||||
override fun notificationService(): NotificationService = notificationService
|
||||
override fun notificationSettingsService(): NotificationSettingsService = notificationSettingsService
|
||||
|
||||
override fun roomMembershipObserver(): RoomMembershipObserver {
|
||||
return RoomMembershipObserver()
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import io.element.android.libraries.matrix.api.core.SpaceId
|
|||
import io.element.android.libraries.matrix.api.core.ThreadId
|
||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
|
||||
|
||||
const val A_USER_NAME = "alice"
|
||||
const val A_PASSWORD = "password"
|
||||
|
|
@ -59,6 +61,8 @@ const val A_HOMESERVER_URL_2 = "matrix-client.org"
|
|||
|
||||
val A_HOMESERVER = MatrixHomeServerDetails(A_HOMESERVER_URL, supportsPasswordLogin = true, supportsOidcLogin = false)
|
||||
val A_HOMESERVER_OIDC = MatrixHomeServerDetails(A_HOMESERVER_URL, supportsPasswordLogin = false, supportsOidcLogin = true)
|
||||
val A_ROOM_NOTIFICATION_MODE = RoomNotificationMode.MUTE
|
||||
val A_ROOM_NOTIFICATION_SETTINGS = RoomNotificationSettings(mode = A_ROOM_NOTIFICATION_MODE, isDefault = false)
|
||||
|
||||
const val AN_AVATAR_URL = "mxc://data"
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.test.notificationsettings
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_NOTIFICATION_MODE
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
||||
class FakeNotificationSettingsService(
|
||||
initialMode: RoomNotificationMode = A_ROOM_NOTIFICATION_MODE,
|
||||
initialDefaultMode: RoomNotificationMode = A_ROOM_NOTIFICATION_MODE
|
||||
) : NotificationSettingsService {
|
||||
private var _roomNotificationSettingsStateFlow = MutableStateFlow(Unit)
|
||||
private var defaultRoomNotificationMode: RoomNotificationMode = initialDefaultMode
|
||||
private var roomNotificationMode: RoomNotificationMode = initialMode
|
||||
override val notificationSettingsChangeFlow: SharedFlow<Unit>
|
||||
get() = _roomNotificationSettingsStateFlow
|
||||
|
||||
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationSettings> {
|
||||
return Result.success(RoomNotificationSettings(mode = roomNotificationMode, isDefault = roomNotificationMode == defaultRoomNotificationMode))
|
||||
}
|
||||
|
||||
override suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationMode> {
|
||||
return Result.success(defaultRoomNotificationMode)
|
||||
}
|
||||
|
||||
override suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit> {
|
||||
roomNotificationMode = mode
|
||||
_roomNotificationSettingsStateFlow.emit(Unit)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit> {
|
||||
roomNotificationMode = defaultRoomNotificationMode
|
||||
_roomNotificationSettingsStateFlow.emit(Unit)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun muteRoom(roomId: RoomId): Result<Unit> {
|
||||
return setRoomNotificationMode(roomId, RoomNotificationMode.MUTE)
|
||||
}
|
||||
|
||||
override suspend fun unmuteRoom(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<Unit> {
|
||||
return restoreDefaultRoomNotificationMode(roomId)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,16 +27,19 @@ import io.element.android.libraries.matrix.api.media.FileInfo
|
|||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||
import io.element.android.libraries.matrix.api.media.MediaUploadHandler
|
||||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
import io.element.android.libraries.matrix.api.room.MessageEventType
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettingsState
|
||||
import io.element.android.libraries.matrix.api.room.StateEventType
|
||||
import io.element.android.libraries.matrix.api.room.location.AssetType
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||
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.media.FakeMediaUploadHandler
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||
import io.element.android.tests.testutils.simulateLongTask
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -58,6 +61,7 @@ class FakeMatrixRoom(
|
|||
override val isDirect: Boolean = false,
|
||||
override val joinedMemberCount: Long = 123L,
|
||||
override val activeMemberCount: Long = 234L,
|
||||
val notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(),
|
||||
private val matrixTimeline: MatrixTimeline = FakeMatrixTimeline(),
|
||||
canRedact: Boolean = false,
|
||||
) : MatrixRoom {
|
||||
|
|
@ -136,10 +140,19 @@ class FakeMatrixRoom(
|
|||
|
||||
override val membersStateFlow: MutableStateFlow<MatrixRoomMembersState> = MutableStateFlow(MatrixRoomMembersState.Unknown)
|
||||
|
||||
override val roomNotificationSettingsStateFlow: MutableStateFlow<MatrixRoomNotificationSettingsState> =
|
||||
MutableStateFlow(MatrixRoomNotificationSettingsState.Unknown)
|
||||
|
||||
override suspend fun updateMembers(): Result<Unit> = simulateLongTask {
|
||||
updateMembersResult
|
||||
}
|
||||
|
||||
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
|
||||
val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, activeMemberCount).getOrThrow()
|
||||
roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(notificationSettings)
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override val syncUpdateFlow: StateFlow<Long> = MutableStateFlow(0L)
|
||||
|
||||
override val timeline: MatrixTimeline = matrixTimeline
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="Use_an_identity_server_to_invite_by_email.__default_Use_the_default____defaultIdentityServerName_s___default__or_manage_in__settings_Settings__settings_._web">"Use an identity server to invite by email. "<default>"Use the default (%(defaultIdentityServerName)s)"</default>" or manage in "<settings>"Settings"</settings>"."</string>
|
||||
<string name="a11y_hide_password">"Hide password"</string>
|
||||
<string name="a11y_notifications_mentions_only">"Mentions only"</string>
|
||||
<string name="a11y_notifications_muted">"Muted"</string>
|
||||
|
|
@ -161,6 +162,10 @@
|
|||
<string name="leave_room_alert_private_subtitle">"Are you sure that you want to leave this room? This room is not public and you won\'t be able to rejoin without an invite."</string>
|
||||
<string name="leave_room_alert_subtitle">"Are you sure that you want to leave the room?"</string>
|
||||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<plurals name="__count_s_rooms_web">
|
||||
<item quantity="one">"%(count)s room"</item>
|
||||
<item quantity="other">"%(count)s rooms"</item>
|
||||
</plurals>
|
||||
<plurals name="common_member_count">
|
||||
<item quantity="one">"%1$d member"</item>
|
||||
<item quantity="other">"%1$d members"</item>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue