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.core.platform.VectorBaseFragment
import im.vector.riotx.features.home.RoomListDisplayMode 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.RoomListQuickActionsSharedAction
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
@ -132,10 +133,7 @@ class RoomListFragment @Inject constructor(
} }
private fun showError(event: RoomListViewEvents.Failure) { private fun showError(event: RoomListViewEvents.Failure) {
vectorBaseActivity.coordinatorLayout?.let { vectorBaseActivity.showSnackbar(errorFormatter.toHumanReadable(event.throwable))
Snackbar.make(it, errorFormatter.toHumanReadable(event.throwable), Snackbar.LENGTH_SHORT)
.show()
}
} }
private fun setupCreateRoomButton() { private fun setupCreateRoomButton() {
@ -347,7 +345,7 @@ class RoomListFragment @Inject constructor(
roomController.onRoomLongClicked() roomController.onRoomLongClicked()
RoomListQuickActionsBottomSheet RoomListQuickActionsBottomSheet
.newInstance(room.roomId) .newInstance(room.roomId, RoomListActionsArgs.Mode.FULL)
.show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS") .show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS")
return true return true
} }

View File

@ -36,8 +36,15 @@ import javax.inject.Inject
@Parcelize @Parcelize
data class RoomListActionsArgs( data class RoomListActionsArgs(
val roomId: String val roomId: String,
) : Parcelable val mode: Mode
) : Parcelable {
enum class Mode {
FULL,
NOTIFICATIONS
}
}
/** /**
* Bottom sheet fragment that shows room information with list of contextual actions * Bottom sheet fragment that shows room information with list of contextual actions
@ -87,9 +94,9 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
} }
companion object { companion object {
fun newInstance(roomId: String): RoomListQuickActionsBottomSheet { fun newInstance(roomId: String, mode: RoomListActionsArgs.Mode): RoomListQuickActionsBottomSheet {
return RoomListQuickActionsBottomSheet().apply { 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) { override fun buildModels(state: RoomListQuickActionsState) {
val roomSummary = state.roomSummary() ?: return val roomSummary = state.roomSummary() ?: return
// Preview if (state.mode == RoomListActionsArgs.Mode.FULL) {
bottomSheetItemRoomPreview { // Preview
id("preview") bottomSheetItemRoomPreview {
avatarRenderer(avatarRenderer) id("preview")
roomName(roomSummary.displayName) avatarRenderer(avatarRenderer)
avatarUrl(roomSummary.avatarUrl) roomName(roomSummary.displayName)
roomId(roomSummary.roomId) avatarUrl(roomSummary.avatarUrl)
settingsClickListener(View.OnClickListener { listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) }) roomId(roomSummary.roomId)
} settingsClickListener(View.OnClickListener { listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) })
}
// Notifications // Notifications
dividerItem { dividerItem {
id("notifications_separator") id("notifications_separator")
}
} }
val selectedRoomState = state.roomNotificationState() val selectedRoomState = state.roomNotificationState()
@ -56,11 +58,13 @@ class RoomListQuickActionsEpoxyController @Inject constructor(private val avatar
RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState) RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState)
RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState) RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState)
// Leave if (state.mode == RoomListActionsArgs.Mode.FULL) {
dividerItem { // Leave
id("leave_separator") 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) { 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( data class RoomListQuickActionsState(
val roomId: String, val roomId: String,
val mode: RoomListActionsArgs.Mode,
val roomSummary: Async<RoomSummary> = Uninitialized, val roomSummary: Async<RoomSummary> = Uninitialized,
val roomNotificationState: Async<RoomNotificationState> = Uninitialized val roomNotificationState: Async<RoomNotificationState> = Uninitialized
) : MvRxState { ) : 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 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.core.platform.VectorViewModelAction
import im.vector.riotx.features.home.room.list.RoomListAction
sealed class RoomProfileAction: VectorViewModelAction { 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 package im.vector.riotx.features.roomprofile
import android.app.ProgressDialog
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.View import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.airbnb.mvrx.args import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState 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.R
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.setTextOrHide import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.home.AvatarRenderer 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.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_room_profile.* import kotlinx.android.synthetic.main.fragment_room_profile.*
import timber.log.Timber import timber.log.Timber
@ -42,18 +54,70 @@ data class RoomProfileArgs(
class RoomProfileFragment @Inject constructor( class RoomProfileFragment @Inject constructor(
private val roomProfileController: RoomProfileController, private val roomProfileController: RoomProfileController,
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val errorFormatter: ErrorFormatter,
val roomProfileViewModelFactory: RoomProfileViewModel.Factory val roomProfileViewModelFactory: RoomProfileViewModel.Factory
) : VectorBaseFragment(), RoomProfileController.Callback { ) : VectorBaseFragment(), RoomProfileController.Callback {
private var progress: ProgressDialog? = null
private val roomProfileArgs: RoomProfileArgs by args() private val roomProfileArgs: RoomProfileArgs by args()
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel() private val roomProfileViewModel: RoomProfileViewModel by fragmentViewModel()
override fun getLayoutResId() = R.layout.fragment_room_profile override fun getLayoutResId() = R.layout.fragment_room_profile
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
setupToolbar(roomProfileToolbar) setupToolbar(roomProfileToolbar)
setupRecyclerView() 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() { private fun setupRecyclerView() {
@ -100,8 +164,9 @@ class RoomProfileFragment @Inject constructor(
} }
override fun onNotificationsClicked() { override fun onNotificationsClicked() {
vectorBaseActivity.notImplemented("See notifications") RoomListQuickActionsBottomSheet
.newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
.show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
} }
override fun onUploadsClicked() { override fun onUploadsClicked() {
@ -109,6 +174,13 @@ class RoomProfileFragment @Inject constructor(
} }
override fun onLeaveRoomClicked() { 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.airbnb.mvrx.ViewModelContext
import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject 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.android.api.session.Session
import im.vector.matrix.rx.rx import im.vector.matrix.rx.rx
import im.vector.matrix.rx.unwrap import im.vector.matrix.rx.unwrap
import im.vector.riotx.core.platform.VectorViewModel 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, class RoomProfileViewModel @AssistedInject constructor(@Assisted initialState: RoomProfileViewState,
private val session: Session) 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)!! private val room = session.getRoom(initialState.roomId)!!
init { 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"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/simpleFragmentContainer" android:id="@+id/vector_coordinator_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" 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_member_list">"%1$s people"</string>
<string name="room_profile_section_more_uploads">Uploads</string> <string name="room_profile_section_more_uploads">Uploads</string>
<string name="room_profile_section_more_leave">Leave Room</string> <string name="room_profile_section_more_leave">Leave Room</string>
<string name="room_profile_leaving_room">"Leaving the room..."</string>
</resources> </resources>