Room profile: branch leave and notifications actions

This commit is contained in:
ganfra 2019-11-26 17:25:26 +01:00
parent ab4cab05cf
commit fd18bcb97f
10 changed files with 185 additions and 33 deletions

View File

@ -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
}

View File

@ -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))
}
}
}

View File

@ -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) {

View File

@ -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<RoomSummary> = Uninitialized,
val roomNotificationState: Async<RoomNotificationState> = Uninitialized
) : MvRxState {
constructor(args: RoomListActionsArgs) : this(roomId = args.roomId)
constructor(args: RoomListActionsArgs) : this(roomId = args.roomId, mode = args.mode)
}

View File

@ -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()
}

View File

@ -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()
}
}

View File

@ -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()
}

View File

@ -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<RoomProfileViewEvents>()
val viewEvents: DataSource<RoomProfileViewEvents> = _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<Unit> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(RoomProfileViewEvents.Failure(failure))
}
})
}
private fun handleLeaveRoom() {
_viewEvents.post(RoomProfileViewEvents.Loading)
room.leave(object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
_viewEvents.post(RoomProfileViewEvents.OnLeaveRoomSuccess)
}
override fun onFailure(failure: Throwable) {
_viewEvents.post(RoomProfileViewEvents.Failure(failure))
}
})
}
}

View File

@ -1,5 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/simpleFragmentContainer"
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/vector_coordinator_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/simpleFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -29,5 +29,6 @@
<string name="room_profile_section_more_member_list">"%1$s people"</string>
<string name="room_profile_section_more_uploads">Uploads</string>
<string name="room_profile_section_more_leave">Leave Room</string>
<string name="room_profile_leaving_room">"Leaving the room..."</string>
</resources>