Move "Enable Encryption" from room setting screen to room profile screen (#2394)

This commit is contained in:
Benoit Marty 2020-11-16 14:56:42 +01:00 committed by Benoit Marty
parent 0022777a4f
commit 75c105a400
13 changed files with 99 additions and 63 deletions

View File

@ -8,6 +8,7 @@ Improvements 🙌:
- Open an existing DM instead of creating a new one (#2319) - Open an existing DM instead of creating a new one (#2319)
- Ask for explicit user consent to send their contact details to the identity server (#2375) - Ask for explicit user consent to send their contact details to the identity server (#2375)
- Handle events of type "m.room.server_acl" (#890) - Handle events of type "m.room.server_acl" (#890)
- Move "Enable Encryption" from room setting screen to room profile screen (#2394)
Bugfix 🐛: Bugfix 🐛:
- Fix issue when restoring draft after sharing (#2287) - Fix issue when restoring draft after sharing (#2287)

View File

@ -21,6 +21,7 @@ import im.vector.app.core.platform.VectorViewModelAction
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
sealed class RoomProfileAction : VectorViewModelAction { sealed class RoomProfileAction : VectorViewModelAction {
object EnableEncryption : RoomProfileAction()
object LeaveRoom : RoomProfileAction() object LeaveRoom : RoomProfileAction()
data class ChangeRoomNotificationState(val notificationState: RoomNotificationState) : RoomProfileAction() data class ChangeRoomNotificationState(val notificationState: RoomNotificationState) : RoomProfileAction()
object ShareRoomProfile : RoomProfileAction() object ShareRoomProfile : RoomProfileAction()

View File

@ -28,6 +28,7 @@ import im.vector.app.core.ui.list.genericFooterItem
import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.home.ShortcutCreator
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import javax.inject.Inject import javax.inject.Inject
class RoomProfileController @Inject constructor( class RoomProfileController @Inject constructor(
@ -43,6 +44,7 @@ class RoomProfileController @Inject constructor(
interface Callback { interface Callback {
fun onLearnMoreClicked() fun onLearnMoreClicked()
fun onEnableEncryptionClicked()
fun onMemberListClicked() fun onMemberListClicked()
fun onBannedMemberListClicked() fun onBannedMemberListClicked()
fun onNotificationsClicked() fun onNotificationsClicked()
@ -84,6 +86,7 @@ class RoomProfileController @Inject constructor(
centered(false) centered(false)
text(stringProvider.getString(learnMoreSubtitle)) text(stringProvider.getString(learnMoreSubtitle))
} }
buildEncryptionAction(data.actionPermissions, roomSummary)
// More // More
buildProfileSection(stringProvider.getString(R.string.room_profile_section_more)) buildProfileSection(stringProvider.getString(R.string.room_profile_section_more))
@ -171,4 +174,29 @@ class RoomProfileController @Inject constructor(
) )
} }
} }
private fun buildEncryptionAction(actionPermissions: RoomProfileViewState.ActionPermissions, roomSummary: RoomSummary) {
if (!roomSummary.isEncrypted) {
if (actionPermissions.canEnableEncryption) {
buildProfileAction(
id = "enableEncryption",
title = stringProvider.getString(R.string.room_settings_enable_encryption),
dividerColor = dividerColor,
icon = R.drawable.ic_shield_black,
divider = false,
editable = false,
action = { callback?.onEnableEncryptionClicked() }
)
} else {
buildProfileAction(
id = "enableEncryption",
title = stringProvider.getString(R.string.room_settings_enable_encryption_no_permission),
dividerColor = dividerColor,
icon = R.drawable.ic_shield_black,
divider = false,
editable = false
)
}
}
}
} }

View File

@ -49,6 +49,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA
import im.vector.app.features.media.BigImageViewerActivity import im.vector.app.features.media.BigImageViewerActivity
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_matrix_profile.* import kotlinx.android.synthetic.main.fragment_matrix_profile.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import kotlinx.android.synthetic.main.view_stub_room_profile_header.* import kotlinx.android.synthetic.main.view_stub_room_profile_header.*
import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
@ -87,6 +88,7 @@ class RoomProfileFragment @Inject constructor(
it.layoutResource = R.layout.view_stub_room_profile_header it.layoutResource = R.layout.view_stub_room_profile_header
it.inflate() it.inflate()
} }
setupWaitingView()
setupToolbar(matrixProfileToolbar) setupToolbar(matrixProfileToolbar)
setupRecyclerView() setupRecyclerView()
appBarStateChangeListener = MatrixItemAppBarStateChangeListener( appBarStateChangeListener = MatrixItemAppBarStateChangeListener(
@ -111,6 +113,11 @@ class RoomProfileFragment @Inject constructor(
setupLongClicks() setupLongClicks()
} }
private fun setupWaitingView() {
waiting_view_status_text.setText(R.string.please_wait)
waiting_view_status_text.isVisible = true
}
private fun setupLongClicks() { private fun setupLongClicks() {
roomProfileNameView.copyOnLongClick() roomProfileNameView.copyOnLongClick()
roomProfileAliasView.copyOnLongClick() roomProfileAliasView.copyOnLongClick()
@ -155,6 +162,8 @@ class RoomProfileFragment @Inject constructor(
} }
override fun invalidate() = withState(roomProfileViewModel) { state -> override fun invalidate() = withState(roomProfileViewModel) { state ->
waiting_view.isVisible = state.isLoading
state.roomSummary()?.also { state.roomSummary()?.also {
if (it.membership.isLeft()) { if (it.membership.isLeft()) {
Timber.w("The room has been left") Timber.w("The room has been left")
@ -187,6 +196,17 @@ class RoomProfileFragment @Inject constructor(
vectorBaseActivity.notImplemented() vectorBaseActivity.notImplemented()
} }
override fun onEnableEncryptionClicked() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.room_settings_enable_encryption_dialog_title)
.setMessage(R.string.room_settings_enable_encryption_dialog_content)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.room_settings_enable_encryption_dialog_submit) { _, _ ->
roomProfileViewModel.handle(RoomProfileAction.EnableEncryption)
}
.show()
}
override fun onMemberListClicked() { override fun onMemberListClicked() {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomMembers) roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomMembers)
} }

View File

@ -28,12 +28,15 @@ import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.VectorViewModel
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.home.ShortcutCreator
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixCallback
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams import org.matrix.android.sdk.api.session.room.members.roomMemberQueryParams
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.rx.RxRoom import org.matrix.android.sdk.rx.RxRoom
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import org.matrix.android.sdk.rx.unwrap import org.matrix.android.sdk.rx.unwrap
@ -65,6 +68,7 @@ class RoomProfileViewModel @AssistedInject constructor(
val rxRoom = room.rx() val rxRoom = room.rx()
observeRoomSummary(rxRoom) observeRoomSummary(rxRoom)
observeBannedRoomMembers(rxRoom) observeBannedRoomMembers(rxRoom)
observePermissions()
} }
private fun observeRoomSummary(rxRoom: RxRoom) { private fun observeRoomSummary(rxRoom: RxRoom) {
@ -82,8 +86,22 @@ class RoomProfileViewModel @AssistedInject constructor(
} }
} }
private fun observePermissions() {
PowerLevelsObservableFactory(room)
.createObservable()
.subscribe {
val powerLevelsHelper = PowerLevelsHelper(it)
val permissions = RoomProfileViewState.ActionPermissions(
canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
)
setState { copy(actionPermissions = permissions) }
}
.disposeOnClear()
}
override fun handle(action: RoomProfileAction) { override fun handle(action: RoomProfileAction) {
when (action) { when (action) {
is RoomProfileAction.EnableEncryption -> handleEnableEncryption()
RoomProfileAction.LeaveRoom -> handleLeaveRoom() RoomProfileAction.LeaveRoom -> handleLeaveRoom()
is RoomProfileAction.ChangeRoomNotificationState -> handleChangeNotificationMode(action) is RoomProfileAction.ChangeRoomNotificationState -> handleChangeNotificationMode(action)
is RoomProfileAction.ShareRoomProfile -> handleShareRoomProfile() is RoomProfileAction.ShareRoomProfile -> handleShareRoomProfile()
@ -91,6 +109,24 @@ class RoomProfileViewModel @AssistedInject constructor(
}.exhaustive }.exhaustive
} }
private fun handleEnableEncryption() {
postLoading(true)
viewModelScope.launch {
val result = runCatching { room.enableEncryption() }
postLoading(false)
result.onFailure { failure ->
_viewEvents.post(RoomProfileViewEvents.Failure(failure))
}
}
}
private fun postLoading(isLoading: Boolean) {
setState {
copy(isLoading = isLoading)
}
}
private fun handleCreateShortcut() { private fun handleCreateShortcut() {
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
withState { state -> withState { state ->

View File

@ -26,8 +26,14 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
data class RoomProfileViewState( data class RoomProfileViewState(
val roomId: String, val roomId: String,
val roomSummary: Async<RoomSummary> = Uninitialized, val roomSummary: Async<RoomSummary> = Uninitialized,
val bannedMembership: Async<List<RoomMemberSummary>> = Uninitialized val bannedMembership: Async<List<RoomMemberSummary>> = Uninitialized,
val actionPermissions: ActionPermissions = ActionPermissions(),
val isLoading: Boolean = false
) : MvRxState { ) : MvRxState {
constructor(args: RoomProfileArgs) : this(roomId = args.roomId) constructor(args: RoomProfileArgs) : this(roomId = args.roomId)
data class ActionPermissions(
val canEnableEncryption: Boolean = false
)
} }

View File

@ -25,7 +25,6 @@ sealed class RoomSettingsAction : VectorViewModelAction {
data class SetRoomTopic(val newTopic: String) : RoomSettingsAction() data class SetRoomTopic(val newTopic: String) : RoomSettingsAction()
data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction() data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction()
data class SetRoomCanonicalAlias(val newCanonicalAlias: String) : RoomSettingsAction() data class SetRoomCanonicalAlias(val newCanonicalAlias: String) : RoomSettingsAction()
object EnableEncryption : RoomSettingsAction()
object Save : RoomSettingsAction() object Save : RoomSettingsAction()
object Cancel : RoomSettingsAction() object Cancel : RoomSettingsAction()
} }

View File

@ -29,7 +29,6 @@ import im.vector.app.features.home.room.detail.timeline.format.RoomHistoryVisibi
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toModel
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.util.toMatrixItem import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject import javax.inject.Inject
@ -44,7 +43,6 @@ class RoomSettingsController @Inject constructor(
// Delete the avatar, or cancel an avatar change // Delete the avatar, or cancel an avatar change
fun onAvatarDelete() fun onAvatarDelete()
fun onAvatarChange() fun onAvatarChange()
fun onEnableEncryptionClicked()
fun onNameChanged(name: String) fun onNameChanged(name: String)
fun onTopicChanged(topic: String) fun onTopicChanged(topic: String)
fun onHistoryVisibilityClicked() fun onHistoryVisibilityClicked()
@ -130,33 +128,6 @@ class RoomSettingsController @Inject constructor(
editable = data.actionPermissions.canChangeHistoryReadability, editable = data.actionPermissions.canChangeHistoryReadability,
action = { if (data.actionPermissions.canChangeHistoryReadability) callback?.onHistoryVisibilityClicked() } action = { if (data.actionPermissions.canChangeHistoryReadability) callback?.onHistoryVisibilityClicked() }
) )
buildEncryptionAction(data.actionPermissions, roomSummary)
}
private fun buildEncryptionAction(actionPermissions: RoomSettingsViewState.ActionPermissions, roomSummary: RoomSummary) {
if (!actionPermissions.canEnableEncryption) {
return
}
if (roomSummary.isEncrypted) {
buildProfileAction(
id = "encryption",
title = stringProvider.getString(R.string.room_settings_addresses_e2e_enabled),
dividerColor = dividerColor,
divider = false,
editable = false
)
} else {
buildProfileAction(
id = "encryption",
title = stringProvider.getString(R.string.room_settings_enable_encryption),
subtitle = stringProvider.getString(R.string.room_settings_enable_encryption_warning),
dividerColor = dividerColor,
divider = false,
editable = true,
action = { callback?.onEnableEncryptionClicked() }
)
}
} }
private fun formatRoomHistoryVisibilityEvent(event: Event): String? { private fun formatRoomHistoryVisibilityEvent(event: Event): String? {

View File

@ -127,17 +127,6 @@ class RoomSettingsFragment @Inject constructor(
invalidateOptionsMenu() invalidateOptionsMenu()
} }
override fun onEnableEncryptionClicked() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.room_settings_enable_encryption_dialog_title)
.setMessage(R.string.room_settings_enable_encryption_dialog_content)
.setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.room_settings_enable_encryption_dialog_submit) { _, _ ->
viewModel.handle(RoomSettingsAction.EnableEncryption)
}
.show()
}
override fun onNameChanged(name: String) { override fun onNameChanged(name: String) {
viewModel.handle(RoomSettingsAction.SetRoomName(name)) viewModel.handle(RoomSettingsAction.SetRoomName(name))
} }

View File

@ -17,7 +17,6 @@
package im.vector.app.features.roomprofile.settings package im.vector.app.features.roomprofile.settings
import androidx.core.net.toFile import androidx.core.net.toFile
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext import com.airbnb.mvrx.ViewModelContext
@ -28,7 +27,6 @@ import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import io.reactivex.Completable import io.reactivex.Completable
import io.reactivex.Observable import io.reactivex.Observable
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.QueryStringValue
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
@ -118,8 +116,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true,
EventType.STATE_ROOM_CANONICAL_ALIAS), EventType.STATE_ROOM_CANONICAL_ALIAS),
canChangeHistoryReadability = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, canChangeHistoryReadability = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true,
EventType.STATE_ROOM_HISTORY_VISIBILITY), EventType.STATE_ROOM_HISTORY_VISIBILITY)
canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION)
) )
setState { copy(actionPermissions = permissions) } setState { copy(actionPermissions = permissions) }
} }
@ -142,7 +139,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
override fun handle(action: RoomSettingsAction) { override fun handle(action: RoomSettingsAction) {
when (action) { when (action) {
is RoomSettingsAction.EnableEncryption -> handleEnableEncryption()
is RoomSettingsAction.SetAvatarAction -> handleSetAvatarAction(action) is RoomSettingsAction.SetAvatarAction -> handleSetAvatarAction(action)
is RoomSettingsAction.SetRoomName -> setState { copy(newName = action.newName) } is RoomSettingsAction.SetRoomName -> setState { copy(newName = action.newName) }
is RoomSettingsAction.SetRoomTopic -> setState { copy(newTopic = action.newTopic) } is RoomSettingsAction.SetRoomTopic -> setState { copy(newTopic = action.newTopic) }
@ -226,18 +222,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState:
) )
} }
private fun handleEnableEncryption() {
postLoading(true)
viewModelScope.launch {
val result = runCatching { room.enableEncryption() }
postLoading(false)
result.onFailure { failure ->
_viewEvents.post(RoomSettingsViewEvents.Failure(failure))
}
}
}
private fun postLoading(isLoading: Boolean) { private fun postLoading(isLoading: Boolean) {
setState { setState {
copy(isLoading = isLoading) copy(isLoading = isLoading)

View File

@ -47,8 +47,7 @@ data class RoomSettingsViewState(
val canChangeName: Boolean = false, val canChangeName: Boolean = false,
val canChangeTopic: Boolean = false, val canChangeTopic: Boolean = false,
val canChangeCanonicalAlias: Boolean = false, val canChangeCanonicalAlias: Boolean = false,
val canChangeHistoryReadability: Boolean = false, val canChangeHistoryReadability: Boolean = false
val canEnableEncryption: Boolean = false
) )
sealed class AvatarAction { sealed class AvatarAction {

View File

@ -95,7 +95,6 @@
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
@ -105,4 +104,6 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/item_profile_action" /> tools:listitem="@layout/item_profile_action" />
<include layout="@layout/merge_overlay_waiting_view" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -2200,7 +2200,8 @@
<!-- Title for category in the settings which affect the behavior of the message editor (ex: enable Markdown, send typing notification, etc.) --> <!-- Title for category in the settings which affect the behavior of the message editor (ex: enable Markdown, send typing notification, etc.) -->
<string name="settings_category_composer">Message editor</string> <string name="settings_category_composer">Message editor</string>
<string name="room_settings_enable_encryption">Enable end-to-end encryption</string> <string name="room_settings_enable_encryption">Enable end-to-end encryption…</string>
<string name="room_settings_enable_encryption_no_permission">You don\'t have permission to enable encryption in this room.</string>
<string name="room_settings_enable_encryption_warning">Once enabled, encryption cannot be disabled.</string> <string name="room_settings_enable_encryption_warning">Once enabled, encryption cannot be disabled.</string>
<string name="room_settings_enable_encryption_dialog_title">Enable encryption?</string> <string name="room_settings_enable_encryption_dialog_title">Enable encryption?</string>