From 929ebc79c5255c8022a5b4bcf1dea46f1661d1af Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Wed, 10 May 2023 11:08:43 +0200 Subject: [PATCH] Delete cached avatar URI --- .../createroom/impl/CreateRoomConfig.kt | 3 ++- .../createroom/impl/CreateRoomDataStore.kt | 12 +++++++++-- .../configureroom/ConfigureRoomPresenter.kt | 21 ++++++++++--------- .../impl/configureroom/ConfigureRoomView.kt | 3 +-- .../ConfigureRoomPresenterTests.kt | 21 ++++++++++++++----- 5 files changed, 40 insertions(+), 20 deletions(-) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt index 21662fdb64..23b6f3239d 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomConfig.kt @@ -16,6 +16,7 @@ package io.element.android.features.createroom.impl +import android.net.Uri import io.element.android.features.createroom.impl.configureroom.RoomPrivacy import io.element.android.libraries.matrix.api.user.MatrixUser import kotlinx.collections.immutable.ImmutableList @@ -24,7 +25,7 @@ import kotlinx.collections.immutable.persistentListOf data class CreateRoomConfig( val roomName: String? = null, val topic: String? = null, - val avatarUrl: String? = null, + val avatarUri: Uri? = null, val invites: ImmutableList = persistentListOf(), val privacy: RoomPrivacy? = null, ) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt index e55fca755d..8d124d25de 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/CreateRoomDataStore.kt @@ -16,6 +16,7 @@ package io.element.android.features.createroom.impl +import android.net.Uri import io.element.android.features.createroom.impl.configureroom.RoomPrivacy import io.element.android.features.createroom.impl.di.CreateRoomScope import io.element.android.features.userlist.api.UserListDataStore @@ -24,6 +25,7 @@ import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine +import java.io.File import javax.inject.Inject @SingleIn(CreateRoomScope::class) @@ -32,6 +34,11 @@ class CreateRoomDataStore @Inject constructor( ) { private val createRoomConfigFlow: MutableStateFlow = MutableStateFlow(CreateRoomConfig()) + private var cachedAvatarUri: Uri? = null + set(value) { + field?.path?.let { File(it) }?.delete() + field = value + } fun getCreateRoomConfig(): Flow = combine( selectedUserListDataStore.selectedUsers(), @@ -48,8 +55,9 @@ class CreateRoomDataStore @Inject constructor( createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(topic = topic?.takeIf { it.isNotEmpty() })) } - fun setAvatarUrl(avatarUrl: String?) { - createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(avatarUrl = avatarUrl)) + fun setAvatarUri(uri: Uri?, cached: Boolean = false) { + cachedAvatarUri = uri.takeIf { cached } + createRoomConfigFlow.tryEmit(createRoomConfigFlow.value.copy(avatarUri = uri)) } fun setPrivacy(privacy: RoomPrivacy?) { diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt index 399bb2d763..941a03f84c 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenter.kt @@ -56,20 +56,21 @@ class ConfigureRoomPresenter @Inject constructor( } } - val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(onResult = { uri -> - if (uri != null) dataStore.setAvatarUrl(uri.toString()) - }) - val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker(onResult = { uri -> - if (uri != null) dataStore.setAvatarUrl(uri.toString()) - }) + val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker( + onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) }, + deleteAfter = false, + ) + val galleryImagePicker = mediaPickerProvider.registerGalleryImagePicker( + onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri) } + ) - val avatarActions by remember(createRoomConfig.value.avatarUrl) { + val avatarActions by remember(createRoomConfig.value.avatarUri) { derivedStateOf { mutableListOf( AvatarAction.TakePhoto, AvatarAction.ChoosePhoto, ).apply { - if (createRoomConfig.value.avatarUrl != null) { + if (createRoomConfig.value.avatarUri != null) { add(AvatarAction.Remove) } }.toImmutableList() @@ -95,7 +96,7 @@ class ConfigureRoomPresenter @Inject constructor( when (event.action) { AvatarAction.ChoosePhoto -> galleryImagePicker.launch() AvatarAction.TakePhoto -> cameraPhotoPicker.launch() - AvatarAction.Remove -> dataStore.setAvatarUrl(null) + AvatarAction.Remove -> dataStore.setAvatarUri(uri = null) } } @@ -122,7 +123,7 @@ class ConfigureRoomPresenter @Inject constructor( visibility = if (config.privacy == RoomPrivacy.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE, preset = if (config.privacy == RoomPrivacy.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT, invite = config.invites.map { it.userId }, - avatar = config.avatarUrl, + avatar = config.avatarUri?.toString(), ) matrixClient.createRoom(params).getOrThrow() }.execute(createRoomAction) diff --git a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt index 214ec89efb..b019e693e0 100644 --- a/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt +++ b/features/createroom/impl/src/main/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomView.kt @@ -41,7 +41,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.core.net.toUri import io.element.android.features.createroom.impl.R import io.element.android.features.createroom.impl.components.Avatar import io.element.android.features.createroom.impl.components.LabelledTextField @@ -104,7 +103,7 @@ fun ConfigureRoomView( ) { RoomNameWithAvatar( modifier = Modifier.padding(horizontal = 16.dp), - avatarUri = state.config.avatarUrl?.toUri(), + avatarUri = state.config.avatarUri, roomName = state.config.roomName.orEmpty(), onAvatarClick = ::onAvatarClicked, onRoomNameChanged = { state.eventSink(ConfigureRoomEvents.RoomNameChanged(it)) }, diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 8be1e777a8..e1ed1f9c71 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -25,6 +25,7 @@ import app.cash.turbine.test import com.google.common.truth.Truth.assertThat import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore +import io.element.android.features.createroom.impl.configureroom.avatar.AvatarAction import io.element.android.features.userlist.api.UserListDataStore import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.core.RoomId @@ -34,6 +35,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.mediapickers.PickerProvider import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -48,15 +50,18 @@ class ConfigureRoomPresenterTests { private lateinit var presenter: ConfigureRoomPresenter private lateinit var userListDataStore: UserListDataStore + private lateinit var createRoomDataStore: CreateRoomDataStore private lateinit var fakeMatrixClient: FakeMatrixClient @Before fun setup() { fakeMatrixClient = FakeMatrixClient() userListDataStore = UserListDataStore() + createRoomDataStore = CreateRoomDataStore(userListDataStore) presenter = ConfigureRoomPresenter( - dataStore = CreateRoomDataStore(userListDataStore), - matrixClient = fakeMatrixClient + dataStore = createRoomDataStore, + matrixClient = fakeMatrixClient, + mediaPickerProvider = PickerProvider(isInTest = true), ) } @@ -70,7 +75,7 @@ class ConfigureRoomPresenterTests { assertThat(initialState.config.roomName).isNull() assertThat(initialState.config.topic).isNull() assertThat(initialState.config.invites).isEmpty() - assertThat(initialState.config.avatarUrl).isNull() + assertThat(initialState.config.avatarUri).isNull() assertThat(initialState.config.privacy).isNull() } } @@ -139,10 +144,16 @@ class ConfigureRoomPresenterTests { assertThat(newState.config).isEqualTo(expectedConfig) // Room avatar + // Add val anUri = Uri.parse(AN_AVATAR_URL) - newState.eventSink(ConfigureRoomEvents.AvatarUriChanged(anUri)) + createRoomDataStore.setAvatarUri(anUri) newState = awaitItem() - expectedConfig = expectedConfig.copy(avatarUrl = anUri.toString()) + expectedConfig = expectedConfig.copy(avatarUri = anUri) + assertThat(newState.config).isEqualTo(expectedConfig) + // Remove + newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.Remove)) + newState = awaitItem() + expectedConfig = expectedConfig.copy(avatarUri = null) assertThat(newState.config).isEqualTo(expectedConfig) // Room privacy