From fd18bcb97f84f92c538a2b579979010e6f571f72 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 26 Nov 2019 17:25:26 +0100 Subject: [PATCH] Room profile: branch leave and notifications actions --- .../home/room/list/RoomListFragment.kt | 8 +- .../RoomListQuickActionsBottomSheet.kt | 15 +++- .../RoomListQuickActionsEpoxyController.kt | 36 +++++---- .../list/actions/RoomListQuickActionsState.kt | 3 +- .../features/roomprofile/RoomProfileAction.kt | 4 + .../roomprofile/RoomProfileFragment.kt | 78 ++++++++++++++++++- .../roomprofile/RoomProfileViewEvents.kt | 26 +++++++ .../roomprofile/RoomProfileViewModel.kt | 33 +++++++- .../src/main/res/layout/activity_simple.xml | 14 +++- vector/src/main/res/values/strings_riotX.xml | 1 + 10 files changed, 185 insertions(+), 33 deletions(-) create mode 100644 vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewEvents.kt diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt index 9e6d5533f6..54fadf6461 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt @@ -40,6 +40,7 @@ import im.vector.riotx.core.platform.StateView import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.features.home.RoomListDisplayMode +import im.vector.riotx.features.home.room.list.actions.RoomListActionsArgs import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel @@ -132,10 +133,7 @@ class RoomListFragment @Inject constructor( } private fun showError(event: RoomListViewEvents.Failure) { - vectorBaseActivity.coordinatorLayout?.let { - Snackbar.make(it, errorFormatter.toHumanReadable(event.throwable), Snackbar.LENGTH_SHORT) - .show() - } + vectorBaseActivity.showSnackbar(errorFormatter.toHumanReadable(event.throwable)) } private fun setupCreateRoomButton() { @@ -347,7 +345,7 @@ class RoomListFragment @Inject constructor( roomController.onRoomLongClicked() RoomListQuickActionsBottomSheet - .newInstance(room.roomId) + .newInstance(room.roomId, RoomListActionsArgs.Mode.FULL) .show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS") return true } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt index 3a85cf26fa..c797a7dc45 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt @@ -36,8 +36,15 @@ import javax.inject.Inject @Parcelize data class RoomListActionsArgs( - val roomId: String -) : Parcelable + val roomId: String, + val mode: Mode +) : Parcelable { + + enum class Mode { + FULL, + NOTIFICATIONS + } +} /** * Bottom sheet fragment that shows room information with list of contextual actions @@ -87,9 +94,9 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R } companion object { - fun newInstance(roomId: String): RoomListQuickActionsBottomSheet { + fun newInstance(roomId: String, mode: RoomListActionsArgs.Mode): RoomListQuickActionsBottomSheet { return RoomListQuickActionsBottomSheet().apply { - setArguments(RoomListActionsArgs(roomId)) + setArguments(RoomListActionsArgs(roomId, mode)) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt index 8562ec4153..c7fa354961 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt @@ -35,19 +35,21 @@ class RoomListQuickActionsEpoxyController @Inject constructor(private val avatar override fun buildModels(state: RoomListQuickActionsState) { val roomSummary = state.roomSummary() ?: return - // Preview - bottomSheetItemRoomPreview { - id("preview") - avatarRenderer(avatarRenderer) - roomName(roomSummary.displayName) - avatarUrl(roomSummary.avatarUrl) - roomId(roomSummary.roomId) - settingsClickListener(View.OnClickListener { listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) }) - } + if (state.mode == RoomListActionsArgs.Mode.FULL) { + // Preview + bottomSheetItemRoomPreview { + id("preview") + avatarRenderer(avatarRenderer) + roomName(roomSummary.displayName) + avatarUrl(roomSummary.avatarUrl) + roomId(roomSummary.roomId) + settingsClickListener(View.OnClickListener { listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) }) + } - // Notifications - dividerItem { - id("notifications_separator") + // Notifications + dividerItem { + id("notifications_separator") + } } val selectedRoomState = state.roomNotificationState() @@ -56,11 +58,13 @@ class RoomListQuickActionsEpoxyController @Inject constructor(private val avatar RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState) RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState) - // Leave - dividerItem { - id("leave_separator") + if (state.mode == RoomListActionsArgs.Mode.FULL) { + // Leave + dividerItem { + id("leave_separator") + } + RoomListQuickActionsSharedAction.Leave(roomSummary.roomId).toBottomSheetItem(5) } - RoomListQuickActionsSharedAction.Leave(roomSummary.roomId).toBottomSheetItem(5) } private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsState.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsState.kt index a943db1804..6e134871a7 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsState.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/actions/RoomListQuickActionsState.kt @@ -24,9 +24,10 @@ import im.vector.matrix.android.api.session.room.notification.RoomNotificationSt data class RoomListQuickActionsState( val roomId: String, + val mode: RoomListActionsArgs.Mode, val roomSummary: Async = Uninitialized, val roomNotificationState: Async = Uninitialized ) : MvRxState { - constructor(args: RoomListActionsArgs) : this(roomId = args.roomId) + constructor(args: RoomListActionsArgs) : this(roomId = args.roomId, mode = args.mode) } diff --git a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileAction.kt b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileAction.kt index 979a9d2a57..985eee72a4 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileAction.kt @@ -17,7 +17,11 @@ package im.vector.riotx.features.roomprofile +import im.vector.matrix.android.api.session.room.notification.RoomNotificationState import im.vector.riotx.core.platform.VectorViewModelAction +import im.vector.riotx.features.home.room.list.RoomListAction sealed class RoomProfileAction: VectorViewModelAction { + object LeaveRoom: RoomProfileAction() + data class ChangeRoomNotificationState(val notificationState: RoomNotificationState) : RoomProfileAction() } diff --git a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileFragment.kt index a659ba4c00..b1c5855aac 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileFragment.kt @@ -15,20 +15,32 @@ * */ +@file:Suppress("DEPRECATION") + package im.vector.riotx.features.roomprofile +import android.app.ProgressDialog import android.os.Bundle import android.os.Parcelable import android.view.View +import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState +import com.google.android.material.snackbar.Snackbar +import im.vector.matrix.android.api.session.room.notification.RoomNotificationState import im.vector.riotx.R +import im.vector.riotx.core.error.ErrorFormatter import im.vector.riotx.core.extensions.setTextOrHide import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.features.home.AvatarRenderer +import im.vector.riotx.features.home.room.list.RoomListAction +import im.vector.riotx.features.home.room.list.actions.RoomListActionsArgs +import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet +import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedAction +import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.fragment_room_profile.* import timber.log.Timber @@ -42,18 +54,70 @@ data class RoomProfileArgs( class RoomProfileFragment @Inject constructor( private val roomProfileController: RoomProfileController, private val avatarRenderer: AvatarRenderer, + private val errorFormatter: ErrorFormatter, val roomProfileViewModelFactory: RoomProfileViewModel.Factory ) : VectorBaseFragment(), RoomProfileController.Callback { + private var progress: ProgressDialog? = null private val roomProfileArgs: RoomProfileArgs by args() + private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel() override fun getLayoutResId() = R.layout.fragment_room_profile override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java) setupToolbar(roomProfileToolbar) setupRecyclerView() + roomProfileViewModel.viewEvents + .observe() + .subscribe { + progress?.dismiss() + when (it) { + RoomProfileViewEvents.Loading -> showLoading() + RoomProfileViewEvents.OnLeaveRoomSuccess -> onLeaveRoom() + is RoomProfileViewEvents.Failure -> showError(it.throwable) + } + } + .disposeOnDestroyView() + + sharedActionViewModel + .observe() + .subscribe { handleQuickActions(it) } + .disposeOnDestroyView() + } + + private fun handleQuickActions(action: RoomListQuickActionsSharedAction) = when (action) { + is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> { + roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.ALL_MESSAGES_NOISY)) + } + is RoomListQuickActionsSharedAction.NotificationsAll -> { + roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.ALL_MESSAGES)) + } + is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> { + roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.MENTIONS_ONLY)) + } + is RoomListQuickActionsSharedAction.NotificationsMute -> { + roomProfileViewModel.handle(RoomProfileAction.ChangeRoomNotificationState(RoomNotificationState.MUTE)) + } + else -> Timber.v("$action not handled") + } + + private fun onLeaveRoom() { + vectorBaseActivity.finish() + } + + private fun showError(throwable: Throwable) { + vectorBaseActivity.showSnackbar(errorFormatter.toHumanReadable(throwable)) + } + + private fun showLoading() { + progress = ProgressDialog(requireContext()).apply { + setMessage(getString(R.string.room_profile_leaving_room)) + setProgressStyle(ProgressDialog.STYLE_SPINNER) + show() + } } private fun setupRecyclerView() { @@ -100,8 +164,9 @@ class RoomProfileFragment @Inject constructor( } override fun onNotificationsClicked() { - vectorBaseActivity.notImplemented("See notifications") - + RoomListQuickActionsBottomSheet + .newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS) + .show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS") } override fun onUploadsClicked() { @@ -109,6 +174,13 @@ class RoomProfileFragment @Inject constructor( } override fun onLeaveRoomClicked() { - vectorBaseActivity.notImplemented("Leave room") + AlertDialog.Builder(requireContext()) + .setTitle(R.string.room_participants_leave_prompt_title) + .setMessage(R.string.room_participants_leave_prompt_msg) + .setPositiveButton(R.string.leave) { _, _ -> + roomProfileViewModel.handle(RoomProfileAction.LeaveRoom) + } + .setNegativeButton(R.string.cancel, null) + .show() } } diff --git a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewEvents.kt b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewEvents.kt new file mode 100644 index 0000000000..4b483d51a4 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewEvents.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2019 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.riotx.features.roomprofile +/** + * Transient events for RoomProfile + */ +sealed class RoomProfileViewEvents { + object Loading: RoomProfileViewEvents() + object OnLeaveRoomSuccess: RoomProfileViewEvents() + data class Failure(val throwable: Throwable) : RoomProfileViewEvents() + +} diff --git a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewModel.kt b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewModel.kt index 52a48d101d..72b87b7716 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomprofile/RoomProfileViewModel.kt @@ -22,10 +22,15 @@ import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.ViewModelContext import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject +import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.Session import im.vector.matrix.rx.rx import im.vector.matrix.rx.unwrap import im.vector.riotx.core.platform.VectorViewModel +import im.vector.riotx.core.utils.DataSource +import im.vector.riotx.core.utils.PublishDataSource +import im.vector.riotx.features.home.room.list.RoomListAction +import im.vector.riotx.features.home.room.list.RoomListViewEvents class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: RoomProfileViewState, private val session: Session) @@ -45,6 +50,9 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: R } } + private val _viewEvents = PublishDataSource() + val viewEvents: DataSource = _viewEvents + private val room = session.getRoom(initialState.roomId)!! init { @@ -62,7 +70,30 @@ class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: R } } - override fun handle(action: RoomProfileAction) { + override fun handle(action: RoomProfileAction) = when (action) { + RoomProfileAction.LeaveRoom -> handleLeaveRoom() + is RoomProfileAction.ChangeRoomNotificationState -> handleChangeNotificationMode(action) + } + + private fun handleChangeNotificationMode(action: RoomProfileAction.ChangeRoomNotificationState) { + room.setRoomNotificationState(action.notificationState, object : MatrixCallback { + override fun onFailure(failure: Throwable) { + _viewEvents.post(RoomProfileViewEvents.Failure(failure)) + } + }) + } + + private fun handleLeaveRoom() { + _viewEvents.post(RoomProfileViewEvents.Loading) + room.leave(object : MatrixCallback { + override fun onSuccess(data: Unit) { + _viewEvents.post(RoomProfileViewEvents.OnLeaveRoomSuccess) + } + + override fun onFailure(failure: Throwable) { + _viewEvents.post(RoomProfileViewEvents.Failure(failure)) + } + }) } } diff --git a/vector/src/main/res/layout/activity_simple.xml b/vector/src/main/res/layout/activity_simple.xml index 8dc41487fe..0eda46a67d 100644 --- a/vector/src/main/res/layout/activity_simple.xml +++ b/vector/src/main/res/layout/activity_simple.xml @@ -1,5 +1,13 @@ - + android:layout_height="match_parent"> + + + + \ No newline at end of file diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index feaa9f5db5..9f38134022 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -29,5 +29,6 @@ "%1$s people" Uploads Leave Room + "Leaving the room..."