Merge branch 'develop' into feature/fga/user_detail_direct_chat
This commit is contained in:
commit
03a2e31d46
76 changed files with 329 additions and 148 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
2
.github/workflows/maestro.yml
vendored
2
.github/workflows/maestro.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
# Ensure we are building the branch and not the branch after being merged on develop
|
# Ensure we are building the branch and not the branch after being merged on develop
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v4
|
||||||
name: Use JDK 17
|
name: Use JDK 17
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
|
|
|
||||||
2
.github/workflows/nightly.yml
vendored
2
.github/workflows/nightly.yml
vendored
|
|
@ -18,7 +18,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
4
.github/workflows/nightlyReports.yml
vendored
4
.github/workflows/nightlyReports.yml
vendored
|
|
@ -21,7 +21,7 @@ jobs:
|
||||||
uses: nschloe/action-cached-lfs-checkout@v1.2.2
|
uses: nschloe/action-cached-lfs-checkout@v1.2.2
|
||||||
|
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
@ -57,7 +57,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
2
.github/workflows/quality.yml
vendored
2
.github/workflows/quality.yml
vendored
|
|
@ -35,7 +35,7 @@ jobs:
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
2
.github/workflows/recordScreenshots.yml
vendored
2
.github/workflows/recordScreenshots.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: ☕️ Use JDK 17
|
- name: ☕️ Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
2
.github/workflows/sonar.yml
vendored
2
.github/workflows/sonar.yml
vendored
|
|
@ -27,7 +27,7 @@ jobs:
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
- name: Use JDK 17
|
- name: Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
|
@ -39,7 +39,7 @@ jobs:
|
||||||
# https://github.com/actions/checkout/issues/881
|
# https://github.com/actions/checkout/issues/881
|
||||||
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }}
|
||||||
- name: ☕️ Use JDK 17
|
- name: ☕️ Use JDK 17
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||||
java-version: '17'
|
java-version: '17'
|
||||||
|
|
|
||||||
|
|
@ -376,3 +376,22 @@ subprojects {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
subprojects {
|
||||||
|
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||||
|
kotlinOptions {
|
||||||
|
if (project.findProperty("composeCompilerReports") == "true") {
|
||||||
|
freeCompilerArgs += listOf(
|
||||||
|
"-P",
|
||||||
|
"plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (project.findProperty("composeCompilerMetrics") == "true") {
|
||||||
|
freeCompilerArgs += listOf(
|
||||||
|
"-P",
|
||||||
|
"plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.layout.buildDirectory.asFile.get().absolutePath}/compose_compiler"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
1
changelog.d/+make-matrix-classes-immutable.misc
Normal file
1
changelog.d/+make-matrix-classes-immutable.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Make most code used in Compose from `:libraries:matrix` and derived classes Immutable or Stable.
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Set a default power level to join calls. Also, create new rooms taking this power level into account.
|
||||||
|
|
@ -79,6 +79,7 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
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.MessageEventType
|
||||||
|
import io.element.android.libraries.matrix.api.user.CurrentSessionIdHolder
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
|
||||||
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
|
||||||
import io.element.android.libraries.matrix.ui.room.canRedactAsState
|
import io.element.android.libraries.matrix.ui.room.canRedactAsState
|
||||||
|
|
@ -108,6 +109,7 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
private val featureFlagsService: FeatureFlagService,
|
private val featureFlagsService: FeatureFlagService,
|
||||||
@Assisted private val navigator: MessagesNavigator,
|
@Assisted private val navigator: MessagesNavigator,
|
||||||
private val buildMeta: BuildMeta,
|
private val buildMeta: BuildMeta,
|
||||||
|
private val currentSessionIdHolder: CurrentSessionIdHolder,
|
||||||
) : Presenter<MessagesState> {
|
) : Presenter<MessagesState> {
|
||||||
|
|
||||||
private val timelinePresenter = timelinePresenterFactory.create(navigator = navigator)
|
private val timelinePresenter = timelinePresenterFactory.create(navigator = navigator)
|
||||||
|
|
@ -133,10 +135,10 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
|
||||||
val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
|
val userHasPermissionToSendMessage by room.canSendMessageAsState(type = MessageEventType.ROOM_MESSAGE, updateKey = syncUpdateFlow.value)
|
||||||
val userHasPermissionToRedact by room.canRedactAsState(updateKey = syncUpdateFlow.value)
|
val userHasPermissionToRedact by room.canRedactAsState(updateKey = syncUpdateFlow.value)
|
||||||
val roomName: Async<String> by remember(roomInfo?.name) {
|
val roomName: Async<String> by remember {
|
||||||
derivedStateOf { roomInfo?.name?.let { Async.Success(it) } ?: Async.Uninitialized }
|
derivedStateOf { roomInfo?.name?.let { Async.Success(it) } ?: Async.Uninitialized }
|
||||||
}
|
}
|
||||||
val roomAvatar: Async<AvatarData> by remember(roomInfo?.avatarUrl) {
|
val roomAvatar: Async<AvatarData> by remember {
|
||||||
derivedStateOf { roomInfo?.avatarData()?.let { Async.Success(it) } ?: Async.Uninitialized }
|
derivedStateOf { roomInfo?.avatarData()?.let { Async.Success(it) } ?: Async.Uninitialized }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,6 +146,16 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var canJoinCall by rememberSaveable {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(currentSessionIdHolder.current) {
|
||||||
|
withContext(dispatchers.io) {
|
||||||
|
canJoinCall = room.canUserJoinCall(userId = currentSessionIdHolder.current).getOrDefault(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val inviteProgress = remember { mutableStateOf<Async<Unit>>(Async.Uninitialized) }
|
val inviteProgress = remember { mutableStateOf<Async<Unit>>(Async.Uninitialized) }
|
||||||
var showReinvitePrompt by remember { mutableStateOf(false) }
|
var showReinvitePrompt by remember { mutableStateOf(false) }
|
||||||
LaunchedEffect(hasDismissedInviteDialog, composerState.hasFocus, syncUpdateFlow) {
|
LaunchedEffect(hasDismissedInviteDialog, composerState.hasFocus, syncUpdateFlow) {
|
||||||
|
|
@ -162,8 +174,6 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
val enableTextFormatting by preferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true)
|
val enableTextFormatting by preferencesStore.isRichTextEditorEnabledFlow().collectAsState(initial = true)
|
||||||
|
|
||||||
var enableVoiceMessages by remember { mutableStateOf(false) }
|
var enableVoiceMessages by remember { mutableStateOf(false) }
|
||||||
// TODO add min power level to use this feature in the future?
|
|
||||||
val enableInRoomCalls = true
|
|
||||||
LaunchedEffect(featureFlagsService) {
|
LaunchedEffect(featureFlagsService) {
|
||||||
enableVoiceMessages = featureFlagsService.isFeatureEnabled(FeatureFlags.VoiceMessages)
|
enableVoiceMessages = featureFlagsService.isFeatureEnabled(FeatureFlags.VoiceMessages)
|
||||||
}
|
}
|
||||||
|
|
@ -193,6 +203,12 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val callState = when {
|
||||||
|
!canJoinCall -> RoomCallState.DISABLED
|
||||||
|
roomInfo?.hasRoomCall == true -> RoomCallState.ONGOING
|
||||||
|
else -> RoomCallState.ENABLED
|
||||||
|
}
|
||||||
|
|
||||||
return MessagesState(
|
return MessagesState(
|
||||||
roomId = room.roomId,
|
roomId = room.roomId,
|
||||||
roomName = roomName,
|
roomName = roomName,
|
||||||
|
|
@ -213,9 +229,8 @@ class MessagesPresenter @AssistedInject constructor(
|
||||||
inviteProgress = inviteProgress.value,
|
inviteProgress = inviteProgress.value,
|
||||||
enableTextFormatting = enableTextFormatting,
|
enableTextFormatting = enableTextFormatting,
|
||||||
enableVoiceMessages = enableVoiceMessages,
|
enableVoiceMessages = enableVoiceMessages,
|
||||||
enableInRoomCalls = enableInRoomCalls,
|
|
||||||
appName = buildMeta.applicationName,
|
appName = buildMeta.applicationName,
|
||||||
isCallOngoing = roomInfo?.hasRoomCall ?: false,
|
callState = callState,
|
||||||
eventSink = { handleEvents(it) }
|
eventSink = { handleEvents(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,13 @@ data class MessagesState(
|
||||||
val showReinvitePrompt: Boolean,
|
val showReinvitePrompt: Boolean,
|
||||||
val enableTextFormatting: Boolean,
|
val enableTextFormatting: Boolean,
|
||||||
val enableVoiceMessages: Boolean,
|
val enableVoiceMessages: Boolean,
|
||||||
val enableInRoomCalls: Boolean,
|
val callState: RoomCallState,
|
||||||
val isCallOngoing: Boolean,
|
|
||||||
val appName: String,
|
val appName: String,
|
||||||
val eventSink: (MessagesEvents) -> Unit
|
val eventSink: (MessagesEvents) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class RoomCallState {
|
||||||
|
ENABLED,
|
||||||
|
ONGOING,
|
||||||
|
DISABLED
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
aMessagesState().copy(
|
aMessagesState().copy(
|
||||||
isCallOngoing = true,
|
callState = RoomCallState.ONGOING,
|
||||||
),
|
),
|
||||||
aMessagesState().copy(
|
aMessagesState().copy(
|
||||||
enableVoiceMessages = true,
|
enableVoiceMessages = true,
|
||||||
|
|
@ -75,6 +75,9 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
||||||
showSendFailureDialog = true
|
showSendFailureDialog = true
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
aMessagesState().copy(
|
||||||
|
callState = RoomCallState.DISABLED,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,8 +120,7 @@ fun aMessagesState() = MessagesState(
|
||||||
showReinvitePrompt = false,
|
showReinvitePrompt = false,
|
||||||
enableTextFormatting = true,
|
enableTextFormatting = true,
|
||||||
enableVoiceMessages = true,
|
enableVoiceMessages = true,
|
||||||
enableInRoomCalls = true,
|
callState = RoomCallState.ENABLED,
|
||||||
isCallOngoing = false,
|
|
||||||
appName = "Element",
|
appName = "Element",
|
||||||
eventSink = {}
|
eventSink = {}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -191,10 +191,9 @@ fun MessagesView(
|
||||||
MessagesViewTopBar(
|
MessagesViewTopBar(
|
||||||
roomName = state.roomName.dataOrNull(),
|
roomName = state.roomName.dataOrNull(),
|
||||||
roomAvatar = state.roomAvatar.dataOrNull(),
|
roomAvatar = state.roomAvatar.dataOrNull(),
|
||||||
inRoomCallsEnabled = state.enableInRoomCalls,
|
callState = state.callState,
|
||||||
onBackPressed = onBackPressed,
|
onBackPressed = onBackPressed,
|
||||||
onRoomDetailsClicked = onRoomDetailsClicked,
|
onRoomDetailsClicked = onRoomDetailsClicked,
|
||||||
isCallOngoing = state.isCallOngoing,
|
|
||||||
onJoinCallClicked = onJoinCallClicked,
|
onJoinCallClicked = onJoinCallClicked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -449,8 +448,7 @@ private fun MessagesViewComposerBottomSheetContents(
|
||||||
private fun MessagesViewTopBar(
|
private fun MessagesViewTopBar(
|
||||||
roomName: String?,
|
roomName: String?,
|
||||||
roomAvatar: AvatarData?,
|
roomAvatar: AvatarData?,
|
||||||
inRoomCallsEnabled: Boolean,
|
callState: RoomCallState,
|
||||||
isCallOngoing: Boolean,
|
|
||||||
onRoomDetailsClicked: () -> Unit,
|
onRoomDetailsClicked: () -> Unit,
|
||||||
onJoinCallClicked: () -> Unit,
|
onJoinCallClicked: () -> Unit,
|
||||||
onBackPressed: () -> Unit,
|
onBackPressed: () -> Unit,
|
||||||
|
|
@ -477,13 +475,11 @@ private fun MessagesViewTopBar(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
if (inRoomCallsEnabled) {
|
if (callState == RoomCallState.ONGOING) {
|
||||||
if (isCallOngoing) {
|
JoinCallMenuItem(onJoinCallClicked = onJoinCallClicked)
|
||||||
JoinCallMenuItem(onJoinCallClicked = onJoinCallClicked)
|
} else {
|
||||||
} else {
|
IconButton(onClick = onJoinCallClicked, enabled = callState != RoomCallState.DISABLED) {
|
||||||
IconButton(onClick = onJoinCallClicked) {
|
Icon(CompoundIcons.VideoCall, contentDescription = stringResource(CommonStrings.a11y_start_call))
|
||||||
Icon(CompoundIcons.VideoCall, contentDescription = stringResource(CommonStrings.a11y_start_call))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -127,8 +129,8 @@ class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
|
||||||
question = "Poll which are being replied.",
|
question = "Poll which are being replied.",
|
||||||
kind = PollKind.Disclosed,
|
kind = PollKind.Disclosed,
|
||||||
maxSelections = 1u,
|
maxSelections = 1u,
|
||||||
answers = emptyList(),
|
answers = persistentListOf(),
|
||||||
votes = emptyMap(),
|
votes = persistentMapOf(),
|
||||||
endTime = null
|
endTime = null
|
||||||
),
|
),
|
||||||
).map {
|
).map {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package io.element.android.features.messages.impl.timeline.components.reactionsummary
|
package io.element.android.features.messages.impl.timeline.components.reactionsummary
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
|
@ -38,10 +37,6 @@ class ReactionSummaryPresenter @Inject constructor(
|
||||||
) : Presenter<ReactionSummaryState> {
|
) : Presenter<ReactionSummaryState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): ReactionSummaryState {
|
override fun present(): ReactionSummaryState {
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
room.updateMembers()
|
|
||||||
}
|
|
||||||
|
|
||||||
val membersState by room.membersStateFlow.collectAsState()
|
val membersState by room.membersStateFlow.collectAsState()
|
||||||
|
|
||||||
val target: MutableState<ReactionSummaryState.Summary?> = remember {
|
val target: MutableState<ReactionSummaryState.Summary?> = remember {
|
||||||
|
|
|
||||||
|
|
@ -92,12 +92,14 @@ import io.element.android.tests.testutils.consumeItemsUntilTimeout
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import io.element.android.tests.testutils.waitForPredicate
|
import io.element.android.tests.testutils.waitForPredicate
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
|
@Suppress("LargeClass")
|
||||||
class MessagesPresenterTest {
|
class MessagesPresenterTest {
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
|
|
@ -125,6 +127,21 @@ class MessagesPresenterTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - call is disabled if user cannot join it even if there is an ongoing call`() = runTest {
|
||||||
|
val room = FakeMatrixRoom().apply {
|
||||||
|
givenCanUserJoinCall(Result.success(false))
|
||||||
|
givenRoomInfo(aRoomInfo(hasRoomCall = true))
|
||||||
|
}
|
||||||
|
val presenter = createMessagesPresenter(matrixRoom = room)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = consumeItemsUntilTimeout().last()
|
||||||
|
assertThat(initialState.callState).isEqualTo(RoomCallState.DISABLED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - handle toggling a reaction`() = runTest {
|
fun `present - handle toggling a reaction`() = runTest {
|
||||||
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||||
|
|
@ -462,7 +479,7 @@ class MessagesPresenterTest {
|
||||||
val room = FakeMatrixRoom(sessionId = A_SESSION_ID)
|
val room = FakeMatrixRoom(sessionId = A_SESSION_ID)
|
||||||
room.givenRoomMembersState(
|
room.givenRoomMembersState(
|
||||||
MatrixRoomMembersState.Ready(
|
MatrixRoomMembersState.Ready(
|
||||||
listOf(
|
persistentListOf(
|
||||||
aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN),
|
aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN),
|
||||||
aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE),
|
aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE),
|
||||||
)
|
)
|
||||||
|
|
@ -489,7 +506,7 @@ class MessagesPresenterTest {
|
||||||
room.givenRoomMembersState(
|
room.givenRoomMembersState(
|
||||||
MatrixRoomMembersState.Error(
|
MatrixRoomMembersState.Error(
|
||||||
failure = Throwable(),
|
failure = Throwable(),
|
||||||
prevRoomMembers = listOf(
|
prevRoomMembers = persistentListOf(
|
||||||
aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN),
|
aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN),
|
||||||
aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE),
|
aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE),
|
||||||
)
|
)
|
||||||
|
|
@ -535,7 +552,7 @@ class MessagesPresenterTest {
|
||||||
val room = FakeMatrixRoom(sessionId = A_SESSION_ID)
|
val room = FakeMatrixRoom(sessionId = A_SESSION_ID)
|
||||||
room.givenRoomMembersState(
|
room.givenRoomMembersState(
|
||||||
MatrixRoomMembersState.Ready(
|
MatrixRoomMembersState.Ready(
|
||||||
listOf(
|
persistentListOf(
|
||||||
aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN),
|
aRoomMember(userId = A_SESSION_ID, membership = RoomMembershipState.JOIN),
|
||||||
aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE),
|
aRoomMember(userId = A_SESSION_ID_2, membership = RoomMembershipState.LEAVE),
|
||||||
)
|
)
|
||||||
|
|
@ -655,6 +672,7 @@ class MessagesPresenterTest {
|
||||||
clipboardHelper: FakeClipboardHelper = FakeClipboardHelper(),
|
clipboardHelper: FakeClipboardHelper = FakeClipboardHelper(),
|
||||||
analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
|
analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
|
||||||
permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(),
|
permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(),
|
||||||
|
currentSessionIdHolder: CurrentSessionIdHolder = CurrentSessionIdHolder(FakeMatrixClient(A_SESSION_ID)),
|
||||||
): MessagesPresenter {
|
): MessagesPresenter {
|
||||||
val mediaSender = MediaSender(FakeMediaPreProcessor(), matrixRoom)
|
val mediaSender = MediaSender(FakeMediaPreProcessor(), matrixRoom)
|
||||||
val permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter)
|
val permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter)
|
||||||
|
|
@ -723,6 +741,7 @@ class MessagesPresenterTest {
|
||||||
featureFlagsService = FakeFeatureFlagService(),
|
featureFlagsService = FakeFeatureFlagService(),
|
||||||
buildMeta = aBuildMeta(),
|
buildMeta = aBuildMeta(),
|
||||||
dispatchers = coroutineDispatchers,
|
dispatchers = coroutineDispatchers,
|
||||||
|
currentSessionIdHolder = currentSessionIdHolder,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,11 @@ import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.waitForPredicate
|
import io.element.android.tests.testutils.waitForPredicate
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.advanceUntilIdle
|
import kotlinx.coroutines.test.advanceUntilIdle
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import okhttp3.internal.immutableListOf
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import uniffi.wysiwyg_composer.MentionsState
|
import uniffi.wysiwyg_composer.MentionsState
|
||||||
|
|
@ -734,7 +734,7 @@ class MessageComposerPresenterTest {
|
||||||
isOneToOne = false,
|
isOneToOne = false,
|
||||||
).apply {
|
).apply {
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(
|
givenRoomMembersState(MatrixRoomMembersState.Ready(
|
||||||
immutableListOf(currentUser, invitedUser, bob, david),
|
persistentListOf(currentUser, invitedUser, bob, david),
|
||||||
))
|
))
|
||||||
givenCanTriggerRoomNotification(Result.success(true))
|
givenCanTriggerRoomNotification(Result.success(true))
|
||||||
}
|
}
|
||||||
|
|
@ -798,7 +798,7 @@ class MessageComposerPresenterTest {
|
||||||
isOneToOne = true,
|
isOneToOne = true,
|
||||||
).apply {
|
).apply {
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(
|
givenRoomMembersState(MatrixRoomMembersState.Ready(
|
||||||
immutableListOf(currentUser, invitedUser, bob, david),
|
persistentListOf(currentUser, invitedUser, bob, david),
|
||||||
))
|
))
|
||||||
givenCanTriggerRoomNotification(Result.success(true))
|
givenCanTriggerRoomNotification(Result.success(true))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ import io.element.android.tests.testutils.awaitWithLatch
|
||||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import io.element.android.tests.testutils.waitForPredicate
|
import io.element.android.tests.testutils.waitForPredicate
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -254,18 +255,18 @@ class TimelinePresenterTest {
|
||||||
val (alice, bob, charlie) = aMatrixUserList().take(3).mapIndexed { i, user ->
|
val (alice, bob, charlie) = aMatrixUserList().take(3).mapIndexed { i, user ->
|
||||||
ReactionSender(senderId = user.userId, timestamp = now + i * minuteInMillis)
|
ReactionSender(senderId = user.userId, timestamp = now + i * minuteInMillis)
|
||||||
}
|
}
|
||||||
val oneReaction = listOf(
|
val oneReaction = persistentListOf(
|
||||||
EventReaction(
|
EventReaction(
|
||||||
key = "❤️",
|
key = "❤️",
|
||||||
senders = listOf(alice, charlie)
|
senders = persistentListOf(alice, charlie)
|
||||||
),
|
),
|
||||||
EventReaction(
|
EventReaction(
|
||||||
key = "👍",
|
key = "👍",
|
||||||
senders = listOf(alice, bob)
|
senders = persistentListOf(alice, bob)
|
||||||
),
|
),
|
||||||
EventReaction(
|
EventReaction(
|
||||||
key = "🐶",
|
key = "🐶",
|
||||||
senders = listOf(charlie)
|
senders = persistentListOf(charlie)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
timeline.updateTimelineItems {
|
timeline.updateTimelineItems {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -42,7 +43,7 @@ class ReactionSummaryPresenterTests {
|
||||||
private val roomMember = aRoomMember(userId = A_USER_ID, avatarUrl = AN_AVATAR_URL, displayName = A_USER_NAME)
|
private val roomMember = aRoomMember(userId = A_USER_ID, avatarUrl = AN_AVATAR_URL, displayName = A_USER_NAME)
|
||||||
private val summaryEvent = ReactionSummaryEvents.ShowReactionSummary(AN_EVENT_ID, listOf(aggregatedReaction), aggregatedReaction.key)
|
private val summaryEvent = ReactionSummaryEvents.ShowReactionSummary(AN_EVENT_ID, listOf(aggregatedReaction), aggregatedReaction.key)
|
||||||
private val room = FakeMatrixRoom().apply {
|
private val room = FakeMatrixRoom().apply {
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember)))
|
||||||
}
|
}
|
||||||
private val presenter = ReactionSummaryPresenter(room)
|
private val presenter = ReactionSummaryPresenter(room)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageT
|
||||||
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.ui.components.A_BLUR_HASH
|
import io.element.android.libraries.matrix.ui.components.A_BLUR_HASH
|
||||||
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation
|
import io.element.android.libraries.mediaviewer.api.util.FileExtensionExtractorWithoutValidation
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -280,7 +281,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
),
|
),
|
||||||
details = AudioDetails(
|
details = AudioDetails(
|
||||||
duration = 1.minutes,
|
duration = 1.minutes,
|
||||||
waveform = listOf(1f, 2f),
|
waveform = persistentListOf(1f, 2f),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
@ -293,7 +294,7 @@ class TimelineItemContentMessageFactoryTest {
|
||||||
duration = 1.minutes,
|
duration = 1.minutes,
|
||||||
mediaSource = MediaSource(url = "url", json = null),
|
mediaSource = MediaSource(url = "url", json = null),
|
||||||
mimeType = MimeTypes.Ogg,
|
mimeType = MimeTypes.Ogg,
|
||||||
waveform = listOf(1f, 2f).toImmutableList()
|
waveform = persistentListOf(1f, 2f)
|
||||||
)
|
)
|
||||||
assertThat(result).isEqualTo(expected)
|
assertThat(result).isEqualTo(expected)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,11 @@ import io.element.android.libraries.matrix.test.A_USER_ID_7
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_8
|
import io.element.android.libraries.matrix.test.A_USER_ID_8
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_9
|
import io.element.android.libraries.matrix.test.A_USER_ID_9
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.ImmutableMap
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
|
@ -55,7 +60,7 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest {
|
fun `Disclosed poll - not ended, some votes, including one from current user`() = runTest {
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
Truth.assertThat(
|
Truth.assertThat(
|
||||||
factory.create(aPollContent(votes = votes), eventId = null)
|
factory.create(aPollContent(votes = votes), eventId = null)
|
||||||
)
|
)
|
||||||
|
|
@ -87,7 +92,7 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
fun `Disclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
Truth.assertThat(
|
Truth.assertThat(
|
||||||
factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null)
|
factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null)
|
||||||
)
|
)
|
||||||
|
|
@ -106,7 +111,7 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
fun `Disclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
||||||
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }
|
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
Truth.assertThat(
|
Truth.assertThat(
|
||||||
factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null)
|
factory.create(aPollContent(votes = votes, endTime = 1UL), eventId = null)
|
||||||
)
|
)
|
||||||
|
|
@ -136,7 +141,7 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest {
|
fun `Undisclosed poll - not ended, some votes, including one from current user`() = runTest {
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
Truth.assertThat(
|
Truth.assertThat(
|
||||||
factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes), eventId = null)
|
factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes), eventId = null)
|
||||||
)
|
)
|
||||||
|
|
@ -172,7 +177,7 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
fun `Undisclosed poll - ended, some votes, including one from current user (winner)`() = runTest {
|
||||||
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }
|
val votes = MY_USER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
Truth.assertThat(
|
Truth.assertThat(
|
||||||
factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL), eventId = null)
|
factory.create(aPollContent(pollKind = PollKind.Undisclosed, votes = votes, endTime = 1UL), eventId = null)
|
||||||
)
|
)
|
||||||
|
|
@ -192,7 +197,7 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
fun `Undisclosed poll - ended, some votes, including one from current user (not winner) and two winning votes`() = runTest {
|
||||||
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }
|
val votes = OTHER_WINNING_VOTES.mapKeys { it.key.id }.toImmutableMap()
|
||||||
Truth.assertThat(
|
Truth.assertThat(
|
||||||
factory.create(aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL), eventId = null)
|
factory.create(aPollContent(PollKind.Undisclosed).copy(votes = votes, endTime = 1UL), eventId = null)
|
||||||
)
|
)
|
||||||
|
|
@ -221,13 +226,13 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
|
|
||||||
private fun aPollContent(
|
private fun aPollContent(
|
||||||
pollKind: PollKind = PollKind.Disclosed,
|
pollKind: PollKind = PollKind.Disclosed,
|
||||||
votes: Map<String, List<UserId>> = emptyMap(),
|
votes: ImmutableMap<String, ImmutableList<UserId>> = persistentMapOf(),
|
||||||
endTime: ULong? = null,
|
endTime: ULong? = null,
|
||||||
): PollContent = PollContent(
|
): PollContent = PollContent(
|
||||||
question = A_POLL_QUESTION,
|
question = A_POLL_QUESTION,
|
||||||
kind = pollKind,
|
kind = pollKind,
|
||||||
maxSelections = 1UL,
|
maxSelections = 1UL,
|
||||||
answers = listOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4),
|
answers = persistentListOf(A_POLL_ANSWER_1, A_POLL_ANSWER_2, A_POLL_ANSWER_3, A_POLL_ANSWER_4),
|
||||||
votes = votes,
|
votes = votes,
|
||||||
endTime = endTime,
|
endTime = endTime,
|
||||||
)
|
)
|
||||||
|
|
@ -275,17 +280,17 @@ internal class TimelineItemContentPollFactoryTest {
|
||||||
private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries")
|
private val A_POLL_ANSWER_3 = PollAnswer("id_3", "French Fries")
|
||||||
private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger")
|
private val A_POLL_ANSWER_4 = PollAnswer("id_4", "Hamburger")
|
||||||
|
|
||||||
private val MY_USER_WINNING_VOTES = mapOf(
|
private val MY_USER_WINNING_VOTES = persistentMapOf(
|
||||||
A_POLL_ANSWER_1 to listOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4),
|
A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4),
|
||||||
A_POLL_ANSWER_2 to listOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner
|
A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_5, A_USER_ID_6, A_USER_ID_7, A_USER_ID_8, A_USER_ID_9), // winner
|
||||||
A_POLL_ANSWER_3 to emptyList(),
|
A_POLL_ANSWER_3 to persistentListOf(),
|
||||||
A_POLL_ANSWER_4 to listOf(A_USER_ID_10),
|
A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_10),
|
||||||
)
|
)
|
||||||
private val OTHER_WINNING_VOTES = mapOf(
|
private val OTHER_WINNING_VOTES = persistentMapOf(
|
||||||
A_POLL_ANSWER_1 to listOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner
|
A_POLL_ANSWER_1 to persistentListOf(A_USER_ID_2, A_USER_ID_3, A_USER_ID_4, A_USER_ID_5), // winner
|
||||||
A_POLL_ANSWER_2 to listOf(A_USER_ID /* my vote */, A_USER_ID_6),
|
A_POLL_ANSWER_2 to persistentListOf(A_USER_ID /* my vote */, A_USER_ID_6),
|
||||||
A_POLL_ANSWER_3 to emptyList(),
|
A_POLL_ANSWER_3 to persistentListOf(),
|
||||||
A_POLL_ANSWER_4 to listOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner
|
A_POLL_ANSWER_4 to persistentListOf(A_USER_ID_7, A_USER_ID_8, A_USER_ID_9, A_USER_ID_10), // winner
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
||||||
import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer
|
import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -88,8 +89,8 @@ fun aRedactedMatrixTimeline(eventId: EventId) = listOf<MatrixTimelineItem>(
|
||||||
isOwn = false,
|
isOwn = false,
|
||||||
isRemote = false,
|
isRemote = false,
|
||||||
localSendState = null,
|
localSendState = null,
|
||||||
reactions = listOf(),
|
reactions = persistentListOf(),
|
||||||
receipts = listOf(),
|
receipts = persistentListOf(),
|
||||||
sender = A_USER_ID,
|
sender = A_USER_ID,
|
||||||
senderProfile = ProfileTimelineDetails.Unavailable,
|
senderProfile = ProfileTimelineDetails.Unavailable,
|
||||||
timestamp = 9442,
|
timestamp = 9442,
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import io.element.android.libraries.matrix.test.room.anEventTimelineItem
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -539,7 +540,7 @@ class CreatePollPresenterTest {
|
||||||
|
|
||||||
private fun anExistingPoll() = aPollContent(
|
private fun anExistingPoll() = aPollContent(
|
||||||
question = "Do you like polls?",
|
question = "Do you like polls?",
|
||||||
answers = listOf(
|
answers = persistentListOf(
|
||||||
PollAnswer("1", "Yes"),
|
PollAnswer("1", "Yes"),
|
||||||
PollAnswer("2", "No"),
|
PollAnswer("2", "No"),
|
||||||
PollAnswer("2", "Maybe"),
|
PollAnswer("2", "Maybe"),
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
|
|
@ -84,7 +85,7 @@ class EditDefaultNotificationSettingPresenter @AssistedInject constructor(
|
||||||
return EditDefaultNotificationSettingState(
|
return EditDefaultNotificationSettingState(
|
||||||
isOneToOne = isOneToOne,
|
isOneToOne = isOneToOne,
|
||||||
mode = mode.value,
|
mode = mode.value,
|
||||||
roomsWithUserDefinedMode = roomsWithUserDefinedMode.value,
|
roomsWithUserDefinedMode = roomsWithUserDefinedMode.value.toImmutableList(),
|
||||||
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,12 @@ package io.element.android.features.preferences.impl.notifications.edit
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
data class EditDefaultNotificationSettingState(
|
data class EditDefaultNotificationSettingState(
|
||||||
val isOneToOne: Boolean,
|
val isOneToOne: Boolean,
|
||||||
val mode: RoomNotificationMode?,
|
val mode: RoomNotificationMode?,
|
||||||
val roomsWithUserDefinedMode: List<RoomSummary.Filled>,
|
val roomsWithUserDefinedMode: ImmutableList<RoomSummary.Filled>,
|
||||||
val changeNotificationSettingAction: Async<Unit>,
|
val changeNotificationSettingAction: Async<Unit>,
|
||||||
val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit,
|
val eventSink: (EditDefaultNotificationSettingStateEvents) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummaryDetails
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
open class EditDefaultNotificationSettingStateProvider: PreviewParameterProvider<EditDefaultNotificationSettingState> {
|
open class EditDefaultNotificationSettingStateProvider: PreviewParameterProvider<EditDefaultNotificationSettingState> {
|
||||||
override val values: Sequence<EditDefaultNotificationSettingState>
|
override val values: Sequence<EditDefaultNotificationSettingState>
|
||||||
|
|
@ -39,7 +40,7 @@ private fun anEditDefaultNotificationSettingsState(
|
||||||
) = EditDefaultNotificationSettingState(
|
) = EditDefaultNotificationSettingState(
|
||||||
isOneToOne = isOneToOne,
|
isOneToOne = isOneToOne,
|
||||||
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
||||||
roomsWithUserDefinedMode = listOf(aRoomSummary()),
|
roomsWithUserDefinedMode = persistentListOf(aRoomSummary()),
|
||||||
changeNotificationSettingAction = changeNotificationSettingAction,
|
changeNotificationSettingAction = changeNotificationSettingAction,
|
||||||
eventSink = {}
|
eventSink = {}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ fun aRoomMember(
|
||||||
isIgnored = isIgnored,
|
isIgnored = isIgnored,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aRoomMemberList() = listOf(
|
fun aRoomMemberList() = persistentListOf(
|
||||||
anAlice(),
|
anAlice(),
|
||||||
aBob(),
|
aBob(),
|
||||||
aRoomMember(UserId("@carol:server.org"), "Carol"),
|
aRoomMember(UserId("@carol:server.org"), "Carol"),
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
|
@ -129,7 +130,7 @@ class RoomDetailsPresenterTests {
|
||||||
isEncrypted = true,
|
isEncrypted = true,
|
||||||
isDirect = true,
|
isDirect = true,
|
||||||
).apply {
|
).apply {
|
||||||
val roomMembers = listOf(myRoomMember, otherRoomMember)
|
val roomMembers = persistentListOf(myRoomMember, otherRoomMember)
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers))
|
||||||
}
|
}
|
||||||
val presenter = createRoomDetailsPresenter(room)
|
val presenter = createRoomDetailsPresenter(room)
|
||||||
|
|
@ -220,7 +221,7 @@ class RoomDetailsPresenterTests {
|
||||||
isEncrypted = true,
|
isEncrypted = true,
|
||||||
isDirect = true,
|
isDirect = true,
|
||||||
).apply {
|
).apply {
|
||||||
val roomMembers = listOf(myRoomMember, otherRoomMember)
|
val roomMembers = persistentListOf(myRoomMember, otherRoomMember)
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers))
|
||||||
|
|
||||||
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true))
|
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true))
|
||||||
|
|
@ -253,7 +254,7 @@ class RoomDetailsPresenterTests {
|
||||||
isDirect = true,
|
isDirect = true,
|
||||||
topic = null,
|
topic = null,
|
||||||
).apply {
|
).apply {
|
||||||
val roomMembers = listOf(myRoomMember, otherRoomMember)
|
val roomMembers = persistentListOf(myRoomMember, otherRoomMember)
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(roomMembers))
|
||||||
|
|
||||||
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true))
|
givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.success(true))
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import io.element.android.libraries.usersearch.test.FakeUserRepository
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -167,7 +168,7 @@ internal class RoomInviteMembersPresenterTest {
|
||||||
matrixRoom = FakeMatrixRoom().apply {
|
matrixRoom = FakeMatrixRoom().apply {
|
||||||
givenRoomMembersState(
|
givenRoomMembersState(
|
||||||
MatrixRoomMembersState.Ready(
|
MatrixRoomMembersState.Ready(
|
||||||
listOf(
|
persistentListOf(
|
||||||
aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN),
|
aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN),
|
||||||
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE),
|
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE),
|
||||||
)
|
)
|
||||||
|
|
@ -227,7 +228,7 @@ internal class RoomInviteMembersPresenterTest {
|
||||||
roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply {
|
roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply {
|
||||||
givenRoomMembersState(
|
givenRoomMembersState(
|
||||||
MatrixRoomMembersState.Ready(
|
MatrixRoomMembersState.Ready(
|
||||||
listOf(
|
persistentListOf(
|
||||||
aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN),
|
aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN),
|
||||||
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE),
|
aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -56,7 +57,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
val room = aMatrixRoom().apply {
|
val room = aMatrixRoom().apply {
|
||||||
givenUserDisplayNameResult(Result.success("A custom name"))
|
givenUserDisplayNameResult(Result.success("A custom name"))
|
||||||
givenUserAvatarUrlResult(Result.success("A custom avatar"))
|
givenUserAvatarUrlResult(Result.success("A custom avatar"))
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember)))
|
||||||
}
|
}
|
||||||
val presenter = createRoomMemberDetailsPresenter(
|
val presenter = createRoomMemberDetailsPresenter(
|
||||||
room = room,
|
room = room,
|
||||||
|
|
@ -83,7 +84,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
val room = aMatrixRoom().apply {
|
val room = aMatrixRoom().apply {
|
||||||
givenUserDisplayNameResult(Result.failure(Throwable()))
|
givenUserDisplayNameResult(Result.failure(Throwable()))
|
||||||
givenUserAvatarUrlResult(Result.failure(Throwable()))
|
givenUserAvatarUrlResult(Result.failure(Throwable()))
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember)))
|
||||||
}
|
}
|
||||||
val presenter = createRoomMemberDetailsPresenter(
|
val presenter = createRoomMemberDetailsPresenter(
|
||||||
room = room,
|
room = room,
|
||||||
|
|
@ -106,7 +107,7 @@ class RoomMemberDetailsPresenterTests {
|
||||||
val room = aMatrixRoom().apply {
|
val room = aMatrixRoom().apply {
|
||||||
givenUserDisplayNameResult(Result.success(null))
|
givenUserDisplayNameResult(Result.success(null))
|
||||||
givenUserAvatarUrlResult(Result.success(null))
|
givenUserAvatarUrlResult(Result.success(null))
|
||||||
givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember)))
|
givenRoomMembersState(MatrixRoomMembersState.Ready(persistentListOf(roomMember)))
|
||||||
}
|
}
|
||||||
val presenter = createRoomMemberDetailsPresenter(
|
val presenter = createRoomMemberDetailsPresenter(
|
||||||
room = room,
|
room = room,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class RoomListRoomSummary constructor(
|
data class RoomListRoomSummary(
|
||||||
val id: String,
|
val id: String,
|
||||||
val roomId: RoomId,
|
val roomId: RoomId,
|
||||||
val name: String = "",
|
val name: String = "",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
||||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
|
|
@ -132,7 +133,7 @@ class VerifySelfSessionPresenterTests {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
requestVerificationAndAwaitVerifyingState(service)
|
requestVerificationAndAwaitVerifyingState(service)
|
||||||
service.givenVerificationFlowState(VerificationFlowState.ReceivedVerificationData(emptyList()))
|
service.givenVerificationFlowState(VerificationFlowState.ReceivedVerificationData(persistentListOf()))
|
||||||
ensureAllEventsConsumed()
|
ensureAllEventsConsumed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ serialization_json = "1.6.1"
|
||||||
showkase = "1.0.2"
|
showkase = "1.0.2"
|
||||||
appyx = "1.4.0"
|
appyx = "1.4.0"
|
||||||
sqldelight = "2.0.0"
|
sqldelight = "2.0.0"
|
||||||
wysiwyg = "2.19.0"
|
wysiwyg = "2.20.0"
|
||||||
|
|
||||||
# DI
|
# DI
|
||||||
dagger = "2.48.1"
|
dagger = "2.48.1"
|
||||||
|
|
@ -89,7 +89,7 @@ androidx_preference = "androidx.preference:preference:1.2.1"
|
||||||
androidx_webkit = "androidx.webkit:webkit:1.8.0"
|
androidx_webkit = "androidx.webkit:webkit:1.8.0"
|
||||||
|
|
||||||
androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" }
|
androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" }
|
||||||
androidx_compose_material3 = "androidx.compose.material3:material3:1.2.0-alpha11"
|
androidx_compose_material3 = "androidx.compose.material3:material3:1.2.0-alpha12"
|
||||||
androidx_compose_ui = { module = "androidx.compose.ui:ui" }
|
androidx_compose_ui = { module = "androidx.compose.ui:ui" }
|
||||||
androidx_compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" }
|
androidx_compose_ui_tooling = { module = "androidx.compose.ui:ui-tooling" }
|
||||||
androidx_compose_ui_tooling_preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
androidx_compose_ui_tooling_preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||||
|
|
@ -147,7 +147,7 @@ jsoup = "org.jsoup:jsoup:1.17.1"
|
||||||
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
||||||
molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.1"
|
molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.1"
|
||||||
timber = "com.jakewharton.timber:timber:5.0.1"
|
timber = "com.jakewharton.timber:timber:5.0.1"
|
||||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.71"
|
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.72"
|
||||||
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
||||||
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
||||||
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||||
|
|
|
||||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=f2b9ed0faf8472cbe469255ae6c86eddb77076c75191741b4a462f33128dd419
|
distributionSha256Sum=c16d517b50dd28b3f5838f0e844b7520b8f1eb610f2f29de7e4e04a1b7c9c79b
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.encryption
|
package io.element.android.libraries.matrix.api.encryption
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface BackupUploadState {
|
sealed interface BackupUploadState {
|
||||||
data object Unknown : BackupUploadState
|
data object Unknown : BackupUploadState
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.encryption
|
package io.element.android.libraries.matrix.api.encryption
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface SteadyStateException {
|
sealed interface SteadyStateException {
|
||||||
/**
|
/**
|
||||||
* The backup can be deleted.
|
* The backup can be deleted.
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.media
|
package io.element.android.libraries.matrix.api.media
|
||||||
|
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
|
|
||||||
data class AudioDetails(
|
data class AudioDetails(
|
||||||
val duration: Duration,
|
val duration: Duration,
|
||||||
val waveform: List<Float>,
|
val waveform: ImmutableList<Float>,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,21 @@
|
||||||
package io.element.android.libraries.matrix.api.permalink
|
package io.element.android.libraries.matrix.api.permalink
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This sealed class represents all the permalink cases.
|
* This sealed class represents all the permalink cases.
|
||||||
* You don't have to instantiate yourself but should use [PermalinkParser] instead.
|
* You don't have to instantiate yourself but should use [PermalinkParser] instead.
|
||||||
*/
|
*/
|
||||||
|
@Immutable
|
||||||
sealed interface PermalinkData {
|
sealed interface PermalinkData {
|
||||||
|
|
||||||
data class RoomLink(
|
data class RoomLink(
|
||||||
val roomIdOrAlias: String,
|
val roomIdOrAlias: String,
|
||||||
val isRoomAlias: Boolean,
|
val isRoomAlias: Boolean,
|
||||||
val eventId: String?,
|
val eventId: String?,
|
||||||
val viaParameters: List<String>
|
val viaParameters: ImmutableList<String>
|
||||||
) : PermalinkData
|
) : PermalinkData
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.element.android.libraries.matrix.api.permalink
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.net.UrlQuerySanitizer
|
import android.net.UrlQuerySanitizer
|
||||||
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.net.URLDecoder
|
import java.net.URLDecoder
|
||||||
|
|
||||||
|
|
@ -80,7 +81,7 @@ object PermalinkParser {
|
||||||
roomIdOrAlias = decodedIdentifier,
|
roomIdOrAlias = decodedIdentifier,
|
||||||
isRoomAlias = true,
|
isRoomAlias = true,
|
||||||
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
||||||
viaParameters = viaQueryParameters
|
viaParameters = viaQueryParameters.toImmutableList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
|
else -> PermalinkData.FallbackLink(uri, MatrixPatterns.isGroupId(identifier))
|
||||||
|
|
@ -119,7 +120,7 @@ object PermalinkParser {
|
||||||
roomIdOrAlias = identifier,
|
roomIdOrAlias = identifier,
|
||||||
isRoomAlias = false,
|
isRoomAlias = false,
|
||||||
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) },
|
||||||
viaParameters = viaQueryParameters
|
viaParameters = viaQueryParameters.toImmutableList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,8 @@ interface MatrixRoom : Closeable {
|
||||||
|
|
||||||
suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean>
|
suspend fun canUserTriggerRoomNotification(userId: UserId): Result<Boolean>
|
||||||
|
|
||||||
|
suspend fun canUserJoinCall(userId: UserId): Result<Boolean>
|
||||||
|
|
||||||
suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit>
|
suspend fun updateAvatar(mimeType: String, data: ByteArray): Result<Unit>
|
||||||
|
|
||||||
suspend fun removeAvatar(): Result<Unit>
|
suspend fun removeAvatar(): Result<Unit>
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,11 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.room
|
package io.element.android.libraries.matrix.api.room
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
@Immutable
|
||||||
data class MatrixRoomInfo(
|
data class MatrixRoomInfo(
|
||||||
val id: String,
|
val id: String,
|
||||||
val name: String?,
|
val name: String?,
|
||||||
|
|
@ -28,7 +31,7 @@ data class MatrixRoomInfo(
|
||||||
val isSpace: Boolean,
|
val isSpace: Boolean,
|
||||||
val isTombstoned: Boolean,
|
val isTombstoned: Boolean,
|
||||||
val canonicalAlias: String?,
|
val canonicalAlias: String?,
|
||||||
val alternativeAliases: List<String>,
|
val alternativeAliases: ImmutableList<String>,
|
||||||
val currentUserMembership: CurrentUserMembership,
|
val currentUserMembership: CurrentUserMembership,
|
||||||
val latestEvent: EventTimelineItem?,
|
val latestEvent: EventTimelineItem?,
|
||||||
val inviter: RoomMember?,
|
val inviter: RoomMember?,
|
||||||
|
|
@ -39,5 +42,5 @@ data class MatrixRoomInfo(
|
||||||
val notificationCount: Long,
|
val notificationCount: Long,
|
||||||
val userDefinedNotificationMode: RoomNotificationMode?,
|
val userDefinedNotificationMode: RoomNotificationMode?,
|
||||||
val hasRoomCall: Boolean,
|
val hasRoomCall: Boolean,
|
||||||
val activeRoomCallParticipants: List<String>
|
val activeRoomCallParticipants: ImmutableList<String>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,14 @@
|
||||||
package io.element.android.libraries.matrix.api.room
|
package io.element.android.libraries.matrix.api.room
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
sealed interface MatrixRoomMembersState {
|
sealed interface MatrixRoomMembersState {
|
||||||
data object Unknown : MatrixRoomMembersState
|
data object Unknown : MatrixRoomMembersState
|
||||||
data class Pending(val prevRoomMembers: List<RoomMember>? = null) : MatrixRoomMembersState
|
data class Pending(val prevRoomMembers: ImmutableList<RoomMember>? = null) : MatrixRoomMembersState
|
||||||
data class Error(val failure: Throwable, val prevRoomMembers: List<RoomMember>? = null) : MatrixRoomMembersState
|
data class Error(val failure: Throwable, val prevRoomMembers: ImmutableList<RoomMember>? = null) : MatrixRoomMembersState
|
||||||
data class Ready(val roomMembers: List<RoomMember>) : MatrixRoomMembersState
|
data class Ready(val roomMembers: ImmutableList<RoomMember>) : MatrixRoomMembersState
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MatrixRoomMembersState.roomMembers(): List<RoomMember>? {
|
fun MatrixRoomMembersState.roomMembers(): List<RoomMember>? {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.roomlist
|
package io.element.android.libraries.matrix.api.roomlist
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -25,6 +26,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||||
*/
|
*/
|
||||||
interface RoomListService {
|
interface RoomListService {
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface State {
|
sealed interface State {
|
||||||
data object Idle : State
|
data object Idle : State
|
||||||
data object Running : State
|
data object Running : State
|
||||||
|
|
@ -32,6 +34,7 @@ interface RoomListService {
|
||||||
data object Terminated : State
|
data object Terminated : State
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface SyncIndicator {
|
sealed interface SyncIndicator {
|
||||||
data object Show : SyncIndicator
|
data object Show : SyncIndicator
|
||||||
data object Hide : SyncIndicator
|
data object Hide : SyncIndicator
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,15 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.media.ImageInfo
|
import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||||
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
||||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.ImmutableMap
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface EventContent
|
sealed interface EventContent
|
||||||
|
|
||||||
data class MessageContent(
|
data class MessageContent(
|
||||||
|
|
@ -43,14 +47,16 @@ data class PollContent(
|
||||||
val question: String,
|
val question: String,
|
||||||
val kind: PollKind,
|
val kind: PollKind,
|
||||||
val maxSelections: ULong,
|
val maxSelections: ULong,
|
||||||
val answers: List<PollAnswer>,
|
val answers: ImmutableList<PollAnswer>,
|
||||||
val votes: Map<String, List<UserId>>,
|
val votes: ImmutableMap<String, ImmutableList<UserId>>,
|
||||||
val endTime: ULong?
|
val endTime: ULong?
|
||||||
) : EventContent
|
) : EventContent
|
||||||
|
|
||||||
data class UnableToDecryptContent(
|
data class UnableToDecryptContent(
|
||||||
val data: Data
|
val data: Data
|
||||||
) : EventContent {
|
) : EventContent {
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface Data {
|
sealed interface Data {
|
||||||
data class OlmV1Curve25519AesSha2(
|
data class OlmV1Curve25519AesSha2(
|
||||||
val senderKey: String
|
val senderKey: String
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
|
@Immutable
|
||||||
data class EventReaction(
|
data class EventReaction(
|
||||||
val key: String,
|
val key: String,
|
||||||
val senders: List<ReactionSender>
|
val senders: ImmutableList<ReactionSender>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.TransactionId
|
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.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
data class EventTimelineItem(
|
data class EventTimelineItem(
|
||||||
val eventId: EventId?,
|
val eventId: EventId?,
|
||||||
|
|
@ -29,8 +30,8 @@ data class EventTimelineItem(
|
||||||
val isOwn: Boolean,
|
val isOwn: Boolean,
|
||||||
val isRemote: Boolean,
|
val isRemote: Boolean,
|
||||||
val localSendState: LocalEventSendState?,
|
val localSendState: LocalEventSendState?,
|
||||||
val reactions: List<EventReaction>,
|
val reactions: ImmutableList<EventReaction>,
|
||||||
val receipts: List<Receipt>,
|
val receipts: ImmutableList<Receipt>,
|
||||||
val sender: UserId,
|
val sender: UserId,
|
||||||
val senderProfile: ProfileTimelineDetails,
|
val senderProfile: ProfileTimelineDetails,
|
||||||
val timestamp: Long,
|
val timestamp: Long,
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,11 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface InReplyTo {
|
sealed interface InReplyTo {
|
||||||
/** The event details are not loaded yet. We can fetch them. */
|
/** The event details are not loaded yet. We can fetch them. */
|
||||||
data class NotLoaded(val eventId: EventId) : InReplyTo
|
data class NotLoaded(val eventId: EventId) : InReplyTo
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface LocalEventSendState {
|
sealed interface LocalEventSendState {
|
||||||
data object NotSentYet : LocalEventSendState
|
data object NotSentYet : LocalEventSendState
|
||||||
data object Canceled : LocalEventSendState
|
data object Canceled : LocalEventSendState
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.matrix.api.media.AudioDetails
|
import io.element.android.libraries.matrix.api.media.AudioDetails
|
||||||
import io.element.android.libraries.matrix.api.media.AudioInfo
|
import io.element.android.libraries.matrix.api.media.AudioInfo
|
||||||
import io.element.android.libraries.matrix.api.media.FileInfo
|
import io.element.android.libraries.matrix.api.media.FileInfo
|
||||||
|
|
@ -23,6 +24,7 @@ import io.element.android.libraries.matrix.api.media.ImageInfo
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.api.media.VideoInfo
|
import io.element.android.libraries.matrix.api.media.VideoInfo
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface MessageType
|
sealed interface MessageType
|
||||||
|
|
||||||
data class EmoteMessageType(
|
data class EmoteMessageType(
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface OtherState {
|
sealed interface OtherState {
|
||||||
data object PolicyRuleRoom : OtherState
|
data object PolicyRuleRoom : OtherState
|
||||||
data object PolicyRuleServer : OtherState
|
data object PolicyRuleServer : OtherState
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.timeline.item.event
|
package io.element.android.libraries.matrix.api.timeline.item.event
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
|
||||||
|
@Immutable
|
||||||
sealed interface ProfileTimelineDetails {
|
sealed interface ProfileTimelineDetails {
|
||||||
data object Unavailable : ProfileTimelineDetails
|
data object Unavailable : ProfileTimelineDetails
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.user
|
package io.element.android.libraries.matrix.api.user
|
||||||
|
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
data class MatrixSearchUserResults(
|
data class MatrixSearchUserResults(
|
||||||
val results: List<MatrixUser>,
|
val results: ImmutableList<MatrixUser>,
|
||||||
val limited: Boolean,
|
val limited: Boolean,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.api.verification
|
package io.element.android.libraries.matrix.api.verification
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
|
@ -75,6 +77,7 @@ interface SessionVerificationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Verification status of the current session. */
|
/** Verification status of the current session. */
|
||||||
|
@Immutable
|
||||||
sealed interface SessionVerifiedStatus {
|
sealed interface SessionVerifiedStatus {
|
||||||
/** Unknown status, we couldn't read the actual value from the SDK. */
|
/** Unknown status, we couldn't read the actual value from the SDK. */
|
||||||
data object Unknown : SessionVerifiedStatus
|
data object Unknown : SessionVerifiedStatus
|
||||||
|
|
@ -87,6 +90,7 @@ sealed interface SessionVerifiedStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** States produced by the [SessionVerificationService]. */
|
/** States produced by the [SessionVerificationService]. */
|
||||||
|
@Immutable
|
||||||
sealed interface VerificationFlowState {
|
sealed interface VerificationFlowState {
|
||||||
/** Initial state. */
|
/** Initial state. */
|
||||||
data object Initial : VerificationFlowState
|
data object Initial : VerificationFlowState
|
||||||
|
|
@ -98,7 +102,7 @@ sealed interface VerificationFlowState {
|
||||||
data object StartedSasVerification : VerificationFlowState
|
data object StartedSasVerification : VerificationFlowState
|
||||||
|
|
||||||
/** Verification data for the SAS verification (emojis) received. */
|
/** Verification data for the SAS verification (emojis) received. */
|
||||||
data class ReceivedVerificationData(val emoji: List<VerificationEmoji>) : VerificationFlowState
|
data class ReceivedVerificationData(val emoji: ImmutableList<VerificationEmoji>) : VerificationFlowState
|
||||||
|
|
||||||
/** Verification completed successfully. */
|
/** Verification completed successfully. */
|
||||||
data object Finished : VerificationFlowState
|
data object Finished : VerificationFlowState
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package io.element.android.libraries.matrix.api.permalink
|
package io.element.android.libraries.matrix.api.permalink
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.RobolectricTestRunner
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
|
@ -66,7 +67,7 @@ class PermalinkParserTest {
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomIdOrAlias = "!aBCD1234:matrix.org",
|
||||||
isRoomAlias = false,
|
isRoomAlias = false,
|
||||||
eventId = null,
|
eventId = null,
|
||||||
viaParameters = emptyList(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -79,7 +80,7 @@ class PermalinkParserTest {
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomIdOrAlias = "!aBCD1234:matrix.org",
|
||||||
isRoomAlias = false,
|
isRoomAlias = false,
|
||||||
eventId = "\$1234567890abcdef:matrix.org",
|
eventId = "\$1234567890abcdef:matrix.org",
|
||||||
viaParameters = emptyList(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +93,7 @@ class PermalinkParserTest {
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomIdOrAlias = "!aBCD1234:matrix.org",
|
||||||
isRoomAlias = false,
|
isRoomAlias = false,
|
||||||
eventId = null,
|
eventId = null,
|
||||||
viaParameters = emptyList(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +106,7 @@ class PermalinkParserTest {
|
||||||
roomIdOrAlias = "!aBCD1234:matrix.org",
|
roomIdOrAlias = "!aBCD1234:matrix.org",
|
||||||
isRoomAlias = false,
|
isRoomAlias = false,
|
||||||
eventId = "\$1234567890abcdef:matrix.org",
|
eventId = "\$1234567890abcdef:matrix.org",
|
||||||
viaParameters = listOf("matrix.org", "matrix.com"),
|
viaParameters = persistentListOf("matrix.org", "matrix.com"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -118,7 +119,7 @@ class PermalinkParserTest {
|
||||||
roomIdOrAlias = "#element-android:matrix.org",
|
roomIdOrAlias = "#element-android:matrix.org",
|
||||||
isRoomAlias = true,
|
isRoomAlias = true,
|
||||||
eventId = null,
|
eventId = null,
|
||||||
viaParameters = emptyList(),
|
viaParameters = persistentListOf(),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ dependencies {
|
||||||
implementation("net.java.dev.jna:jna:5.13.0@aar")
|
implementation("net.java.dev.jna:jna:5.13.0@aar")
|
||||||
implementation(libs.androidx.datastore.preferences)
|
implementation(libs.androidx.datastore.preferences)
|
||||||
implementation(libs.serialization.json)
|
implementation(libs.serialization.json)
|
||||||
|
implementation(libs.kotlinx.collections.immutable)
|
||||||
|
|
||||||
testImplementation(libs.test.junit)
|
testImplementation(libs.test.junit)
|
||||||
testImplementation(libs.test.truth)
|
testImplementation(libs.test.truth)
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ import org.matrix.rustcomponents.sdk.BackupState
|
||||||
import org.matrix.rustcomponents.sdk.Client
|
import org.matrix.rustcomponents.sdk.Client
|
||||||
import org.matrix.rustcomponents.sdk.ClientDelegate
|
import org.matrix.rustcomponents.sdk.ClientDelegate
|
||||||
import org.matrix.rustcomponents.sdk.NotificationProcessSetup
|
import org.matrix.rustcomponents.sdk.NotificationProcessSetup
|
||||||
|
import org.matrix.rustcomponents.sdk.PowerLevels
|
||||||
import org.matrix.rustcomponents.sdk.Room
|
import org.matrix.rustcomponents.sdk.Room
|
||||||
import org.matrix.rustcomponents.sdk.RoomListItem
|
import org.matrix.rustcomponents.sdk.RoomListItem
|
||||||
import org.matrix.rustcomponents.sdk.TaskHandle
|
import org.matrix.rustcomponents.sdk.TaskHandle
|
||||||
|
|
@ -274,6 +275,7 @@ class RustMatrixClient constructor(
|
||||||
},
|
},
|
||||||
invite = createRoomParams.invite?.map { it.value },
|
invite = createRoomParams.invite?.map { it.value },
|
||||||
avatar = createRoomParams.avatar,
|
avatar = createRoomParams.avatar,
|
||||||
|
powerLevelContentOverride = defaultRoomCreationPowerLevels,
|
||||||
)
|
)
|
||||||
val roomId = RoomId(client.createRoom(rustParams))
|
val roomId = RoomId(client.createRoom(rustParams))
|
||||||
|
|
||||||
|
|
@ -296,7 +298,7 @@ class RustMatrixClient constructor(
|
||||||
isDirect = true,
|
isDirect = true,
|
||||||
visibility = RoomVisibility.PRIVATE,
|
visibility = RoomVisibility.PRIVATE,
|
||||||
preset = RoomPreset.TRUSTED_PRIVATE_CHAT,
|
preset = RoomPreset.TRUSTED_PRIVATE_CHAT,
|
||||||
invite = listOf(userId)
|
invite = listOf(userId),
|
||||||
)
|
)
|
||||||
return createRoom(createRoomParams)
|
return createRoom(createRoomParams)
|
||||||
}
|
}
|
||||||
|
|
@ -481,3 +483,18 @@ class RustMatrixClient constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val defaultRoomCreationPowerLevels = PowerLevels(
|
||||||
|
usersDefault = null,
|
||||||
|
eventsDefault = null,
|
||||||
|
stateDefault = null,
|
||||||
|
ban = null,
|
||||||
|
kick = null,
|
||||||
|
redact = null,
|
||||||
|
invite = null,
|
||||||
|
notifications = null,
|
||||||
|
users = mapOf(),
|
||||||
|
events = mapOf(
|
||||||
|
"m.call.member" to 0,
|
||||||
|
"org.matrix.msc3401.call.member" to 0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,14 @@
|
||||||
package io.element.android.libraries.matrix.impl.media
|
package io.element.android.libraries.matrix.impl.media
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.media.AudioDetails
|
import io.element.android.libraries.matrix.api.media.AudioDetails
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlin.time.toJavaDuration
|
import kotlin.time.toJavaDuration
|
||||||
import kotlin.time.toKotlinDuration
|
import kotlin.time.toKotlinDuration
|
||||||
import org.matrix.rustcomponents.sdk.UnstableAudioDetailsContent as RustAudioDetails
|
import org.matrix.rustcomponents.sdk.UnstableAudioDetailsContent as RustAudioDetails
|
||||||
|
|
||||||
fun RustAudioDetails.map(): AudioDetails = AudioDetails(
|
fun RustAudioDetails.map(): AudioDetails = AudioDetails(
|
||||||
duration = duration.toKotlinDuration(),
|
duration = duration.toKotlinDuration(),
|
||||||
waveform = waveform.fromMSC3246range(),
|
waveform = waveform.fromMSC3246range().toImmutableList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
fun AudioDetails.map(): RustAudioDetails = RustAudioDetails(
|
fun AudioDetails.map(): RustAudioDetails = RustAudioDetails(
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
|
import io.element.android.libraries.matrix.impl.timeline.item.event.EventTimelineItemMapper
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
import org.matrix.rustcomponents.sdk.Membership as RustMembership
|
import org.matrix.rustcomponents.sdk.Membership as RustMembership
|
||||||
import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo
|
import org.matrix.rustcomponents.sdk.RoomInfo as RustRoomInfo
|
||||||
|
|
@ -40,7 +41,7 @@ class MatrixRoomInfoMapper(
|
||||||
isSpace = it.isSpace,
|
isSpace = it.isSpace,
|
||||||
isTombstoned = it.isTombstoned,
|
isTombstoned = it.isTombstoned,
|
||||||
canonicalAlias = it.canonicalAlias,
|
canonicalAlias = it.canonicalAlias,
|
||||||
alternativeAliases = it.alternativeAliases,
|
alternativeAliases = it.alternativeAliases.toImmutableList(),
|
||||||
currentUserMembership = it.membership.map(),
|
currentUserMembership = it.membership.map(),
|
||||||
latestEvent = it.latestEvent?.use (timelineItemMapper::map),
|
latestEvent = it.latestEvent?.use (timelineItemMapper::map),
|
||||||
inviter = it.inviter?.use(RoomMemberMapper::map),
|
inviter = it.inviter?.use(RoomMemberMapper::map),
|
||||||
|
|
@ -51,7 +52,7 @@ class MatrixRoomInfoMapper(
|
||||||
notificationCount = it.notificationCount.toLong(),
|
notificationCount = it.notificationCount.toLong(),
|
||||||
userDefinedNotificationMode = it.userDefinedNotificationMode?.map(),
|
userDefinedNotificationMode = it.userDefinedNotificationMode?.map(),
|
||||||
hasRoomCall = it.hasRoomCall,
|
hasRoomCall = it.hasRoomCall,
|
||||||
activeRoomCallParticipants = it.activeRoomCallParticipants
|
activeRoomCallParticipants = it.activeRoomCallParticipants.toImmutableList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ import io.element.android.libraries.matrix.impl.widget.RustWidgetDriver
|
||||||
import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl
|
import io.element.android.libraries.matrix.impl.widget.generateWidgetWebViewUrl
|
||||||
import io.element.android.libraries.sessionstorage.api.SessionData
|
import io.element.android.libraries.sessionstorage.api.SessionData
|
||||||
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
import io.element.android.services.toolbox.api.systemclock.SystemClock
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
|
@ -198,7 +199,7 @@ class RustMatrixRoom(
|
||||||
|
|
||||||
override suspend fun updateMembers(): Result<Unit> = withContext(roomMembersDispatcher) {
|
override suspend fun updateMembers(): Result<Unit> = withContext(roomMembersDispatcher) {
|
||||||
val currentState = _membersStateFlow.value
|
val currentState = _membersStateFlow.value
|
||||||
val currentMembers = currentState.roomMembers()
|
val currentMembers = currentState.roomMembers()?.toImmutableList()
|
||||||
_membersStateFlow.value = MatrixRoomMembersState.Pending(prevRoomMembers = currentMembers)
|
_membersStateFlow.value = MatrixRoomMembersState.Pending(prevRoomMembers = currentMembers)
|
||||||
var rustMembers: List<RoomMember>? = null
|
var rustMembers: List<RoomMember>? = null
|
||||||
try {
|
try {
|
||||||
|
|
@ -213,7 +214,7 @@ class RustMatrixRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val mappedMembers = rustMembers.parallelMap(RoomMemberMapper::map)
|
val mappedMembers = rustMembers.parallelMap(RoomMemberMapper::map)
|
||||||
_membersStateFlow.value = MatrixRoomMembersState.Ready(mappedMembers)
|
_membersStateFlow.value = MatrixRoomMembersState.Ready(mappedMembers.toImmutableList())
|
||||||
Result.success(Unit)
|
Result.success(Unit)
|
||||||
} catch (exception: CancellationException) {
|
} catch (exception: CancellationException) {
|
||||||
_membersStateFlow.value = MatrixRoomMembersState.Error(prevRoomMembers = currentMembers, failure = exception)
|
_membersStateFlow.value = MatrixRoomMembersState.Error(prevRoomMembers = currentMembers, failure = exception)
|
||||||
|
|
@ -363,6 +364,12 @@ class RustMatrixRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun canUserJoinCall(userId: UserId): Result<Boolean> {
|
||||||
|
return runCatching {
|
||||||
|
innerRoom.canUserSendState(userId.value, StateEventType.ROOM_MEMBER_EVENT.map())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun sendImage(file: File, thumbnailFile: File, imageInfo: ImageInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
|
override suspend fun sendImage(file: File, thumbnailFile: File, imageInfo: ImageInfo, progressCallback: ProgressCallback?): Result<MediaUploadHandler> {
|
||||||
return sendAttachment(listOf(file, thumbnailFile)) {
|
return sendAttachment(listOf(file, thumbnailFile)) {
|
||||||
innerTimeline.sendImage(file.path, thumbnailFile.path, imageInfo.map(), progressCallback?.toProgressWatcher())
|
innerTimeline.sendImage(file.path, thumbnailFile.path, imageInfo.map(), progressCallback?.toProgressWatcher())
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@ import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimeli
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender
|
import io.element.android.libraries.matrix.api.timeline.item.event.ReactionSender
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
|
import io.element.android.libraries.matrix.api.timeline.item.event.Receipt
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
|
import io.element.android.libraries.matrix.api.timeline.item.event.TimelineItemEventOrigin
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import org.matrix.rustcomponents.sdk.Reaction
|
import org.matrix.rustcomponents.sdk.Reaction
|
||||||
import org.matrix.rustcomponents.sdk.EventItemOrigin as RustEventItemOrigin
|
import org.matrix.rustcomponents.sdk.EventItemOrigin as RustEventItemOrigin
|
||||||
import org.matrix.rustcomponents.sdk.EventSendState as RustEventSendState
|
import org.matrix.rustcomponents.sdk.EventSendState as RustEventSendState
|
||||||
|
|
@ -81,7 +84,7 @@ fun RustEventSendState?.map(): LocalEventSendState? {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun List<Reaction>?.map(): List<EventReaction> {
|
private fun List<Reaction>?.map(): ImmutableList<EventReaction> {
|
||||||
return this?.map {
|
return this?.map {
|
||||||
EventReaction(
|
EventReaction(
|
||||||
key = it.key,
|
key = it.key,
|
||||||
|
|
@ -90,18 +93,20 @@ private fun List<Reaction>?.map(): List<EventReaction> {
|
||||||
senderId = UserId(sender.senderId),
|
senderId = UserId(sender.senderId),
|
||||||
timestamp = sender.timestamp.toLong()
|
timestamp = sender.timestamp.toLong()
|
||||||
)
|
)
|
||||||
}
|
}.toImmutableList()
|
||||||
)
|
)
|
||||||
} ?: emptyList()
|
}?.toImmutableList() ?: persistentListOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Map<String, RustReceipt>.map(): List<Receipt> {
|
private fun Map<String, RustReceipt>.map(): ImmutableList<Receipt> {
|
||||||
return map {
|
return map {
|
||||||
Receipt(
|
Receipt(
|
||||||
userId = UserId(it.key),
|
userId = UserId(it.key),
|
||||||
timestamp = it.value.timestamp?.toLong() ?: 0
|
timestamp = it.value.timestamp?.toLong() ?: 0
|
||||||
)
|
)
|
||||||
}.sortedByDescending { it.timestamp }
|
}
|
||||||
|
.sortedByDescending { it.timestamp }
|
||||||
|
.toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun RustEventTimelineItemDebugInfo.map(): TimelineItemDebugInfo {
|
private fun RustEventTimelineItemDebugInfo.map(): TimelineItemDebugInfo {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecry
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
|
||||||
import io.element.android.libraries.matrix.impl.media.map
|
import io.element.android.libraries.matrix.impl.media.map
|
||||||
import io.element.android.libraries.matrix.impl.poll.map
|
import io.element.android.libraries.matrix.impl.poll.map
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableMap
|
||||||
import org.matrix.rustcomponents.sdk.TimelineItemContent
|
import org.matrix.rustcomponents.sdk.TimelineItemContent
|
||||||
import org.matrix.rustcomponents.sdk.TimelineItemContentKind
|
import org.matrix.rustcomponents.sdk.TimelineItemContentKind
|
||||||
import org.matrix.rustcomponents.sdk.use
|
import org.matrix.rustcomponents.sdk.use
|
||||||
|
|
@ -106,10 +108,10 @@ class TimelineEventContentMapper(private val eventMessageMapper: EventMessageMap
|
||||||
question = kind.question,
|
question = kind.question,
|
||||||
kind = kind.kind.map(),
|
kind = kind.kind.map(),
|
||||||
maxSelections = kind.maxSelections,
|
maxSelections = kind.maxSelections,
|
||||||
answers = kind.answers.map { answer -> answer.map() },
|
answers = kind.answers.map { answer -> answer.map() }.toImmutableList(),
|
||||||
votes = kind.votes.mapValues { vote ->
|
votes = kind.votes.mapValues { vote ->
|
||||||
vote.value.map { userId -> UserId(userId) }
|
vote.value.map { userId -> UserId(userId) }.toImmutableList()
|
||||||
},
|
}.toImmutableMap(),
|
||||||
endTime = kind.endTime,
|
endTime = kind.endTime,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,14 @@
|
||||||
package io.element.android.libraries.matrix.impl.usersearch
|
package io.element.android.libraries.matrix.impl.usersearch
|
||||||
|
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import org.matrix.rustcomponents.sdk.SearchUsersResults
|
import org.matrix.rustcomponents.sdk.SearchUsersResults
|
||||||
|
|
||||||
object UserSearchResultMapper {
|
object UserSearchResultMapper {
|
||||||
|
|
||||||
fun map(result: SearchUsersResults): MatrixSearchUserResults {
|
fun map(result: SearchUsersResults): MatrixSearchUserResults {
|
||||||
return MatrixSearchUserResults(
|
return MatrixSearchUserResults(
|
||||||
results = result.results.map(UserProfileMapper::map),
|
results = result.results.map(UserProfileMapper::map).toImmutableList(),
|
||||||
limited = result.limited,
|
limited = result.limited,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
||||||
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -106,8 +107,9 @@ class RustSessionVerificationService(
|
||||||
|
|
||||||
override fun didReceiveVerificationData(data: List<SessionVerificationEmoji>) {
|
override fun didReceiveVerificationData(data: List<SessionVerificationEmoji>) {
|
||||||
val emojis = data.map { emoji ->
|
val emojis = data.map { emoji ->
|
||||||
emoji.use { VerificationEmoji(it.symbol(), it.description()) }
|
emoji.use { VerificationEmoji(it.symbol(), it.description()) }
|
||||||
}
|
}
|
||||||
|
.toImmutableList()
|
||||||
_verificationFlowState.value = VerificationFlowState.ReceivedVerificationData(emojis)
|
_verificationFlowState.value = VerificationFlowState.ReceivedVerificationData(emojis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,5 @@ dependencies {
|
||||||
api(libs.coroutines.core)
|
api(libs.coroutines.core)
|
||||||
implementation(libs.coroutines.test)
|
implementation(libs.coroutines.test)
|
||||||
implementation(projects.tests.testutils)
|
implementation(projects.tests.testutils)
|
||||||
|
implementation(libs.kotlinx.collections.immutable)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ import io.element.android.libraries.matrix.test.notificationsettings.FakeNotific
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||||
import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver
|
import io.element.android.libraries.matrix.test.widget.FakeWidgetDriver
|
||||||
import io.element.android.tests.testutils.simulateLongTask
|
import io.element.android.tests.testutils.simulateLongTask
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
|
@ -110,6 +111,7 @@ class FakeMatrixRoom(
|
||||||
private var generateWidgetWebViewUrlResult = Result.success("https://call.element.io")
|
private var generateWidgetWebViewUrlResult = Result.success("https://call.element.io")
|
||||||
private var getWidgetDriverResult: Result<MatrixWidgetDriver> = Result.success(FakeWidgetDriver())
|
private var getWidgetDriverResult: Result<MatrixWidgetDriver> = Result.success(FakeWidgetDriver())
|
||||||
private var canUserTriggerRoomNotificationResult: Result<Boolean> = Result.success(true)
|
private var canUserTriggerRoomNotificationResult: Result<Boolean> = Result.success(true)
|
||||||
|
private var canUserJoinCallResult: Result<Boolean> = Result.success(true)
|
||||||
var sendMessageMentions = emptyList<Mention>()
|
var sendMessageMentions = emptyList<Mention>()
|
||||||
val editMessageCalls = mutableListOf<Pair<String, String?>>()
|
val editMessageCalls = mutableListOf<Pair<String, String?>>()
|
||||||
|
|
||||||
|
|
@ -291,6 +293,10 @@ class FakeMatrixRoom(
|
||||||
return canUserTriggerRoomNotificationResult
|
return canUserTriggerRoomNotificationResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun canUserJoinCall(userId: UserId): Result<Boolean> {
|
||||||
|
return canUserJoinCallResult
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun sendImage(
|
override suspend fun sendImage(
|
||||||
file: File,
|
file: File,
|
||||||
thumbnailFile: File,
|
thumbnailFile: File,
|
||||||
|
|
@ -473,6 +479,10 @@ class FakeMatrixRoom(
|
||||||
canUserTriggerRoomNotificationResult = result
|
canUserTriggerRoomNotificationResult = result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun givenCanUserJoinCall(result: Result<Boolean>) {
|
||||||
|
canUserJoinCallResult = result
|
||||||
|
}
|
||||||
|
|
||||||
fun givenIgnoreResult(result: Result<Unit>) {
|
fun givenIgnoreResult(result: Result<Unit>) {
|
||||||
ignoreResult = result
|
ignoreResult = result
|
||||||
}
|
}
|
||||||
|
|
@ -615,7 +625,7 @@ fun aRoomInfo(
|
||||||
isSpace = isSpace,
|
isSpace = isSpace,
|
||||||
isTombstoned = isTombstoned,
|
isTombstoned = isTombstoned,
|
||||||
canonicalAlias = canonicalAlias,
|
canonicalAlias = canonicalAlias,
|
||||||
alternativeAliases = alternativeAliases,
|
alternativeAliases = alternativeAliases.toImmutableList(),
|
||||||
currentUserMembership = currentUserMembership,
|
currentUserMembership = currentUserMembership,
|
||||||
latestEvent = latestEvent,
|
latestEvent = latestEvent,
|
||||||
inviter = inviter,
|
inviter = inviter,
|
||||||
|
|
@ -626,5 +636,5 @@ fun aRoomInfo(
|
||||||
notificationCount = notificationCount,
|
notificationCount = notificationCount,
|
||||||
userDefinedNotificationMode = userDefinedNotificationMode,
|
userDefinedNotificationMode = userDefinedNotificationMode,
|
||||||
hasRoomCall = hasRoomCall,
|
hasRoomCall = hasRoomCall,
|
||||||
activeRoomCallParticipants = activeRoomCallParticipants
|
activeRoomCallParticipants = activeRoomCallParticipants.toImmutableList(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID
|
import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_NAME
|
import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.persistentMapOf
|
||||||
|
|
||||||
fun aRoomSummaryFilled(
|
fun aRoomSummaryFilled(
|
||||||
roomId: RoomId = A_ROOM_ID,
|
roomId: RoomId = A_ROOM_ID,
|
||||||
|
|
@ -107,8 +110,8 @@ fun anEventTimelineItem(
|
||||||
isOwn: Boolean = false,
|
isOwn: Boolean = false,
|
||||||
isRemote: Boolean = false,
|
isRemote: Boolean = false,
|
||||||
localSendState: LocalEventSendState? = null,
|
localSendState: LocalEventSendState? = null,
|
||||||
reactions: List<EventReaction> = emptyList(),
|
reactions: ImmutableList<EventReaction> = persistentListOf(),
|
||||||
receipts: List<Receipt> = emptyList(),
|
receipts: ImmutableList<Receipt> = persistentListOf(),
|
||||||
sender: UserId = A_USER_ID,
|
sender: UserId = A_USER_ID,
|
||||||
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(),
|
senderProfile: ProfileTimelineDetails = aProfileTimelineDetails(),
|
||||||
timestamp: Long = 0L,
|
timestamp: Long = 0L,
|
||||||
|
|
@ -181,12 +184,12 @@ fun aTimelineItemDebugInfo(
|
||||||
|
|
||||||
fun aPollContent(
|
fun aPollContent(
|
||||||
question: String = "Do you like polls?",
|
question: String = "Do you like polls?",
|
||||||
answers: List<PollAnswer> = listOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")),
|
answers: ImmutableList<PollAnswer> = persistentListOf(PollAnswer("1", "Yes"), PollAnswer("2", "No")),
|
||||||
) = PollContent(
|
) = PollContent(
|
||||||
question = question,
|
question = question,
|
||||||
kind = PollKind.Disclosed,
|
kind = PollKind.Disclosed,
|
||||||
maxSelections = 1u,
|
maxSelections = 1u,
|
||||||
answers = answers,
|
answers = answers,
|
||||||
votes = mapOf(),
|
votes = persistentMapOf(),
|
||||||
endTime = null
|
endTime = null
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import io.element.android.libraries.matrix.api.verification.SessionVerificationS
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
||||||
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatus
|
||||||
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
import io.element.android.libraries.matrix.api.verification.VerificationEmoji
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toPersistentList
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -29,7 +31,7 @@ class FakeSessionVerificationService : SessionVerificationService {
|
||||||
private val _sessionVerifiedStatus = MutableStateFlow<SessionVerifiedStatus>(SessionVerifiedStatus.Unknown)
|
private val _sessionVerifiedStatus = MutableStateFlow<SessionVerifiedStatus>(SessionVerifiedStatus.Unknown)
|
||||||
private var _verificationFlowState = MutableStateFlow<VerificationFlowState>(VerificationFlowState.Initial)
|
private var _verificationFlowState = MutableStateFlow<VerificationFlowState>(VerificationFlowState.Initial)
|
||||||
private var _canVerifySessionFlow = MutableStateFlow(true)
|
private var _canVerifySessionFlow = MutableStateFlow(true)
|
||||||
private var emojiList = emptyList<VerificationEmoji>()
|
private var emojiList = persistentListOf<VerificationEmoji>()
|
||||||
var shouldFail = false
|
var shouldFail = false
|
||||||
|
|
||||||
override val verificationFlowState: StateFlow<VerificationFlowState> =_verificationFlowState
|
override val verificationFlowState: StateFlow<VerificationFlowState> =_verificationFlowState
|
||||||
|
|
@ -87,7 +89,7 @@ class FakeSessionVerificationService : SessionVerificationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun givenEmojiList(emojis: List<VerificationEmoji>) {
|
fun givenEmojiList(emojis: List<VerificationEmoji>) {
|
||||||
this.emojiList = emojis
|
this.emojiList = emojis.toPersistentList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun reset() {
|
override suspend fun reset() {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package io.element.android.libraries.textcomposer
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.libraries.designsystem.theme.bgSubtleTertiary
|
import io.element.android.libraries.designsystem.theme.bgSubtleTertiary
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.wysiwyg.compose.RichTextEditorDefaults
|
import io.element.android.wysiwyg.compose.RichTextEditorDefaults
|
||||||
|
|
@ -39,7 +40,8 @@ internal object ElementRichTextEditorStyle {
|
||||||
m3colors.primary
|
m3colors.primary
|
||||||
} else {
|
} else {
|
||||||
m3colors.secondary
|
m3colors.secondary
|
||||||
}
|
},
|
||||||
|
lineHeight = 16.25.sp,
|
||||||
),
|
),
|
||||||
cursor = RichTextEditorDefaults.cursorStyle(
|
cursor = RichTextEditorDefaults.cursorStyle(
|
||||||
color = colors.iconAccentTertiary,
|
color = colors.iconAccentTertiary,
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
|
@ -85,7 +84,6 @@ import io.element.android.libraries.textcomposer.model.VoiceMessagePlayerEvent
|
||||||
import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent
|
import io.element.android.libraries.textcomposer.model.VoiceMessageRecorderEvent
|
||||||
import io.element.android.libraries.textcomposer.model.VoiceMessageState
|
import io.element.android.libraries.textcomposer.model.VoiceMessageState
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.wysiwyg.compose.PillStyle
|
|
||||||
import io.element.android.wysiwyg.compose.RichTextEditor
|
import io.element.android.wysiwyg.compose.RichTextEditor
|
||||||
import io.element.android.wysiwyg.compose.RichTextEditorState
|
import io.element.android.wysiwyg.compose.RichTextEditorState
|
||||||
import io.element.android.wysiwyg.display.TextDisplay
|
import io.element.android.wysiwyg.display.TextDisplay
|
||||||
|
|
@ -444,8 +442,6 @@ private fun TextInput(
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
style = ElementRichTextEditorStyle.create(
|
style = ElementRichTextEditorStyle.create(
|
||||||
hasFocus = state.hasFocus
|
hasFocus = state.hasFocus
|
||||||
).copy(
|
|
||||||
pill = PillStyle(Color.Red)
|
|
||||||
),
|
),
|
||||||
resolveMentionDisplay = resolveMentionDisplay,
|
resolveMentionDisplay = resolveMentionDisplay,
|
||||||
resolveRoomMentionDisplay = resolveRoomMentionDisplay,
|
resolveRoomMentionDisplay = resolveRoomMentionDisplay,
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ dependencies {
|
||||||
implementation(projects.libraries.matrixui)
|
implementation(projects.libraries.matrixui)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
api(projects.libraries.usersearch.api)
|
api(projects.libraries.usersearch.api)
|
||||||
|
implementation(libs.kotlinx.collections.immutable)
|
||||||
|
|
||||||
testImplementation(libs.test.junit)
|
testImplementation(libs.test.junit)
|
||||||
testImplementation(libs.coroutines.test)
|
testImplementation(libs.coroutines.test)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
import io.element.android.libraries.matrix.test.A_USER_NAME
|
import io.element.android.libraries.matrix.test.A_USER_NAME
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
|
@ -37,7 +38,7 @@ internal class MatrixUserListDataSourceTest {
|
||||||
searchTerm = "test",
|
searchTerm = "test",
|
||||||
result = Result.success(
|
result = Result.success(
|
||||||
MatrixSearchUserResults(
|
MatrixSearchUserResults(
|
||||||
results = listOf(
|
results = persistentListOf(
|
||||||
aMatrixUserProfile(),
|
aMatrixUserProfile(),
|
||||||
aMatrixUserProfile(userId = A_USER_ID_2)
|
aMatrixUserProfile(userId = A_USER_ID_2)
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:6cabc1dec0b89061db2b9f5301371b839a458e7e5bb6c8bc5b4d2fd4fcc3a179
|
||||||
|
size 54275
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:da867f9dd0e7d21419ce52e2e0eabfc26583e9dfb1523613a932394c307b3e28
|
||||||
|
size 52621
|
||||||
Loading…
Add table
Add a link
Reference in a new issue