Skip to content
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

Room Settings: Name, Topic, Photo, Aliases, History Visibility #1464

Merged
merged 29 commits into from
Jun 30, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
05e8482
Room name and topic fields added to form.
onurays Jun 9, 2020
bfebaa5
Show/hide save action button dynamically.
onurays Jun 10, 2020
a6e4a32
Chain all operations to save settings.
onurays Jun 10, 2020
52eec06
Updating room avatar is implemented.
onurays Jun 12, 2020
e1a12f4
Show current history readability.
onurays Jun 14, 2020
f5790e5
Implementation of room history readability.
onurays Jun 22, 2020
762dd1d
Implementation of canonical alias.
onurays Jun 23, 2020
1f30cf4
Check if user have enough power level to change settings.
onurays Jun 23, 2020
7f2ce91
Add camera and gallery options to set room avatar.
onurays Jun 24, 2020
ef1ae41
Change room avatar in BigImageViewer.
onurays Jun 24, 2020
8787f5d
Remove room avatar item from room settings.
onurays Jun 24, 2020
a03f69f
Check if user has enough power level to change room avatar.
onurays Jun 24, 2020
16bd642
Implementation of updating user avatar.
onurays Jun 25, 2020
e0e4cf3
Code review fixes.
onurays Jun 29, 2020
a93cbf3
Lint fix.
onurays Jun 29, 2020
56f8e52
Simplify uploading room and user avatar.
onurays Jun 29, 2020
512e4f0
Create UCropHelper with default settings.
onurays Jun 29, 2020
ad084e1
Use simple dialog for avatar selection.
onurays Jun 29, 2020
32721ca
Code review fix.
onurays Jun 29, 2020
4d6ba5a
Check permission before triggering history readability click action.
onurays Jun 29, 2020
2650453
Add room alias first before setting the canonical alias.
onurays Jun 29, 2020
5f788d9
Use AlertDialog from v7 compat lib.
onurays Jun 29, 2020
b3d4d20
Check permission before trying to reach Camera.
onurays Jun 30, 2020
e0ea0c1
Hide save action after saving completed.
onurays Jun 30, 2020
cca6d0e
Cleanup
bmarty Jun 30, 2020
ff0b922
Create RoomHistoryVisibilityFormatter
bmarty Jun 30, 2020
da472ea
Use name instead of computed displayName
bmarty Jun 30, 2020
e658ef1
Fix issue with save action visibility
bmarty Jun 30, 2020
962e11a
Onuray's remark :)
bmarty Jun 30, 2020
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 @@ -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
Expand Down Expand Up @@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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))
})
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We may put the last parentheses to the new line? :)

Copy link
Member

Choose a reason for hiding this comment

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

Done

.disposeOnClear()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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() {
Expand All @@ -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 ->
Expand All @@ -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
Expand All @@ -146,7 +152,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
{
postLoading(false)
setState { copy(newHistoryVisibility = null) }
setState { copy(showSaveAction = false) }
_viewEvents.post(RoomSettingsViewEvents.Success)
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading