diff --git a/CHANGES.md b/CHANGES.md index 936e6b0ffe..3ac90b4c71 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Improvements 🙌: - 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) - Handle events of type "m.room.server_acl" (#890) + - Move "Enable Encryption" from room setting screen to room profile screen (#2394) Bugfix 🐛: - Fix issue when restoring draft after sharing (#2287) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt index 85bc8773a5..073d30ff8e 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileAction.kt @@ -21,6 +21,7 @@ import im.vector.app.core.platform.VectorViewModelAction import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState sealed class RoomProfileAction : VectorViewModelAction { + object EnableEncryption : RoomProfileAction() object LeaveRoom : RoomProfileAction() data class ChangeRoomNotificationState(val notificationState: RoomNotificationState) : RoomProfileAction() object ShareRoomProfile : RoomProfileAction() diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt index 7dc744da31..891d15d04f 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileController.kt @@ -28,6 +28,7 @@ import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.features.home.ShortcutCreator import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.api.crypto.RoomEncryptionTrustLevel +import org.matrix.android.sdk.api.session.room.model.RoomSummary import javax.inject.Inject class RoomProfileController @Inject constructor( @@ -43,6 +44,7 @@ class RoomProfileController @Inject constructor( interface Callback { fun onLearnMoreClicked() + fun onEnableEncryptionClicked() fun onMemberListClicked() fun onBannedMemberListClicked() fun onNotificationsClicked() @@ -84,6 +86,7 @@ class RoomProfileController @Inject constructor( centered(false) text(stringProvider.getString(learnMoreSubtitle)) } + buildEncryptionAction(data.actionPermissions, roomSummary) // 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 + ) + } + } + } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 5bd121d49b..bab64aebe9 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -49,6 +49,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.media.BigImageViewerActivity import kotlinx.android.parcel.Parcelize 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 org.matrix.android.sdk.api.session.room.notification.RoomNotificationState 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.inflate() } + setupWaitingView() setupToolbar(matrixProfileToolbar) setupRecyclerView() appBarStateChangeListener = MatrixItemAppBarStateChangeListener( @@ -111,6 +113,11 @@ class RoomProfileFragment @Inject constructor( setupLongClicks() } + private fun setupWaitingView() { + waiting_view_status_text.setText(R.string.please_wait) + waiting_view_status_text.isVisible = true + } + private fun setupLongClicks() { roomProfileNameView.copyOnLongClick() roomProfileAliasView.copyOnLongClick() @@ -155,6 +162,8 @@ class RoomProfileFragment @Inject constructor( } override fun invalidate() = withState(roomProfileViewModel) { state -> + waiting_view.isVisible = state.isLoading + state.roomSummary()?.also { if (it.membership.isLeft()) { Timber.w("The room has been left") @@ -187,6 +196,17 @@ class RoomProfileFragment @Inject constructor( 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() { roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomMembers) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt index a78bf472d6..ec772ffcaa 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewModel.kt @@ -28,12 +28,15 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.ShortcutCreator +import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixCallback 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.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.rx import org.matrix.android.sdk.rx.unwrap @@ -65,6 +68,7 @@ class RoomProfileViewModel @AssistedInject constructor( val rxRoom = room.rx() observeRoomSummary(rxRoom) observeBannedRoomMembers(rxRoom) + observePermissions() } 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) { when (action) { + is RoomProfileAction.EnableEncryption -> handleEnableEncryption() RoomProfileAction.LeaveRoom -> handleLeaveRoom() is RoomProfileAction.ChangeRoomNotificationState -> handleChangeNotificationMode(action) is RoomProfileAction.ShareRoomProfile -> handleShareRoomProfile() @@ -91,6 +109,24 @@ class RoomProfileViewModel @AssistedInject constructor( }.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() { viewModelScope.launch(Dispatchers.IO) { withState { state -> diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt index 50723655bc..398982ede1 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileViewState.kt @@ -26,8 +26,14 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary data class RoomProfileViewState( val roomId: String, val roomSummary: Async = Uninitialized, - val bannedMembership: Async> = Uninitialized + val bannedMembership: Async> = Uninitialized, + val actionPermissions: ActionPermissions = ActionPermissions(), + val isLoading: Boolean = false ) : MvRxState { constructor(args: RoomProfileArgs) : this(roomId = args.roomId) + + data class ActionPermissions( + val canEnableEncryption: Boolean = false + ) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt index 80bb8813cf..f0a7b38478 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsAction.kt @@ -25,7 +25,6 @@ sealed class RoomSettingsAction : VectorViewModelAction { data class SetRoomTopic(val newTopic: String) : RoomSettingsAction() data class SetRoomHistoryVisibility(val visibility: RoomHistoryVisibility) : RoomSettingsAction() data class SetRoomCanonicalAlias(val newCanonicalAlias: String) : RoomSettingsAction() - object EnableEncryption : RoomSettingsAction() object Save : RoomSettingsAction() object Cancel : RoomSettingsAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt index 5231cc6b06..3c73e6ed46 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsController.kt @@ -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.toModel 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 javax.inject.Inject @@ -44,7 +43,6 @@ class RoomSettingsController @Inject constructor( // Delete the avatar, or cancel an avatar change fun onAvatarDelete() fun onAvatarChange() - fun onEnableEncryptionClicked() fun onNameChanged(name: String) fun onTopicChanged(topic: String) fun onHistoryVisibilityClicked() @@ -130,33 +128,6 @@ class RoomSettingsController @Inject constructor( editable = data.actionPermissions.canChangeHistoryReadability, 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? { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt index 57521f7d80..ab9d3c6896 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsFragment.kt @@ -127,17 +127,6 @@ class RoomSettingsFragment @Inject constructor( 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) { viewModel.handle(RoomSettingsAction.SetRoomName(name)) } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt index 086ce93bb0..05a75a585b 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewModel.kt @@ -17,7 +17,6 @@ package im.vector.app.features.roomprofile.settings import androidx.core.net.toFile -import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext @@ -28,7 +27,6 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.powerlevel.PowerLevelsObservableFactory import io.reactivex.Completable import io.reactivex.Observable -import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.session.Session @@ -118,8 +116,7 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: canChangeCanonicalAlias = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_CANONICAL_ALIAS), canChangeHistoryReadability = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, - EventType.STATE_ROOM_HISTORY_VISIBILITY), - canEnableEncryption = powerLevelsHelper.isUserAllowedToSend(session.myUserId, true, EventType.STATE_ROOM_ENCRYPTION) + EventType.STATE_ROOM_HISTORY_VISIBILITY) ) setState { copy(actionPermissions = permissions) } } @@ -142,7 +139,6 @@ class RoomSettingsViewModel @AssistedInject constructor(@Assisted initialState: override fun handle(action: RoomSettingsAction) { when (action) { - is RoomSettingsAction.EnableEncryption -> handleEnableEncryption() is RoomSettingsAction.SetAvatarAction -> handleSetAvatarAction(action) is RoomSettingsAction.SetRoomName -> setState { copy(newName = action.newName) } 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) { setState { copy(isLoading = isLoading) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt index f913bed382..2cadc8f798 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/RoomSettingsViewState.kt @@ -47,8 +47,7 @@ data class RoomSettingsViewState( val canChangeName: Boolean = false, val canChangeTopic: Boolean = false, val canChangeCanonicalAlias: Boolean = false, - val canChangeHistoryReadability: Boolean = false, - val canEnableEncryption: Boolean = false + val canChangeHistoryReadability: Boolean = false ) sealed class AvatarAction { diff --git a/vector/src/main/res/layout/fragment_matrix_profile.xml b/vector/src/main/res/layout/fragment_matrix_profile.xml index c935ab5cee..c10185b2f3 100644 --- a/vector/src/main/res/layout/fragment_matrix_profile.xml +++ b/vector/src/main/res/layout/fragment_matrix_profile.xml @@ -95,7 +95,6 @@ - + + \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 48729df815..7eec4eca19 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2200,7 +2200,8 @@ Message editor - Enable end-to-end encryption + Enable end-to-end encryption… + You don\'t have permission to enable encryption in this room. Once enabled, encryption cannot be disabled. Enable encryption?