This commit is contained in:
Benoit Marty 2020-06-30 15:52:40 +02:00
parent e0ea0c195b
commit cca6d0e967
13 changed files with 88 additions and 87 deletions

View file

@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.room.Room
import im.vector.matrix.android.api.session.room.members.RoomMemberQueryParams
import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary
import im.vector.matrix.android.api.session.room.model.ReadReceipt
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
import im.vector.matrix.android.api.session.room.model.RoomMemberSummary
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
@ -119,7 +120,7 @@ class RxRoom(private val room: Room) {
room.updateCanonicalAlias(alias, it)
}
fun updateHistoryReadability(readability: String) = completableBuilder<Unit> {
fun updateHistoryReadability(readability: RoomHistoryVisibility): Completable = completableBuilder<Unit> {
room.updateHistoryReadability(readability, it)
}

View file

@ -21,6 +21,7 @@ import androidx.lifecycle.LiveData
import im.vector.matrix.android.api.MatrixCallback
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.model.RoomHistoryVisibility
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.Optional
@ -50,7 +51,7 @@ interface StateService {
/**
* Update the history readability of the room
*/
fun updateHistoryReadability(readability: String, callback: MatrixCallback<Unit>): Cancelable
fun updateHistoryReadability(readability: RoomHistoryVisibility, callback: MatrixCallback<Unit>): Cancelable
/**
* Update the avatar of the room

View file

@ -28,8 +28,6 @@ import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.internal.database.model.UserThreePidEntity
import im.vector.matrix.android.internal.di.SessionDatabase
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.content.FileUploader
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
@ -38,12 +36,8 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import io.realm.kotlin.where
import javax.inject.Inject
private const val UPLOAD_AVATAR_WORK = "UPLOAD_AVATAR_WORK"
internal class DefaultProfileService @Inject constructor(private val taskExecutor: TaskExecutor,
@SessionDatabase private val monarchy: Monarchy,
@SessionId private val sessionId: String,
private val workManagerProvider: WorkManagerProvider,
private val coroutineDispatchers: MatrixCoroutineDispatchers,
private val refreshUserThreePidsTask: RefreshUserThreePidsTask,
private val getProfileInfoTask: GetProfileInfoTask,

View file

@ -24,6 +24,7 @@ import im.vector.matrix.android.api.MatrixCallback
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.events.model.EventType
import im.vector.matrix.android.api.session.room.model.RoomHistoryVisibility
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.JsonDict
@ -35,8 +36,6 @@ import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.task.launchToCallback
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
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,
@ -121,7 +120,7 @@ internal class DefaultStateService @AssistedInject constructor(@Assisted private
)
}
override fun updateHistoryReadability(readability: String, callback: MatrixCallback<Unit>): Cancelable {
override fun updateHistoryReadability(readability: RoomHistoryVisibility, callback: MatrixCallback<Unit>): Cancelable {
return sendStateEvent(
eventType = EventType.STATE_ROOM_HISTORY_VISIBILITY,
body = mapOf("history_visibility" to readability),

View file

@ -97,15 +97,15 @@ class BigImageViewerActivity : VectorBaseActivity() {
}
private fun showAvatarSelector() {
AlertDialog
.Builder(this)
AlertDialog.Builder(this)
.setItems(arrayOf(
stringProvider.getString(R.string.attachment_type_camera),
stringProvider.getString(R.string.attachment_type_gallery)
)) { dialog, which ->
dialog.cancel()
onAvatarTypeSelected(isCamera = (which == 0))
}.show()
}
.show()
}
private var avatarCameraUri: Uri? = null

View file

@ -46,7 +46,6 @@ import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.core.intent.getFilenameFromUri
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.resources.ColorProvider
import im.vector.riotx.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
import im.vector.riotx.core.utils.allGranted
@ -78,8 +77,7 @@ data class RoomProfileArgs(
class RoomProfileFragment @Inject constructor(
private val roomProfileController: RoomProfileController,
private val avatarRenderer: AvatarRenderer,
val roomProfileViewModelFactory: RoomProfileViewModel.Factory,
val colorProvider: ColorProvider
val roomProfileViewModelFactory: RoomProfileViewModel.Factory
) : VectorBaseFragment(), RoomProfileController.Callback {
private val roomProfileArgs: RoomProfileArgs by args()
@ -253,15 +251,15 @@ class RoomProfileFragment @Inject constructor(
}
private fun showAvatarSelector() {
AlertDialog
.Builder(requireContext())
AlertDialog.Builder(requireContext())
.setItems(arrayOf(
getString(R.string.attachment_type_camera),
getString(R.string.attachment_type_gallery)
)) { dialog, which ->
dialog.cancel()
onAvatarTypeSelected(isCamera = (which == 0))
}.show()
}
.show()
}
private var avatarCameraUri: Uri? = null

View file

@ -68,10 +68,12 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted private val ini
val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable()
powerLevelsContentLive.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
setState { copy(canChangeAvatar = powerLevelsHelper.isUserAbleToChangeRoomAvatar(session.myUserId)) }
}.disposeOnClear()
powerLevelsContentLive
.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
setState { copy(canChangeAvatar = powerLevelsHelper.isUserAbleToChangeRoomAvatar(session.myUserId)) }
}
.disposeOnClear()
}
override fun handle(action: RoomProfileAction) = when (action) {
@ -111,11 +113,13 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted private val ini
private fun handleChangeAvatar(action: RoomProfileAction.ChangeRoomAvatar) {
_viewEvents.post(RoomProfileViewEvents.Loading())
room.rx().updateAvatar(action.uri, action.fileName ?: UUID.randomUUID().toString())
.subscribe({
_viewEvents.post(RoomProfileViewEvents.OnChangeAvatarSuccess)
}, {
_viewEvents.post(RoomProfileViewEvents.Failure(it))
})
.subscribe(
{
_viewEvents.post(RoomProfileViewEvents.OnChangeAvatarSuccess)
},
{
_viewEvents.post(RoomProfileViewEvents.Failure(it))
})
.disposeOnClear()
}
}

View file

@ -86,7 +86,7 @@ class RoomSettingsController @Inject constructor(
formEditTextItem {
id("alias")
enabled(data.actionPermissions.canChangeCanonicalAlias)
value(data.newAlias ?: roomSummary.canonicalAlias)
value(data.newCanonicalAlias ?: roomSummary.canonicalAlias)
hint(stringProvider.getString(R.string.room_settings_addresses_add_new_address))
onTextChange { text ->

View file

@ -34,7 +34,6 @@ import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.utils.toast
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.roomprofile.RoomProfileArgs
@ -45,8 +44,7 @@ import javax.inject.Inject
class RoomSettingsFragment @Inject constructor(
val viewModelFactory: RoomSettingsViewModel.Factory,
private val controller: RoomSettingsController,
private val avatarRenderer: AvatarRenderer,
private val stringProvider: StringProvider
private val avatarRenderer: AvatarRenderer
) : VectorBaseFragment(), RoomSettingsController.Callback {
private val viewModel: RoomSettingsViewModel by fragmentViewModel()
@ -154,12 +152,13 @@ class RoomSettingsFragment @Inject constructor(
return@withState
}
// TODO Create a formatter for this enum, it's done 3 times in the project
private fun formatHistoryVisibility(historyVisibility: RoomHistoryVisibility): String {
return when (historyVisibility) {
RoomHistoryVisibility.SHARED -> stringProvider.getString(R.string.notice_room_visibility_shared)
RoomHistoryVisibility.INVITED -> stringProvider.getString(R.string.notice_room_visibility_invited)
RoomHistoryVisibility.JOINED -> stringProvider.getString(R.string.notice_room_visibility_joined)
RoomHistoryVisibility.WORLD_READABLE -> stringProvider.getString(R.string.notice_room_visibility_world_readable)
RoomHistoryVisibility.SHARED -> getString(R.string.notice_room_visibility_shared)
RoomHistoryVisibility.INVITED -> getString(R.string.notice_room_visibility_invited)
RoomHistoryVisibility.JOINED -> getString(R.string.notice_room_visibility_joined)
RoomHistoryVisibility.WORLD_READABLE -> getString(R.string.notice_room_visibility_world_readable)
}
}

View file

@ -27,11 +27,11 @@ import im.vector.matrix.android.api.session.events.model.EventType
import im.vector.matrix.android.api.session.room.powerlevels.PowerLevelsHelper
import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.features.powerlevel.PowerLevelsObservableFactory
import io.reactivex.Completable
import io.reactivex.Observable
import java.util.Locale
class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: RoomSettingsViewState,
private val session: Session)
@ -55,6 +55,30 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
init {
observeRoomSummary()
observeState()
}
private fun observeState() {
selectSubscribe(
RoomSettingsViewState::newName,
RoomSettingsViewState::newCanonicalAlias,
RoomSettingsViewState::newTopic,
RoomSettingsViewState::newHistoryVisibility,
RoomSettingsViewState::roomSummary) { newName,
newAlias,
newTopic,
newHistoryVisibility,
asyncSummary ->
val summary = asyncSummary()
setState {
copy(
showSaveAction = summary?.displayName != newName
|| summary?.topic != newTopic
|| summary?.canonicalAlias != newAlias
|| newHistoryVisibility != null
)
}
}
}
private fun observeRoomSummary() {
@ -67,53 +91,35 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
roomSummary = async,
newName = roomSummary?.displayName,
newTopic = roomSummary?.topic,
newAlias = roomSummary?.canonicalAlias
newCanonicalAlias = roomSummary?.canonicalAlias
)
}
val powerLevelsContentLive = PowerLevelsObservableFactory(room).createObservable()
powerLevelsContentLive.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
val permissions = RoomSettingsViewState.ActionPermissions(
canChangeName = powerLevelsHelper.isUserAbleToChangeRoomName(session.myUserId),
canChangeTopic = powerLevelsHelper.isUserAbleToChangeRoomTopic(session.myUserId),
canChangeCanonicalAlias = powerLevelsHelper.isUserAbleToChangeRoomCanonicalAlias(session.myUserId),
canChangeHistoryReadability = powerLevelsHelper.isUserAbleToChangeRoomHistoryReadability(session.myUserId)
)
setState { copy(actionPermissions = permissions) }
}.disposeOnClear()
powerLevelsContentLive
.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
val permissions = RoomSettingsViewState.ActionPermissions(
canChangeName = powerLevelsHelper.isUserAbleToChangeRoomName(session.myUserId),
canChangeTopic = powerLevelsHelper.isUserAbleToChangeRoomTopic(session.myUserId),
canChangeCanonicalAlias = powerLevelsHelper.isUserAbleToChangeRoomCanonicalAlias(session.myUserId),
canChangeHistoryReadability = powerLevelsHelper.isUserAbleToChangeRoomHistoryReadability(session.myUserId)
)
setState { copy(actionPermissions = permissions) }
}
.disposeOnClear()
}
override fun handle(action: RoomSettingsAction) {
when (action) {
is RoomSettingsAction.EnableEncryption -> handleEnableEncryption()
is RoomSettingsAction.SetRoomName -> {
setState { copy(newName = action.newName) }
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
}
is RoomSettingsAction.SetRoomTopic -> {
setState { copy(newTopic = action.newTopic) }
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
}
is RoomSettingsAction.SetRoomHistoryVisibility -> {
setState { copy(newHistoryVisibility = action.visibility) }
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
}
is RoomSettingsAction.SetRoomAlias -> {
setState { copy(newAlias = action.alias) }
setState { copy(showSaveAction = shouldShowSaveAction(this)) }
}
is RoomSettingsAction.SetRoomName -> setState { copy(newName = action.newName) }
is RoomSettingsAction.SetRoomTopic -> setState { copy(newTopic = action.newTopic) }
is RoomSettingsAction.SetRoomHistoryVisibility -> setState { copy(newHistoryVisibility = action.visibility) }
is RoomSettingsAction.SetRoomAlias -> setState { copy(newCanonicalAlias = action.alias) }
is RoomSettingsAction.Save -> saveSettings()
}
}
private fun shouldShowSaveAction(state: RoomSettingsViewState): Boolean {
val summary = state.roomSummary.invoke()
return summary?.displayName != state.newName
|| summary?.topic != state.newTopic
|| summary?.canonicalAlias != state.newAlias
|| state.newHistoryVisibility != null
}.exhaustive
}
private fun saveSettings() = withState { state ->
@ -130,13 +136,13 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
operationList.add(room.rx().updateTopic(state.newTopic ?: ""))
}
if (state.newAlias != null && summary?.canonicalAlias != state.newAlias) {
operationList.add(room.rx().addRoomAlias(state.newAlias))
operationList.add(room.rx().updateCanonicalAlias(state.newAlias))
if (state.newCanonicalAlias != null && summary?.canonicalAlias != state.newCanonicalAlias.takeIf { it.isNotEmpty() }) {
operationList.add(room.rx().addRoomAlias(state.newCanonicalAlias))
operationList.add(room.rx().updateCanonicalAlias(state.newCanonicalAlias))
}
if (state.newHistoryVisibility != null) {
operationList.add(room.rx().updateHistoryReadability(state.newHistoryVisibility.name.toLowerCase(Locale.ROOT)))
operationList.add(room.rx().updateHistoryReadability(state.newHistoryVisibility))
}
Observable
@ -146,7 +152,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
{
postLoading(false)
setState { copy(newHistoryVisibility = null) }
setState { copy(showSaveAction = false) }
_viewEvents.post(RoomSettingsViewEvents.Success)
},
{

View file

@ -32,7 +32,7 @@ data class RoomSettingsViewState(
val newName: String? = null,
val newTopic: String? = null,
val newHistoryVisibility: RoomHistoryVisibility? = null,
val newAlias: String? = null,
val newCanonicalAlias: String? = null,
val showSaveAction: Boolean = false,
val actionPermissions: ActionPermissions = ActionPermissions()
) : MvRxState {

View file

@ -32,11 +32,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:background="?attr/colorAccent"
app:layout_constraintBottom_toBottomOf="@id/formTextInputTextInputLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/formTextInputTextInputLayout"
android:background="?attr/colorAccent"
tools:text="Add"/>
tools:text="Add" />
<View
android:id="@+id/formTextInputDivider"

View file

@ -3,9 +3,9 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_attachment_type_selector"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:background="@drawable/bg_attachment_type_selector"
android:orientation="vertical"
android:paddingTop="16dp"
android:paddingBottom="16dp">
@ -28,9 +28,9 @@
<ImageButton
android:id="@+id/avatarCameraButton"
style="@style/AttachmentTypeSelectorButton"
android:src="@drawable/ic_attachment_camera_white_24dp"
android:contentDescription="@string/attachment_type_camera"
tools:background="@color/colorAccent" />
android:src="@drawable/ic_attachment_camera_white_24dp"
tools:background="@color/riotx_accent" />
<TextView
style="@style/AttachmentTypeSelectorLabel"
@ -50,9 +50,9 @@
<ImageButton
android:id="@+id/avatarGalleryButton"
style="@style/AttachmentTypeSelectorButton"
android:src="@drawable/ic_attachment_gallery_white_24dp"
android:contentDescription="@string/attachment_type_gallery"
tools:background="@color/colorAccent" />
android:src="@drawable/ic_attachment_gallery_white_24dp"
tools:background="@color/riotx_accent" />
<TextView
style="@style/AttachmentTypeSelectorLabel"