mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-12-22 23:58:47 +01:00
Updating room avatar is implemented.
This commit is contained in:
parent
a6e4a328b3
commit
52eec06110
@ -16,6 +16,7 @@
|
||||
|
||||
package im.vector.matrix.rx
|
||||
|
||||
import android.net.Uri
|
||||
import im.vector.matrix.android.api.query.QueryStringValue
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
@ -109,6 +110,10 @@ class RxRoom(private val room: Room) {
|
||||
fun updateName(name: String): Completable = completableBuilder<Unit> {
|
||||
room.updateName(name, it)
|
||||
}
|
||||
|
||||
fun updateAvatar(avatarUri: Uri, fileName: String): Completable = completableBuilder<Unit> {
|
||||
room.updateAvatar(avatarUri, fileName, it)
|
||||
}
|
||||
}
|
||||
|
||||
fun Room.rx(): RxRoom {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package im.vector.matrix.android.api.session.room.state
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.query.QueryStringValue
|
||||
@ -36,6 +37,11 @@ interface StateService {
|
||||
*/
|
||||
fun updateName(name: String, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
/**
|
||||
* Update the avatar of the room
|
||||
*/
|
||||
fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun sendStateEvent(eventType: String, stateKey: String?, body: JsonDict, callback: MatrixCallback<Unit>): Cancelable
|
||||
|
||||
fun getStateEvent(eventType: String, stateKey: QueryStringValue = QueryStringValue.NoCondition): Event?
|
||||
|
@ -32,6 +32,7 @@ import im.vector.matrix.android.internal.session.account.AccountModule
|
||||
import im.vector.matrix.android.internal.session.cache.CacheModule
|
||||
import im.vector.matrix.android.internal.session.call.CallModule
|
||||
import im.vector.matrix.android.internal.session.content.ContentModule
|
||||
import im.vector.matrix.android.internal.session.content.UploadAvatarWorker
|
||||
import im.vector.matrix.android.internal.session.content.UploadContentWorker
|
||||
import im.vector.matrix.android.internal.session.filter.FilterModule
|
||||
import im.vector.matrix.android.internal.session.group.GetGroupDataWorker
|
||||
@ -117,6 +118,8 @@ internal interface SessionComponent {
|
||||
|
||||
fun inject(worker: UploadContentWorker)
|
||||
|
||||
fun inject(worker: UploadAvatarWorker)
|
||||
|
||||
fun inject(worker: SyncWorker)
|
||||
|
||||
fun inject(worker: AddHttpPusherWorker)
|
||||
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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 im.vector.matrix.android.internal.session.content
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.squareup.moshi.JsonClass
|
||||
import im.vector.matrix.android.internal.worker.SessionWorkerParams
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import im.vector.matrix.android.internal.worker.getSessionComponent
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Possible previous worker: None
|
||||
* Possible next worker : None
|
||||
*/
|
||||
internal class UploadAvatarWorker(val context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
override val sessionId: String,
|
||||
val queryUri: Uri,
|
||||
val fileName: String,
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class OutputParams(
|
||||
override val sessionId: String,
|
||||
val imageUrl: String? = null,
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
@Inject lateinit var fileUploader: FileUploader
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val params = WorkerParamsFactory.fromData<Params>(inputData)
|
||||
?: return Result.success()
|
||||
.also { Timber.e("Unable to parse work parameters") }
|
||||
|
||||
Timber.v("Starting upload media work with params $params")
|
||||
|
||||
if (params.lastFailureMessage != null) {
|
||||
// Transmit the error
|
||||
return Result.success(inputData)
|
||||
.also { Timber.e("Work cancelled due to input error from parent") }
|
||||
}
|
||||
|
||||
// Just defensive code to ensure that we never have an uncaught exception that could break the queue
|
||||
return try {
|
||||
internalDoWork(params)
|
||||
} catch (failure: Throwable) {
|
||||
Timber.e(failure)
|
||||
handleFailure(params, failure)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun internalDoWork(params: Params): Result {
|
||||
val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
|
||||
sessionComponent.inject(this)
|
||||
|
||||
try {
|
||||
val inputStream = context.contentResolver.openInputStream(params.queryUri)
|
||||
?: return Result.success(
|
||||
WorkerParamsFactory.toData(
|
||||
params.copy(
|
||||
lastFailureMessage = "Cannot openInputStream for file: " + params.queryUri.toString()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
inputStream.use {
|
||||
return try {
|
||||
Timber.v("## UploadAvatarWorker - Uploading avatar...")
|
||||
val response = fileUploader.uploadByteArray(inputStream.readBytes(), params.fileName, "image/jpeg")
|
||||
Timber.v("## UploadAvatarWorker - Uploadeded avatar: ${response.contentUri}")
|
||||
handleSuccess(params, response.contentUri)
|
||||
} catch (t: Throwable) {
|
||||
Timber.e(t, "## UploadAvatarWorker - Uploading avatar failed...")
|
||||
handleFailure(params, t)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
return Result.success(
|
||||
WorkerParamsFactory.toData(
|
||||
params.copy(
|
||||
lastFailureMessage = e.localizedMessage
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleFailure(params: Params, failure: Throwable): Result {
|
||||
return Result.success(
|
||||
WorkerParamsFactory.toData(
|
||||
params.copy(
|
||||
lastFailureMessage = failure.localizedMessage
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleSuccess(params: Params, imageUrl: String): Result {
|
||||
Timber.v("handleSuccess $imageUrl, work is stopped $isStopped")
|
||||
|
||||
val sendParams = OutputParams(params.sessionId, imageUrl, params.lastFailureMessage)
|
||||
return Result.success(WorkerParamsFactory.toData(sendParams))
|
||||
}
|
||||
}
|
@ -16,7 +16,10 @@
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.state
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.work.BackoffPolicy
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
@ -25,15 +28,29 @@ import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.state.StateService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.api.util.CancelableBag
|
||||
import im.vector.matrix.android.api.util.JsonDict
|
||||
import im.vector.matrix.android.api.util.Optional
|
||||
import im.vector.matrix.android.internal.di.SessionId
|
||||
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
||||
import im.vector.matrix.android.internal.session.content.UploadAvatarWorker
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.CancelableWork
|
||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
private const val UPLOAD_AVATAR_WORK = "UPLOAD_AVATAR_WORK"
|
||||
|
||||
internal class DefaultStateService @AssistedInject constructor(@Assisted private val roomId: String,
|
||||
private val stateEventDataSource: StateEventDataSource,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val sendStateTask: SendStateTask
|
||||
private val sendStateTask: SendStateTask,
|
||||
@SessionId private val sessionId: String,
|
||||
private val workManagerProvider: WorkManagerProvider,
|
||||
private val coroutineDispatchers: MatrixCoroutineDispatchers
|
||||
) : StateService {
|
||||
|
||||
@AssistedInject.Factory
|
||||
@ -93,4 +110,40 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
|
||||
stateKey = null
|
||||
)
|
||||
}
|
||||
|
||||
override fun updateAvatar(avatarUri: Uri, fileName: String, callback: MatrixCallback<Unit>): Cancelable {
|
||||
val cancelableBag = CancelableBag()
|
||||
val workerParams = UploadAvatarWorker.Params(sessionId, avatarUri, fileName)
|
||||
val workerData = WorkerParamsFactory.toData(workerParams)
|
||||
|
||||
val uploadAvatarWork = workManagerProvider.matrixOneTimeWorkRequestBuilder<UploadAvatarWorker>()
|
||||
.setConstraints(WorkManagerProvider.workConstraints)
|
||||
.setInputData(workerData)
|
||||
.setBackoffCriteria(BackoffPolicy.LINEAR, WorkManagerProvider.BACKOFF_DELAY, TimeUnit.MILLISECONDS)
|
||||
.build()
|
||||
|
||||
workManagerProvider.workManager
|
||||
.beginUniqueWork("${roomId}_$UPLOAD_AVATAR_WORK", ExistingWorkPolicy.REPLACE, uploadAvatarWork)
|
||||
.enqueue()
|
||||
|
||||
cancelableBag.add(CancelableWork(workManagerProvider.workManager, uploadAvatarWork.id))
|
||||
|
||||
taskExecutor.executorScope.launch(coroutineDispatchers.main) {
|
||||
workManagerProvider.workManager.getWorkInfoByIdLiveData(uploadAvatarWork.id)
|
||||
.observeForever { info ->
|
||||
if (info != null && info.state.isFinished) {
|
||||
val result = WorkerParamsFactory.fromData<UploadAvatarWorker.OutputParams>(info.outputData)
|
||||
cancelableBag.add(
|
||||
sendStateEvent(
|
||||
eventType = EventType.STATE_ROOM_AVATAR,
|
||||
body = mapOf("url" to result?.imageUrl!!),
|
||||
callback = callback,
|
||||
stateKey = null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return cancelableBag
|
||||
}
|
||||
}
|
||||
|
@ -25,10 +25,12 @@ import androidx.core.view.isVisible
|
||||
import androidx.core.widget.ImageViewCompat
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotx.core.extensions.setTextOrHide
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.themes.ThemeUtils
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_profile_action)
|
||||
@ -51,6 +53,12 @@ abstract class ProfileActionItem : VectorEpoxyModel<ProfileActionItem.Holder>()
|
||||
@EpoxyAttribute
|
||||
var accessoryRes: Int = 0
|
||||
|
||||
@EpoxyAttribute
|
||||
var accessoryMatrixItem: MatrixItem? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var avatarRenderer: AvatarRenderer? = null
|
||||
|
||||
@EpoxyAttribute
|
||||
var editable: Boolean = true
|
||||
|
||||
@ -93,6 +101,13 @@ abstract class ProfileActionItem : VectorEpoxyModel<ProfileActionItem.Holder>()
|
||||
holder.secondaryAccessory.isVisible = false
|
||||
}
|
||||
|
||||
if (accessoryMatrixItem != null) {
|
||||
avatarRenderer?.render(accessoryMatrixItem!!, holder.secondaryAccessory)
|
||||
holder.secondaryAccessory.isVisible = true
|
||||
} else {
|
||||
holder.secondaryAccessory.isVisible = false
|
||||
}
|
||||
|
||||
if (editableRes != 0 && editable) {
|
||||
val tintColorSecondary = if (destructive) {
|
||||
tintColor
|
||||
|
@ -19,8 +19,10 @@ package im.vector.riotx.core.epoxy.profiles
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import im.vector.matrix.android.api.util.MatrixItem
|
||||
import im.vector.riotx.core.epoxy.ClickListener
|
||||
import im.vector.riotx.core.epoxy.dividerItem
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
|
||||
fun EpoxyController.buildProfileSection(title: String) {
|
||||
profileSectionItem {
|
||||
@ -41,7 +43,9 @@ fun EpoxyController.buildProfileAction(
|
||||
destructive: Boolean = false,
|
||||
divider: Boolean = true,
|
||||
action: ClickListener? = null,
|
||||
@DrawableRes accessory: Int = 0
|
||||
@DrawableRes accessory: Int = 0,
|
||||
accessoryMatrixItem: MatrixItem? = null,
|
||||
avatarRenderer: AvatarRenderer? = null
|
||||
) {
|
||||
profileActionItem {
|
||||
iconRes(icon)
|
||||
@ -53,6 +57,8 @@ fun EpoxyController.buildProfileAction(
|
||||
destructive(destructive)
|
||||
title(title)
|
||||
accessoryRes(accessory)
|
||||
accessoryMatrixItem(accessoryMatrixItem)
|
||||
avatarRenderer(avatarRenderer)
|
||||
listener { _ ->
|
||||
action?.invoke()
|
||||
}
|
||||
|
@ -17,11 +17,12 @@
|
||||
package im.vector.riotx.features.roomprofile.settings
|
||||
|
||||
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
|
||||
sealed class RoomSettingsAction : VectorViewModelAction {
|
||||
data class SetRoomName(val newName: String) : RoomSettingsAction()
|
||||
data class SetRoomTopic(val newTopic: String) : RoomSettingsAction()
|
||||
data class SetRoomAvatar(val newAvatarUrl: String) : RoomSettingsAction()
|
||||
data class SetRoomAvatar(val image: MultiPickerImageType) : RoomSettingsAction()
|
||||
object EnableEncryption : RoomSettingsAction()
|
||||
object Save : RoomSettingsAction()
|
||||
}
|
||||
|
@ -17,16 +17,19 @@
|
||||
package im.vector.riotx.features.roomprofile.settings
|
||||
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import im.vector.matrix.android.api.util.toMatrixItem
|
||||
import im.vector.riotx.R
|
||||
import im.vector.riotx.core.epoxy.profiles.buildProfileAction
|
||||
import im.vector.riotx.core.epoxy.profiles.buildProfileSection
|
||||
import im.vector.riotx.core.resources.ColorProvider
|
||||
import im.vector.riotx.core.resources.StringProvider
|
||||
import im.vector.riotx.features.form.formEditTextItem
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import javax.inject.Inject
|
||||
|
||||
// TODO Add other feature here (waiting for design)
|
||||
class RoomSettingsController @Inject constructor(
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val stringProvider: StringProvider,
|
||||
colorProvider: ColorProvider
|
||||
) : TypedEpoxyController<RoomSettingsViewState>() {
|
||||
@ -35,6 +38,7 @@ class RoomSettingsController @Inject constructor(
|
||||
fun onEnableEncryptionClicked()
|
||||
fun onNameChanged(name: String)
|
||||
fun onTopicChanged(topic: String)
|
||||
fun onPhotoClicked()
|
||||
}
|
||||
|
||||
private val dividerColor = colorProvider.getColorFromAttribute(R.attr.vctr_list_divider_color)
|
||||
@ -74,6 +78,18 @@ class RoomSettingsController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
buildProfileAction(
|
||||
id = "photo",
|
||||
title = stringProvider.getString(R.string.room_settings_room_photo),
|
||||
subtitle = "",
|
||||
dividerColor = dividerColor,
|
||||
divider = true,
|
||||
editable = true,
|
||||
accessoryMatrixItem = roomSummary.toMatrixItem(),
|
||||
avatarRenderer = avatarRenderer,
|
||||
action = { callback?.onPhotoClicked() }
|
||||
)
|
||||
|
||||
if (roomSummary.isEncrypted) {
|
||||
buildProfileAction(
|
||||
id = "encryption",
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package im.vector.riotx.features.roomprofile.settings
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
@ -34,6 +36,8 @@ import im.vector.riotx.core.platform.VectorBaseFragment
|
||||
import im.vector.riotx.core.utils.toast
|
||||
import im.vector.riotx.features.home.AvatarRenderer
|
||||
import im.vector.riotx.features.roomprofile.RoomProfileArgs
|
||||
import im.vector.riotx.multipicker.MultiPicker
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
import kotlinx.android.synthetic.main.fragment_room_setting_generic.*
|
||||
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
|
||||
import javax.inject.Inject
|
||||
@ -62,7 +66,7 @@ class RoomSettingsFragment @Inject constructor(
|
||||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is RoomSettingsViewEvents.Failure -> showFailure(it.throwable)
|
||||
is RoomSettingsViewEvents.Success -> showSuccess()
|
||||
is RoomSettingsViewEvents.Success -> showSuccess()
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
@ -95,6 +99,17 @@ class RoomSettingsFragment @Inject constructor(
|
||||
renderRoomSummary(viewState)
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(state: RoomSettingsViewState) {
|
||||
waiting_view.isVisible = state.isLoading
|
||||
|
||||
state.roomSummary()?.let {
|
||||
roomSettingsToolbarTitleView.text = it.displayName
|
||||
avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView)
|
||||
}
|
||||
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
override fun onEnableEncryptionClicked() {
|
||||
AlertDialog.Builder(requireActivity())
|
||||
.setTitle(R.string.room_settings_enable_encryption_dialog_title)
|
||||
@ -114,14 +129,27 @@ class RoomSettingsFragment @Inject constructor(
|
||||
viewModel.handle(RoomSettingsAction.SetRoomTopic(topic))
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(state: RoomSettingsViewState) {
|
||||
waiting_view.isVisible = state.isLoading
|
||||
override fun onPhotoClicked() {
|
||||
MultiPicker.get(MultiPicker.IMAGE).single().startWith(this)
|
||||
}
|
||||
|
||||
state.roomSummary()?.let {
|
||||
roomSettingsToolbarTitleView.text = it.displayName
|
||||
avatarRenderer.render(it.toMatrixItem(), roomSettingsToolbarAvatarImageView)
|
||||
private fun onRoomPhotoSelected(selectedImage: MultiPickerImageType) {
|
||||
viewModel.handle(RoomSettingsAction.SetRoomAvatar(selectedImage))
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
MultiPicker.REQUEST_CODE_PICK_IMAGE -> {
|
||||
MultiPicker
|
||||
.get(MultiPicker.IMAGE)
|
||||
.getSelectedFiles(requireContext(), requestCode, resultCode, data)
|
||||
.firstOrNull()?.let {
|
||||
onRoomPhotoSelected(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invalidateOptionsMenu()
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import im.vector.matrix.rx.unwrap
|
||||
import im.vector.riotx.core.platform.VectorViewModel
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Observable
|
||||
import java.util.UUID
|
||||
|
||||
class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: RoomSettingsViewState,
|
||||
private val session: Session)
|
||||
@ -69,17 +70,17 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
|
||||
override fun handle(action: RoomSettingsAction) {
|
||||
when (action) {
|
||||
is RoomSettingsAction.EnableEncryption -> handleEnableEncryption()
|
||||
is RoomSettingsAction.SetRoomName -> setState {
|
||||
copy(
|
||||
newName = action.newName,
|
||||
showSaveAction = shouldShowSaveAction(this)
|
||||
)
|
||||
is RoomSettingsAction.SetRoomName -> {
|
||||
setState { copy(newName = action.newName) }
|
||||
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
|
||||
}
|
||||
is RoomSettingsAction.SetRoomTopic -> setState {
|
||||
copy(
|
||||
newTopic = action.newTopic,
|
||||
showSaveAction = shouldShowSaveAction(this)
|
||||
)
|
||||
is RoomSettingsAction.SetRoomTopic -> {
|
||||
setState { copy(newTopic = action.newTopic) }
|
||||
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
|
||||
}
|
||||
is RoomSettingsAction.SetRoomAvatar -> {
|
||||
setState { copy(newAvatar = action.image) }
|
||||
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
|
||||
}
|
||||
is RoomSettingsAction.Save -> saveSettings()
|
||||
}
|
||||
@ -88,7 +89,8 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
|
||||
private fun shouldShowSaveAction(state: RoomSettingsViewState): Boolean {
|
||||
val summary = state.roomSummary.invoke()
|
||||
return summary?.displayName != state.newName ||
|
||||
summary?.topic != state.newTopic
|
||||
summary?.topic != state.newTopic ||
|
||||
state.newAvatar != null
|
||||
}
|
||||
|
||||
private fun saveSettings() = withState { state ->
|
||||
@ -105,12 +107,18 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
|
||||
operationList.add(room.rx().updateTopic(state.newTopic ?: ""))
|
||||
}
|
||||
|
||||
if (state.newAvatar != null) {
|
||||
operationList.add(room.rx().updateAvatar(state.newAvatar.contentUri, state.newAvatar.displayName ?: UUID.randomUUID().toString()))
|
||||
}
|
||||
|
||||
Observable
|
||||
.fromIterable(operationList)
|
||||
.flatMapCompletable { it }
|
||||
.subscribe(
|
||||
{
|
||||
postLoading(false)
|
||||
setState { copy(newAvatar = null) }
|
||||
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
|
||||
_viewEvents.post(RoomSettingsViewEvents.Success)
|
||||
},
|
||||
{
|
||||
|
@ -21,6 +21,7 @@ import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotx.features.roomprofile.RoomProfileArgs
|
||||
import im.vector.riotx.multipicker.entity.MultiPickerImageType
|
||||
|
||||
data class RoomSettingsViewState(
|
||||
val roomId: String,
|
||||
@ -28,6 +29,7 @@ data class RoomSettingsViewState(
|
||||
val isLoading: Boolean = false,
|
||||
val newName: String? = null,
|
||||
val newTopic: String? = null,
|
||||
val newAvatar: MultiPickerImageType? = null,
|
||||
val showSaveAction: Boolean = false
|
||||
) : MvRxState {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user