Simple space context menu

This commit is contained in:
Valere 2021-03-19 17:30:53 +01:00
parent 06a84d985a
commit 681b5b3ddc
14 changed files with 312 additions and 16 deletions

View File

@ -80,6 +80,7 @@ import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.spaces.ShareSpaceBottomSheet
import im.vector.app.features.spaces.SpaceCreationActivity
import im.vector.app.features.spaces.SpaceExploreActivity
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
import im.vector.app.features.terms.ReviewTermsActivity
import im.vector.app.features.ui.UiStateRepository
import im.vector.app.features.usercode.UserCodeActivity
@ -179,6 +180,7 @@ interface ScreenComponent {
fun inject(bottomSheet: SignOutBottomSheetDialogFragment)
fun inject(bottomSheet: MatrixToBottomSheet)
fun inject(bottomSheet: ShareSpaceBottomSheet)
fun inject(bottomSheet: SpaceSettingsMenuBottomSheet)
/* ==========================================================================================
* Others

View File

@ -58,6 +58,7 @@ import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity
import im.vector.app.features.spaces.SpaceCreationActivity
import im.vector.app.features.spaces.SpacePreviewActivity
import im.vector.app.features.spaces.SpaceSettingsMenuBottomSheet
import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
import im.vector.app.features.workers.signout.ServerBackupStatusViewState
@ -164,6 +165,12 @@ class HomeActivity :
is HomeActivitySharedAction.AddSpace -> {
createSpaceResultLauncher.launch(SpaceCreationActivity.newIntent(this))
}
is HomeActivitySharedAction.ShowSpaceSettings -> {
// open bottom sheet
SpaceSettingsMenuBottomSheet
.newInstance(sharedAction.spaceId)
.show(supportFragmentManager, "SPACE_SETTINGS")
}
}.exhaustive
}
.disposeOnDestroy()

View File

@ -27,4 +27,5 @@ sealed class HomeActivitySharedAction : VectorSharedAction {
object OpenGroup : HomeActivitySharedAction()
object AddSpace : HomeActivitySharedAction()
data class OpenSpacePreview(val spaceId: String) : HomeActivitySharedAction()
data class ShowSpaceSettings(val spaceId: String) : HomeActivitySharedAction()
}

View File

@ -300,6 +300,16 @@ class HomeDetailFragment @Inject constructor(
views.groupToolbarAvatarImageView.debouncedClicks {
sharedActionViewModel.post(HomeActivitySharedAction.OpenDrawer)
}
views.homeToolbarContent.debouncedClicks {
withState(viewModel) {
val currentSpace = it.spaceSummary.orNull()
?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID }
if (vectorPreferences.labSpaces() && currentSpace != null) {
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId))
}
}
}
}
private fun setupBottomNavigationView() {

View File

@ -54,6 +54,7 @@ class RoomProfileActivity :
const val EXTRA_DIRECT_ACCESS_ROOM_ROOT = 0
const val EXTRA_DIRECT_ACCESS_ROOM_SETTINGS = 1
const val EXTRA_DIRECT_ACCESS_ROOM_MEMBERS = 2
fun newIntent(context: Context, roomId: String, directAccess: Int?): Intent {
val roomProfileArgs = RoomProfileArgs(roomId)
@ -97,6 +98,9 @@ class RoomProfileActivity :
addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
addFragmentToBackstack(R.id.simpleFragmentContainer, RoomSettingsFragment::class.java, roomProfileArgs)
}
EXTRA_DIRECT_ACCESS_ROOM_MEMBERS -> {
addFragment(R.id.simpleFragmentContainer, RoomMemberListFragment::class.java, roomProfileArgs)
}
else -> addFragment(R.id.simpleFragmentContainer, RoomProfileFragment::class.java, roomProfileArgs)
}
}

View File

@ -80,8 +80,8 @@ class SpaceListFragment @Inject constructor(
viewModel.handle(SpaceListAction.SelectSpace(spaceSummary))
}
override fun onLeaveSpace(spaceSummary: RoomSummary) {
viewModel.handle(SpaceListAction.LeaveSpace(spaceSummary))
override fun onSpaceSettings(spaceSummary: RoomSummary) {
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId))
}
override fun onAddSpaceSelected() {

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2021 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.app.features.spaces
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import com.airbnb.mvrx.args
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.databinding.BottomSheetSpaceSettingsBinding
import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.navigation.Navigator
import im.vector.app.features.powerlevel.PowerLevelsObservableFactory
import im.vector.app.features.roomprofile.RoomProfileActivity
import im.vector.app.features.settings.VectorPreferences
import io.reactivex.android.schedulers.AndroidSchedulers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.parcelize.Parcelize
import org.matrix.android.sdk.api.session.room.powerlevels.PowerLevelsHelper
import org.matrix.android.sdk.api.util.toMatrixItem
import org.matrix.android.sdk.internal.util.awaitCallback
import timber.log.Timber
import javax.inject.Inject
@Parcelize
data class SpaceBottomSheetSettingsArgs(
val spaceId: String
) : Parcelable
class SpaceSettingsMenuBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetSpaceSettingsBinding>() {
@Inject lateinit var navigator: Navigator
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var avatarRenderer: AvatarRenderer
@Inject lateinit var vectorPreferences: VectorPreferences
private val spaceArgs: SpaceBottomSheetSettingsArgs by args()
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetSpaceSettingsBinding {
return BottomSheetSpaceSettingsBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val session = activeSessionHolder.getSafeActiveSession() ?: return
val roomSummary = session.getRoomSummary(spaceArgs.spaceId)
roomSummary?.let { roomSummary ->
avatarRenderer.renderSpace(roomSummary.toMatrixItem(), views.roomAvatarImageView)
views.roomNameView.text = roomSummary.displayName
views.roomDescription.text = roomSummary.topic
}
val room = session.getRoom(spaceArgs.spaceId) ?: return
PowerLevelsObservableFactory(room)
.createObservable()
.observeOn(AndroidSchedulers.mainThread())
.subscribe { powerLevelContent ->
val powerLevelsHelper = PowerLevelsHelper(powerLevelContent)
val canInvite = powerLevelsHelper.isUserAbleToInvite(session.myUserId)
views.invitePeople.isVisible = canInvite
}.disposeOnDestroyView()
views.invitePeople.views.bottomSheetActionClickableZone.debouncedClicks {
navigator.openInviteUsersToRoom(requireContext(), spaceArgs.spaceId)
}
views.showMemberList.views.bottomSheetActionClickableZone.debouncedClicks {
navigator.openRoomProfile(requireContext(), spaceArgs.spaceId, RoomProfileActivity.EXTRA_DIRECT_ACCESS_ROOM_MEMBERS)
}
views.spaceSettings.isVisible = vectorPreferences.developerMode()
views.spaceSettings.views.bottomSheetActionClickableZone.debouncedClicks {
navigator.openRoomProfile(requireContext(), spaceArgs.spaceId)
}
views.exploreRooms.views.bottomSheetActionClickableZone.debouncedClicks {
startActivity(SpaceExploreActivity.newIntent(requireContext(), spaceArgs.spaceId))
}
views.leaveSpace.views.bottomSheetActionClickableZone.debouncedClicks {
AlertDialog.Builder(requireContext())
.setMessage(getString(R.string.space_leave_prompt_msg))
.setPositiveButton(R.string.leave) { _, _ ->
GlobalScope.launch {
try {
awaitCallback {
session.getRoom(spaceArgs.spaceId)?.leave(null, it)
}
} catch (failure: Throwable) {
Timber.e(failure, "Failed to leave space")
}
}
dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
}
companion object {
fun newInstance(spaceId: String): SpaceSettingsMenuBottomSheet {
return SpaceSettingsMenuBottomSheet().apply {
setArguments(SpaceBottomSheetSettingsArgs(spaceId))
}
}
}
}

View File

@ -102,7 +102,7 @@ class SpaceSummaryController @Inject constructor(
id(groupSummary.roomId)
matrixItem(groupSummary.toMatrixItem())
selected(isSelected)
onLeave { callback?.onLeaveSpace(groupSummary) }
onMore { callback?.onSpaceSettings(groupSummary) }
listener { callback?.onSpaceSelected(groupSummary) }
}
}
@ -120,7 +120,7 @@ class SpaceSummaryController @Inject constructor(
interface Callback {
fun onSpaceSelected(spaceSummary: RoomSummary)
fun onLeaveSpace(spaceSummary: RoomSummary)
fun onSpaceSettings(spaceSummary: RoomSummary)
fun onAddSpaceSelected()
}
}

View File

@ -38,7 +38,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var selected: Boolean = false
@EpoxyAttribute var listener: (() -> Unit)? = null
@EpoxyAttribute var onLeave: (() -> Unit)? = null
@EpoxyAttribute var onMore: (() -> Unit)? = null
@EpoxyAttribute var toggleExpand: (() -> Unit)? = null
@EpoxyAttribute var expanded: Boolean? = null
@ -47,14 +47,14 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
holder.rootView.setOnClickListener { listener?.invoke() }
holder.groupNameView.text = matrixItem.displayName
holder.rootView.isChecked = selected
if (onLeave != null) {
holder.leaveView.setOnClickListener(
if (onMore != null) {
holder.moreView.setOnClickListener(
DebouncedClickListener({ _ ->
onLeave?.invoke()
onMore?.invoke()
})
)
} else {
holder.leaveView.isVisible = false
holder.moreView.isVisible = false
}
when (expanded) {
@ -88,7 +88,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
val groupNameView by bind<TextView>(R.id.groupNameView)
val rootView by bind<CheckableConstraintLayout>(R.id.itemGroupLayout)
val leaveView by bind<ImageView>(R.id.groupTmpLeave)
val moreView by bind<ImageView>(R.id.groupTmpLeave)
val collapseIndicator by bind<ImageView>(R.id.groupChildrenCollapse)
}
}

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M22.6667,12C22.6667,17.8911 17.8911,22.6667 12,22.6667C6.109,22.6667 1.3333,17.8911 1.3333,12C1.3333,6.109 6.109,1.3334 12,1.3334C17.8911,1.3334 22.6667,6.109 22.6667,12ZM17.8333,7.1022C18.0778,6.5711 17.4288,5.9221 16.8977,6.1666L10.2263,9.238C9.7853,9.4411 9.4402,9.7861 9.2372,10.2271L6.1657,16.8986C5.9212,17.4297 6.5702,18.0787 7.1013,17.8341L13.7727,14.7627C14.2137,14.5597 14.5588,14.2146 14.7618,13.7736L17.8333,7.1022Z"
android:fillColor="#737D8C"
android:fillType="evenOdd"/>
<path
android:pathData="M13.178,13.1789C12.5271,13.8298 11.4719,13.8298 10.821,13.1789C10.1701,12.528 10.1701,11.4727 10.821,10.8219C11.4719,10.171 12.5271,10.171 13.178,10.8219C13.8289,11.4727 13.8289,12.528 13.178,13.1789Z"
android:fillColor="#737D8C"/>
</vector>

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/callControlsWrapper"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?riotx_bottom_sheet_background"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:padding="8dp"
android:paddingStart="16dp"
android:paddingEnd="8dp">
<ImageView
android:id="@+id/roomAvatarImageView"
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@string/avatar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/roomNameView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginEnd="8dp"
android:duplicateParentState="true"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?riotx_text_primary"
android:textSize="15sp"
android:textStyle="bold"
app:layout_constrainedWidth="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/roomAvatarImageView"
app:layout_constraintTop_toTopOf="parent"
tools:text="@sample/matrix.json/data/displayName" />
<TextView
android:id="@+id/roomDescription"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginTop="3dp"
android:layout_marginEnd="8dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?riotx_text_secondary"
android:textSize="15sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/roomAvatarImageView"
app:layout_constraintTop_toBottomOf="@+id/roomNameView"
tools:text="@sample/matrix.json/data/message" />
</androidx.constraintlayout.widget.ConstraintLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?vctr_list_divider_color" />
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/invitePeople"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/invite_people_menu"
app:leftIcon="@drawable/ic_invite_people"
app:tint="?attr/riotx_text_primary"
app:titleTextColor="?attr/riotx_text_primary" />
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/showMemberList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/list_members"
app:leftIcon="@drawable/ic_room_profile_member_list"
app:tint="?attr/riotx_text_primary"
app:titleTextColor="?attr/riotx_text_primary" />
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/spaceSettings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/settings"
app:leftIcon="@drawable/ic_settings_root_general"
app:tint="?attr/riotx_text_primary"
app:titleTextColor="?attr/riotx_text_primary" />
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/exploreRooms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/space_explore_activity_title"
app:leftIcon="@drawable/ic_explore"
app:tint="?attr/riotx_text_primary"
app:titleTextColor="?attr/riotx_text_primary"
tools:actionDescription="" />
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/leaveSpace"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:actionTitle="@string/leave_space"
app:leftIcon="@drawable/ic_room_actions_leave"
app:tint="@color/riotx_destructive_accent"
app:titleTextColor="@color/riotx_destructive_accent" />
</LinearLayout>

View File

@ -35,6 +35,7 @@
android:layout_weight="1"
android:gravity="start"
android:orientation="vertical"
android:id="@+id/homeToolbarContent"
android:paddingStart="8dp"
android:paddingEnd="8dp">

View File

@ -66,8 +66,8 @@
android:padding="4dp"
android:layout_marginEnd="4dp"
android:importantForAccessibility="no"
android:src="@drawable/ic_room_actions_leave"
app:tint="@color/riotx_destructive_accent"
android:src="@drawable/ic_more_vertical"
app:tint="?riotx_text_secondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/groupAvatarChevron"
app:layout_constraintTop_toTopOf="parent" />

View File

@ -3281,6 +3281,7 @@
<string name="create_spaces_default_public_random_room_name">Random</string>
<string name="create_spaces_loading_message">Creating Space…</string>
<string name="invite_people_to_your_space">Invite people to your space</string>
<string name="invite_people_menu">Invite people</string>
<string name="invite_people_to_your_space_desc">Its just you at the moment. %s will be even better with others.</string>
<string name="invite_by_email">Invite by email</string>
<string name="invite_by_mxid">Invite by username</string>
@ -3295,4 +3296,6 @@
<string name="suggested_rooms_pills_on_empty_text">Youre not in any rooms yet. Below are some suggested rooms, but you can see more with the green button bottom right.</string>
<string name="space_explore_activity_title">Explore rooms</string>
<string name="leave_space">Leave Space</string>
<string name="space_leave_prompt_msg">Are you sure you want to leave the space?</string>
</resources>