Skip to content

Adapt to changes in SDK #2836

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import io.element.android.features.rageshake.api.logs.LogFilesRemover
import io.element.android.libraries.di.AppScope
import javax.inject.Inject

/**
* Remove existing logs from the device to remove any leaks of sensitive data.
*/
@ContributesMultibinding(AppScope::class)
class AppMigration01 @Inject constructor(
private val logFilesRemover: LogFilesRemover,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import io.element.android.libraries.sessionstorage.api.SessionStore
import kotlinx.coroutines.coroutineScope
import javax.inject.Inject

/**
* This migration sets the skip session verification preference to true for all existing sessions.
* This way we don't force existing users to verify their session again.
*/
@ContributesMultibinding(AppScope::class)
class AppMigration02 @Inject constructor(
private val sessionStore: SessionStore,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.element.android.features.migration.impl.migrations

import com.squareup.anvil.annotations.ContributesMultibinding
import io.element.android.libraries.di.AppScope
import javax.inject.Inject

/**
* This performs the same operation as [AppMigration01], since we need to clear the local logs again.
*/
@ContributesMultibinding(AppScope::class)
class AppMigration03 @Inject constructor(
private val migration01: AppMigration01,
) : AppMigration {
override val order: Int = 3

override suspend fun migrate() {
migration01.migrate()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK, but maybe it will be clearer using composition.

What do you think about:

@ContributesMultibinding(AppScope::class)
class AppMigration03 @Inject constructor(
    private val appMigration01: AppMigration01,
) : AppMigration {
    override val order: Int = 3

    override suspend fun migrate() {
        appMigration01.migrate()
    }
}

Consequently, AppMigration01 does not need to be open

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.element.android.features.migration.impl.migrations

import io.element.android.features.rageshake.test.logs.FakeLogFilesRemover
import kotlinx.coroutines.test.runTest
import org.junit.Test

class AppMigration03Test {
@Test
fun `test migration`() = runTest {
val logsFileRemover = FakeLogFilesRemover()
val migration = AppMigration03(migration01 = AppMigration01(logsFileRemover))

migration.migrate()

logsFileRemover.performLambda.assertions().isCalledOnce()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class RoomDetailsPresenter @Inject constructor(

val roomAvatar by remember { derivedStateOf { roomInfo?.avatarUrl ?: room.avatarUrl } }

val roomName by remember { derivedStateOf { (roomInfo?.name ?: room.name ?: room.displayName).trim() } }
val roomName by remember { derivedStateOf { (roomInfo?.name ?: room.displayName).trim() } }
val roomTopic by remember { derivedStateOf { roomInfo?.topic ?: room.topic } }
val isFavorite by remember { derivedStateOf { roomInfo?.isFavorite.orFalse() } }
val isPublic by remember { derivedStateOf { roomInfo?.isPublic.orFalse() } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class RoomDetailsEditPresenter @Inject constructor(
// just erase the local value when the room field has changed
var roomAvatarUri by rememberSaveable(room.avatarUrl) { mutableStateOf(room.avatarUrl?.toUri()) }

var roomName by rememberSaveable { mutableStateOf((room.name ?: room.displayName).trim()) }
var roomName by rememberSaveable { mutableStateOf(room.displayName.trim()) }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to use the new field RoomInfo.rawName here, but this can be handled separately.

It will fix the form per-filled with a computed room name like "Alice, Bob and 3 others".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using RoomInfo.rawName needs some other changes so I think it's probably better to do it on a separate PR.

var roomTopic by rememberSaveable { mutableStateOf(room.topic?.trim()) }

val saveButtonEnabled by remember(
Expand All @@ -76,7 +76,7 @@ class RoomDetailsEditPresenter @Inject constructor(
) {
derivedStateOf {
roomAvatarUri?.toString()?.trim() != room.avatarUrl?.toUri()?.toString()?.trim() ||
roomName.trim() != (room.name ?: room.displayName).trim() ||
roomName.trim() != room.displayName.trim() ||
roomTopic.orEmpty().trim() != room.topic.orEmpty().trim()
}
}
Expand Down Expand Up @@ -168,7 +168,7 @@ class RoomDetailsEditPresenter @Inject constructor(
Timber.e(it, "Failed to set room topic")
})
}
if (name.isNotEmpty() && name.trim() != room.name.orEmpty().trim()) {
if (name.isNotEmpty() && name.trim() != room.displayName.trim()) {
results.add(room.setName(name).onFailure {
Timber.e(it, "Failed to set room name")
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class RoomDetailsPresenterTests {
presenter.test {
val initialState = awaitItem()
assertThat(initialState.roomId).isEqualTo(room.roomId)
assertThat(initialState.roomName).isEqualTo(room.name)
assertThat(initialState.roomName).isEqualTo(room.displayName)
assertThat(initialState.roomAvatarUrl).isEqualTo(room.avatarUrl)
assertThat(initialState.roomTopic).isEqualTo(RoomTopicState.ExistingTopic(room.topic!!))
assertThat(initialState.memberCount).isEqualTo(room.joinedMemberCount)
Expand Down Expand Up @@ -148,7 +148,7 @@ class RoomDetailsPresenterTests {

@Test
fun `present - initial state with no room name`() = runTest {
val room = aMatrixRoom(name = null)
val room = aMatrixRoom(displayName = "")
val presenter = createRoomDetailsPresenter(room)
presenter.test {
val initialState = awaitItem()
Expand Down Expand Up @@ -476,8 +476,7 @@ class RoomDetailsPresenterTests {

fun aMatrixRoom(
roomId: RoomId = A_ROOM_ID,
name: String? = A_ROOM_NAME,
displayName: String = "A fallback display name",
displayName: String = A_ROOM_NAME,
topic: String? = "A topic",
avatarUrl: String? = "https://matrix.org/avatar.jpg",
isEncrypted: Boolean = true,
Expand All @@ -486,7 +485,6 @@ fun aMatrixRoom(
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService()
) = FakeMatrixRoom(
roomId = roomId,
name = name,
displayName = displayName,
topic = topic,
avatarUrl = avatarUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class RoomDetailsEditPresenterTest {
}.test {
val initialState = awaitItem()
assertThat(initialState.roomId).isEqualTo(room.roomId.value)
assertThat(initialState.roomName).isEqualTo(room.name)
assertThat(initialState.roomName).isEqualTo(room.displayName)
assertThat(initialState.roomAvatarUrl).isEqualTo(roomAvatarUri)
assertThat(initialState.roomTopic).isEqualTo(room.topic.orEmpty())
assertThat(initialState.avatarActions).containsExactly(
Expand Down Expand Up @@ -191,7 +191,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - updates state in response to changes`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)
val presenter = createRoomDetailsEditPresenter(room)

moleculeFlow(RecompositionMode.Immediate) {
Expand Down Expand Up @@ -234,7 +234,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - obtains avatar uris from gallery`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

fakePickerProvider.givenResult(anotherAvatarUri)

Expand All @@ -255,7 +255,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - obtains avatar uris from camera`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

fakePickerProvider.givenResult(anotherAvatarUri)
val fakePermissionsPresenter = FakePermissionsPresenter()
Expand Down Expand Up @@ -288,7 +288,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - updates save button state`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

fakePickerProvider.givenResult(roomAvatarUri)

Expand Down Expand Up @@ -340,7 +340,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - updates save button state when initial values are null`() = runTest {
val room = aMatrixRoom(topic = null, name = null, displayName = "fallback", avatarUrl = null)
val room = aMatrixRoom(topic = null, displayName = "fallback", avatarUrl = null)

fakePickerProvider.givenResult(roomAvatarUri)

Expand Down Expand Up @@ -392,7 +392,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - save changes room details if different`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

val presenter = createRoomDetailsEditPresenter(room)

Expand All @@ -417,7 +417,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - save doesn't change room details if they're the same trimmed`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

val presenter = createRoomDetailsEditPresenter(room)

Expand All @@ -441,7 +441,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - save doesn't change topic if it was unset and is now blank`() = runTest {
val room = aMatrixRoom(topic = null, name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = null, displayName = "Name", avatarUrl = AN_AVATAR_URL)

val presenter = createRoomDetailsEditPresenter(room)

Expand All @@ -464,7 +464,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - save doesn't change name if it's now empty`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

val presenter = createRoomDetailsEditPresenter(room)

Expand All @@ -487,7 +487,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - save processes and sets avatar when processor returns successfully`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

givenPickerReturnsFile()

Expand All @@ -511,7 +511,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - save does not set avatar data if processor fails`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL)
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL)

fakePickerProvider.givenResult(anotherAvatarUri)
fakeMediaPreProcessor.givenResult(Result.failure(Throwable("Oh no")))
Expand All @@ -538,7 +538,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - sets save action to failure if name update fails`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL).apply {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
givenSetNameResult(Result.failure(Throwable("!")))
}

Expand All @@ -547,7 +547,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - sets save action to failure if topic update fails`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL).apply {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
givenSetTopicResult(Result.failure(Throwable("!")))
}

Expand All @@ -556,7 +556,7 @@ class RoomDetailsEditPresenterTest {

@Test
fun `present - sets save action to failure if removing avatar fails`() = runTest {
val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL).apply {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
givenRemoveAvatarResult(Result.failure(Throwable("!")))
}

Expand All @@ -567,7 +567,7 @@ class RoomDetailsEditPresenterTest {
fun `present - sets save action to failure if setting avatar fails`() = runTest {
givenPickerReturnsFile()

val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL).apply {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
givenUpdateAvatarResult(Result.failure(Throwable("!")))
}

Expand All @@ -578,7 +578,7 @@ class RoomDetailsEditPresenterTest {
fun `present - CancelSaveChanges resets save action state`() = runTest {
givenPickerReturnsFile()

val room = aMatrixRoom(topic = "My topic", name = "Name", avatarUrl = AN_AVATAR_URL).apply {
val room = aMatrixRoom(topic = "My topic", displayName = "Name", avatarUrl = AN_AVATAR_URL).apply {
givenSetTopicResult(Result.failure(Throwable("!")))
}

Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ jsoup = "org.jsoup:jsoup:1.17.2"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:1.4.2"
timber = "com.jakewharton.timber:timber:5.0.1"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.16"
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.2.18"
matrix_richtexteditor = { module = "io.element.android:wysiwyg", 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" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ import java.io.File
interface MatrixRoom : Closeable {
val sessionId: SessionId
val roomId: RoomId
val name: String?
val displayName: String
val alias: RoomAlias?
val alternativeAliases: List<RoomAlias>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,12 @@ interface RoomList {

/**
* The source of the room list data.
* All: all rooms except invites.
* Invites: only invites.
* All: all rooms.
*
* To apply some dynamic filtering on top of that, use [DynamicRoomList].
*/
enum class Source {
All,
Invites,
All
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is becoming a bit useless if there is only one value, but I think we could keep this enum for clarity?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I wanted to keep it in case we'd need separate lists in the future again for some reason.

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ interface RoomListService {
*/
val allRooms: DynamicRoomList

/**
* returns a [RoomList] object of all invites.
*/
val invites: RoomList

/**
* Will set the visible range of all rooms.
* This is useful to load more data when the user scrolls down.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import org.matrix.rustcomponents.sdk.BackupState
Expand Down Expand Up @@ -145,12 +146,7 @@ class RustMatrixClient(
dispatchers = dispatchers,
)
private val notificationProcessSetup = NotificationProcessSetup.SingleProcess(syncService)
private val notificationClient = client.notificationClient(notificationProcessSetup)
.use { builder ->
builder
.filterByPushRules()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API has vanished, I guess this is OK

.finish()
}
private val notificationClient = runBlocking { client.notificationClient(notificationProcessSetup) }
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
private val notificationSettingsService = RustNotificationSettingsService(client, dispatchers)
.apply { start() }
Expand Down Expand Up @@ -465,7 +461,7 @@ class RustMatrixClient(

override suspend fun resolveRoomAlias(roomAlias: RoomAlias): Result<RoomId> = withContext(sessionDispatcher) {
runCatching {
client.resolveRoomAlias(roomAlias.value).let(::RoomId)
client.resolveRoomAlias(roomAlias.value).roomId.let(::RoomId)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will improve this and use the returned servers list in a separate PR.

}
}

Expand Down
Loading
Loading