mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 02:15:35 +03:00
Merge pull request #6749 from vector-im/feature/eric/space-list-modal
Adds Space List Bottom Sheet
This commit is contained in:
commit
4fedafc1be
26 changed files with 896 additions and 165 deletions
1
changelog.d/6749.wip
Normal file
1
changelog.d/6749.wip
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Adds space list bottom sheet for new app layout
|
|
@ -34,6 +34,7 @@ import im.vector.app.features.home.HomeSharedActionViewModel
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
|
import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel
|
||||||
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
|
import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
|
import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
|
||||||
import im.vector.app.features.reactions.EmojiChooserViewModel
|
import im.vector.app.features.reactions.EmojiChooserViewModel
|
||||||
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel
|
||||||
import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel
|
import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel
|
||||||
|
@ -157,4 +158,9 @@ interface ViewModelModule {
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@ViewModelKey(SpacePeopleSharedActionViewModel::class)
|
@ViewModelKey(SpacePeopleSharedActionViewModel::class)
|
||||||
fun bindSpacePeopleSharedActionViewModel(viewModel: SpacePeopleSharedActionViewModel): ViewModel
|
fun bindSpacePeopleSharedActionViewModel(viewModel: SpacePeopleSharedActionViewModel): ViewModel
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@ViewModelKey(RoomListSharedActionViewModel::class)
|
||||||
|
fun bindRoomListSharedActionViewModel(viewModel: RoomListSharedActionViewModel): ViewModel
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import im.vector.app.features.themes.ThemeUtils
|
||||||
@EpoxyModelClass
|
@EpoxyModelClass
|
||||||
abstract class HomeSpaceSummaryItem : VectorEpoxyModel<HomeSpaceSummaryItem.Holder>(R.layout.item_space) {
|
abstract class HomeSpaceSummaryItem : VectorEpoxyModel<HomeSpaceSummaryItem.Holder>(R.layout.item_space) {
|
||||||
|
|
||||||
|
@EpoxyAttribute var text: String = ""
|
||||||
@EpoxyAttribute var selected: Boolean = false
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
||||||
@EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
@EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.app.features.grouplist
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.graphics.ColorUtils
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.platform.CheckableConstraintLayout
|
||||||
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class NewHomeSpaceSummaryItem : VectorEpoxyModel<NewHomeSpaceSummaryItem.Holder>(R.layout.item_new_space) {
|
||||||
|
|
||||||
|
@EpoxyAttribute var text: String = ""
|
||||||
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
||||||
|
@EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||||
|
@EpoxyAttribute var showSeparator: Boolean = false
|
||||||
|
|
||||||
|
override fun getViewType() = R.id.space_item_home
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.root.onClick(listener)
|
||||||
|
holder.name.text = holder.view.context.getString(R.string.all_chats)
|
||||||
|
holder.root.isChecked = selected
|
||||||
|
holder.root.context.resources
|
||||||
|
holder.avatar.background = ContextCompat.getDrawable(holder.view.context, R.drawable.new_space_home_background)
|
||||||
|
holder.avatar.backgroundTintList = ColorStateList.valueOf(
|
||||||
|
ColorUtils.setAlphaComponent(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_tertiary), (255 * 0.3).toInt()))
|
||||||
|
holder.avatar.setImageResource(R.drawable.ic_space_home)
|
||||||
|
holder.avatar.imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_primary))
|
||||||
|
holder.avatar.scaleType = ImageView.ScaleType.CENTER_INSIDE
|
||||||
|
|
||||||
|
holder.unreadCounter.render(countState)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val root by bind<CheckableConstraintLayout>(R.id.root)
|
||||||
|
val avatar by bind<ImageView>(R.id.avatar)
|
||||||
|
val name by bind<TextView>(R.id.name)
|
||||||
|
val unreadCounter by bind<UnreadCounterBadgeView>(R.id.unread_counter)
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,7 +67,7 @@ class NewHomeDetailFragment @Inject constructor(
|
||||||
private val alertManager: PopupAlertManager,
|
private val alertManager: PopupAlertManager,
|
||||||
private val callManager: WebRtcCallManager,
|
private val callManager: WebRtcCallManager,
|
||||||
private val vectorPreferences: VectorPreferences,
|
private val vectorPreferences: VectorPreferences,
|
||||||
private val appStateHandler: SpaceStateHandler,
|
private val spaceStateHandler: SpaceStateHandler,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
) : VectorBaseFragment<FragmentNewHomeDetailBinding>(),
|
) : VectorBaseFragment<FragmentNewHomeDetailBinding>(),
|
||||||
KeysBackupBanner.Delegate,
|
KeysBackupBanner.Delegate,
|
||||||
|
@ -176,13 +176,13 @@ class NewHomeDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun navigateBack() {
|
private fun navigateBack() {
|
||||||
val previousSpaceId = appStateHandler.getSpaceBackstack().removeLastOrNull()
|
val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull()
|
||||||
val parentSpaceId = appStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
|
val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull()
|
||||||
setCurrentSpace(previousSpaceId ?: parentSpaceId)
|
setCurrentSpace(previousSpaceId ?: parentSpaceId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setCurrentSpace(spaceId: String?) {
|
private fun setCurrentSpace(spaceId: String?) {
|
||||||
appStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false)
|
spaceStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false)
|
||||||
sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace)
|
sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ class NewHomeDetailFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshSpaceState() {
|
private fun refreshSpaceState() {
|
||||||
appStateHandler.getCurrentSpace()?.let {
|
spaceStateHandler.getCurrentSpace()?.let {
|
||||||
onSpaceChange(it)
|
onSpaceChange(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,7 +450,7 @@ class NewHomeDetailFragment @Inject constructor(
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed(toolbarButton: Boolean) = if (appStateHandler.getCurrentSpace() != null) {
|
override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) {
|
||||||
navigateBack()
|
navigateBack()
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -25,8 +25,7 @@ sealed class RoomListQuickActionsSharedAction(
|
||||||
@StringRes val titleRes: Int,
|
@StringRes val titleRes: Int,
|
||||||
@DrawableRes val iconResId: Int?,
|
@DrawableRes val iconResId: Int?,
|
||||||
val destructive: Boolean = false
|
val destructive: Boolean = false
|
||||||
) :
|
) : VectorSharedAction {
|
||||||
VectorSharedAction {
|
|
||||||
|
|
||||||
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActionsSharedAction(
|
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActionsSharedAction(
|
||||||
R.string.room_list_quick_actions_notifications_all_noisy,
|
R.string.room_list_quick_actions_notifications_all_noisy,
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.home.room.list.actions
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorSharedAction
|
||||||
|
|
||||||
|
sealed class RoomListSharedAction : VectorSharedAction {
|
||||||
|
|
||||||
|
object CloseBottomSheet : RoomListSharedAction()
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.home.room.list.actions
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorSharedActionViewModel
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RoomListSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel<RoomListSharedAction>()
|
|
@ -43,9 +43,12 @@ import im.vector.app.features.home.room.list.RoomSummaryItemFactory
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction
|
||||||
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel
|
||||||
|
import im.vector.app.features.home.room.list.actions.RoomListSharedAction
|
||||||
|
import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
|
||||||
import im.vector.app.features.home.room.list.home.filter.HomeFilteredRoomsController
|
import im.vector.app.features.home.room.list.home.filter.HomeFilteredRoomsController
|
||||||
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
|
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
|
||||||
import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController
|
import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController
|
||||||
|
import im.vector.app.features.spaces.SpaceListBottomSheet
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
@ -62,10 +65,13 @@ class HomeRoomListFragment @Inject constructor(
|
||||||
RoomListListener {
|
RoomListListener {
|
||||||
|
|
||||||
private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel()
|
private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel()
|
||||||
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
private lateinit var sharedQuickActionsViewModel: RoomListQuickActionsSharedActionViewModel
|
||||||
|
private lateinit var sharedActionViewModel: RoomListSharedActionViewModel
|
||||||
private var concatAdapter = ConcatAdapter()
|
private var concatAdapter = ConcatAdapter()
|
||||||
private var modelBuildListener: OnModelBuildFinishedListener? = null
|
private var modelBuildListener: OnModelBuildFinishedListener? = null
|
||||||
|
|
||||||
|
private val spaceListBottomSheet = SpaceListBottomSheet()
|
||||||
|
|
||||||
private lateinit var stateRestorer: LayoutManagerStateRestorer
|
private lateinit var stateRestorer: LayoutManagerStateRestorer
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding {
|
||||||
|
@ -74,15 +80,25 @@ class HomeRoomListFragment @Inject constructor(
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
sharedActionViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java]
|
|
||||||
sharedActionViewModel
|
|
||||||
.stream()
|
|
||||||
.onEach { handleQuickActions(it) }
|
|
||||||
.launchIn(viewLifecycleOwner.lifecycleScope)
|
|
||||||
|
|
||||||
views.stateView.contentView = views.roomListView
|
views.stateView.contentView = views.roomListView
|
||||||
views.stateView.state = StateView.State.Loading
|
views.stateView.state = StateView.State.Loading
|
||||||
|
setupObservers()
|
||||||
|
setupRecyclerView()
|
||||||
|
setupFabs()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupObservers() {
|
||||||
|
sharedQuickActionsViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java]
|
||||||
|
sharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java]
|
||||||
|
|
||||||
|
sharedActionViewModel
|
||||||
|
.stream()
|
||||||
|
.onEach(::handleSharedAction)
|
||||||
|
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||||
|
sharedQuickActionsViewModel
|
||||||
|
.stream()
|
||||||
|
.onEach(::handleQuickActions)
|
||||||
|
.launchIn(viewLifecycleOwner.lifecycleScope)
|
||||||
|
|
||||||
roomListViewModel.observeViewEvents {
|
roomListViewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -92,9 +108,42 @@ class HomeRoomListFragment @Inject constructor(
|
||||||
is HomeRoomListViewEvents.Done -> Unit
|
is HomeRoomListViewEvents.Done -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setupRecyclerView()
|
private fun handleSharedAction(action: RoomListSharedAction) {
|
||||||
setupFabs()
|
when (action) {
|
||||||
|
RoomListSharedAction.CloseBottomSheet -> spaceListBottomSheet.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
|
||||||
|
when (quickAction) {
|
||||||
|
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.NotificationsAll -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES))
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MENTIONS_ONLY))
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.NotificationsMute -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MUTE))
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.Settings -> {
|
||||||
|
navigator.openRoomProfile(requireActivity(), quickAction.roomId)
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.Favorite -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_FAVOURITE))
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.LowPriority -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_LOW_PRIORITY))
|
||||||
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.Leave -> {
|
||||||
|
roomListViewModel.handle(HomeRoomListAction.LeaveRoom(quickAction.roomId))
|
||||||
|
promptLeaveRoom(quickAction.roomId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupRecyclerView() {
|
private fun setupRecyclerView() {
|
||||||
|
@ -121,7 +170,8 @@ class HomeRoomListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
views.newLayoutOpenSpacesButton.setOnClickListener {
|
views.newLayoutOpenSpacesButton.setOnClickListener {
|
||||||
// Click action for open spaces modal goes here (Issue #6499)
|
// Click action for open spaces modal goes here
|
||||||
|
spaceListBottomSheet.show(requireActivity().supportFragmentManager, SpaceListBottomSheet.TAG)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide FABs when list is scrolling
|
// Hide FABs when list is scrolling
|
||||||
|
@ -158,36 +208,6 @@ class HomeRoomListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
|
|
||||||
when (quickAction) {
|
|
||||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY))
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.NotificationsAll -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES))
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MENTIONS_ONLY))
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.NotificationsMute -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MUTE))
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.Settings -> {
|
|
||||||
navigator.openRoomProfile(requireActivity(), quickAction.roomId)
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.Favorite -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_FAVOURITE))
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.LowPriority -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_LOW_PRIORITY))
|
|
||||||
}
|
|
||||||
is RoomListQuickActionsSharedAction.Leave -> {
|
|
||||||
roomListViewModel.handle(HomeRoomListAction.LeaveRoom(quickAction.roomId))
|
|
||||||
promptLeaveRoom(quickAction.roomId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun promptLeaveRoom(roomId: String) {
|
private fun promptLeaveRoom(roomId: String) {
|
||||||
val isPublicRoom = roomListViewModel.isPublicRoom(roomId)
|
val isPublicRoom = roomListViewModel.isPublicRoom(roomId)
|
||||||
val message = buildString {
|
val message = buildString {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.content.res.ColorStateList
|
||||||
|
import android.widget.ImageView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class NewSpaceAddItem : VectorEpoxyModel<NewSpaceAddItem.Holder>(R.layout.item_new_space_add) {
|
||||||
|
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.view.onClick(listener)
|
||||||
|
|
||||||
|
holder.plus.imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_primary))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val plus by bind<ImageView>(R.id.plus)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* 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 com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class NewSpaceListHeaderItem : VectorEpoxyModel<NewSpaceListHeaderItem.Holder>(R.layout.item_new_space_list_header) {
|
||||||
|
class Holder : VectorEpoxyHolder()
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* 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 com.airbnb.epoxy.EpoxyController
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import im.vector.app.features.grouplist.newHomeSpaceSummaryItem
|
||||||
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
|
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class NewSpaceSummaryController @Inject constructor(
|
||||||
|
private val avatarRenderer: AvatarRenderer,
|
||||||
|
private val stringProvider: StringProvider,
|
||||||
|
) : EpoxyController() {
|
||||||
|
|
||||||
|
var callback: Callback? = null
|
||||||
|
private var viewState: SpaceListViewState? = null
|
||||||
|
|
||||||
|
private val subSpaceComparator: Comparator<SpaceChildInfo> = compareBy<SpaceChildInfo> { it.order }.thenBy { it.childRoomId }
|
||||||
|
|
||||||
|
fun update(viewState: SpaceListViewState) {
|
||||||
|
this.viewState = viewState
|
||||||
|
requestModelBuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildModels() {
|
||||||
|
val nonNullViewState = viewState ?: return
|
||||||
|
buildGroupModels(
|
||||||
|
nonNullViewState.spaces,
|
||||||
|
nonNullViewState.selectedSpace,
|
||||||
|
nonNullViewState.rootSpacesOrdered,
|
||||||
|
nonNullViewState.homeAggregateCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildGroupModels(
|
||||||
|
spaceSummaries: List<RoomSummary>?,
|
||||||
|
selectedSpace: RoomSummary?,
|
||||||
|
rootSpaces: List<RoomSummary>?,
|
||||||
|
homeCount: RoomAggregateNotificationCount
|
||||||
|
) {
|
||||||
|
val host = this
|
||||||
|
newSpaceListHeaderItem {
|
||||||
|
id("space_list_header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedSpace != null) {
|
||||||
|
addSubSpaces(selectedSpace, spaceSummaries, homeCount)
|
||||||
|
} else {
|
||||||
|
addHomeItem(true, homeCount)
|
||||||
|
addRootSpaces(rootSpaces)
|
||||||
|
}
|
||||||
|
|
||||||
|
newSpaceAddItem {
|
||||||
|
id("create")
|
||||||
|
listener { host.callback?.onAddSpaceSelected() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addHomeItem(selected: Boolean, homeCount: RoomAggregateNotificationCount) {
|
||||||
|
val host = this
|
||||||
|
newHomeSpaceSummaryItem {
|
||||||
|
id("space_home")
|
||||||
|
text(host.stringProvider.getString(R.string.all_chats))
|
||||||
|
selected(selected)
|
||||||
|
countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight))
|
||||||
|
listener { host.callback?.onSpaceSelected(null) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addSubSpaces(
|
||||||
|
selectedSpace: RoomSummary,
|
||||||
|
spaceSummaries: List<RoomSummary>?,
|
||||||
|
homeCount: RoomAggregateNotificationCount,
|
||||||
|
) {
|
||||||
|
val host = this
|
||||||
|
val spaceChildren = selectedSpace.spaceChildren
|
||||||
|
var subSpacesAdded = false
|
||||||
|
|
||||||
|
spaceChildren?.sortedWith(subSpaceComparator)?.forEach { spaceChild ->
|
||||||
|
val subSpaceSummary = spaceSummaries?.firstOrNull { it.roomId == spaceChild.childRoomId } ?: return@forEach
|
||||||
|
|
||||||
|
if (subSpaceSummary.membership != Membership.INVITE) {
|
||||||
|
subSpacesAdded = true
|
||||||
|
newSpaceSummaryItem {
|
||||||
|
avatarRenderer(host.avatarRenderer)
|
||||||
|
id(subSpaceSummary.roomId)
|
||||||
|
matrixItem(subSpaceSummary.toMatrixItem())
|
||||||
|
selected(false)
|
||||||
|
listener { host.callback?.onSpaceSelected(subSpaceSummary) }
|
||||||
|
countState(
|
||||||
|
UnreadCounterBadgeView.State(
|
||||||
|
subSpaceSummary.notificationCount,
|
||||||
|
subSpaceSummary.highlightCount > 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subSpacesAdded) {
|
||||||
|
addHomeItem(false, homeCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addRootSpaces(rootSpaces: List<RoomSummary>?) {
|
||||||
|
val host = this
|
||||||
|
rootSpaces
|
||||||
|
?.filter { it.membership != Membership.INVITE }
|
||||||
|
?.forEach { roomSummary ->
|
||||||
|
newSpaceSummaryItem {
|
||||||
|
avatarRenderer(host.avatarRenderer)
|
||||||
|
id(roomSummary.roomId)
|
||||||
|
matrixItem(roomSummary.toMatrixItem())
|
||||||
|
listener { host.callback?.onSpaceSelected(roomSummary) }
|
||||||
|
countState(UnreadCounterBadgeView.State(roomSummary.notificationCount, roomSummary.highlightCount > 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callback {
|
||||||
|
fun onSpaceSelected(spaceSummary: RoomSummary?)
|
||||||
|
fun onSpaceInviteSelected(spaceSummary: RoomSummary)
|
||||||
|
fun onSpaceSettings(spaceSummary: RoomSummary)
|
||||||
|
fun onAddSpaceSelected()
|
||||||
|
fun sendFeedBack()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
import im.vector.app.core.platform.CheckableConstraintLayout
|
||||||
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class NewSpaceSummaryItem : VectorEpoxyModel<NewSpaceSummaryItem.Holder>(R.layout.item_new_space) {
|
||||||
|
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var avatarRenderer: AvatarRenderer
|
||||||
|
@EpoxyAttribute lateinit var matrixItem: MatrixItem
|
||||||
|
@EpoxyAttribute var selected: Boolean = false
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
||||||
|
@EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.rootView.onClick(listener)
|
||||||
|
holder.name.text = matrixItem.displayName
|
||||||
|
holder.rootView.isChecked = selected
|
||||||
|
|
||||||
|
avatarRenderer.render(matrixItem, holder.avatar)
|
||||||
|
holder.unreadCounter.render(countState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun unbind(holder: Holder) {
|
||||||
|
avatarRenderer.clear(holder.avatar)
|
||||||
|
super.unbind(holder)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val rootView by bind<CheckableConstraintLayout>(R.id.root)
|
||||||
|
val avatar by bind<ImageView>(R.id.avatar)
|
||||||
|
val name by bind<TextView>(R.id.name)
|
||||||
|
val unreadCounter by bind<UnreadCounterBadgeView>(R.id.unread_counter)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 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.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.extensions.replaceChildFragment
|
||||||
|
import im.vector.app.databinding.FragmentSpacesBottomSheetBinding
|
||||||
|
|
||||||
|
class SpaceListBottomSheet : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private lateinit var binding: FragmentSpacesBottomSheetBinding
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
binding = FragmentSpacesBottomSheetBinding.inflate(inflater, container, false)
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
replaceChildFragment(R.id.space_list, SpaceListFragment::class.java)
|
||||||
|
}
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "SpacesBottomSheet"
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,20 +32,29 @@ import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.StateView
|
import im.vector.app.core.platform.StateView
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentSpaceListBinding
|
import im.vector.app.databinding.FragmentSpaceListBinding
|
||||||
|
import im.vector.app.features.VectorFeatures
|
||||||
import im.vector.app.features.home.HomeActivitySharedAction
|
import im.vector.app.features.home.HomeActivitySharedAction
|
||||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
import im.vector.app.features.home.HomeSharedActionViewModel
|
||||||
|
import im.vector.app.features.home.room.list.actions.RoomListSharedAction
|
||||||
|
import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Fragment is displayed in the navigation drawer [im.vector.app.features.home.HomeDrawerFragment] and
|
* This Fragment is displayed in the navigation drawer [im.vector.app.features.home.HomeDrawerFragment] and
|
||||||
* is displaying the space hierarchy, with some actions on Spaces.
|
* is displaying the space hierarchy, with some actions on Spaces.
|
||||||
|
*
|
||||||
|
* In the New App Layout this fragment will instead be displayed in a Bottom Sheet [SpaceListBottomSheet]
|
||||||
|
* and will only display spaces that are direct children of the currently selected space (or root spaces if none)
|
||||||
*/
|
*/
|
||||||
class SpaceListFragment @Inject constructor(
|
class SpaceListFragment @Inject constructor(
|
||||||
private val spaceController: SpaceSummaryController
|
private val spaceController: SpaceSummaryController,
|
||||||
) : VectorBaseFragment<FragmentSpaceListBinding>(), SpaceSummaryController.Callback {
|
private val newSpaceController: NewSpaceSummaryController,
|
||||||
|
private val vectorFeatures: VectorFeatures,
|
||||||
|
) : VectorBaseFragment<FragmentSpaceListBinding>(), SpaceSummaryController.Callback, NewSpaceSummaryController.Callback {
|
||||||
|
|
||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
private lateinit var homeActivitySharedActionViewModel: HomeSharedActionViewModel
|
||||||
|
private lateinit var roomListSharedActionViewModel: RoomListSharedActionViewModel
|
||||||
private val viewModel: SpaceListViewModel by fragmentViewModel()
|
private val viewModel: SpaceListViewModel by fragmentViewModel()
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSpaceListBinding {
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSpaceListBinding {
|
||||||
|
@ -54,10 +63,69 @@ class SpaceListFragment @Inject constructor(
|
||||||
|
|
||||||
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(HomeSharedActionViewModel::class.java)
|
homeActivitySharedActionViewModel = activityViewModelProvider[HomeSharedActionViewModel::class.java]
|
||||||
spaceController.callback = this
|
roomListSharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java]
|
||||||
views.stateView.contentView = views.groupListView
|
views.stateView.contentView = views.groupListView
|
||||||
views.groupListView.configureWith(spaceController)
|
setupSpaceController()
|
||||||
|
observeViewEvents()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupSpaceController() {
|
||||||
|
if (vectorFeatures.isNewAppLayoutEnabled()) {
|
||||||
|
enableDragAndDropForNewSpaceController()
|
||||||
|
newSpaceController.callback = this
|
||||||
|
views.groupListView.configureWith(newSpaceController)
|
||||||
|
} else {
|
||||||
|
enableDragAndDropForSpaceController()
|
||||||
|
spaceController.callback = this
|
||||||
|
views.groupListView.configureWith(spaceController)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enableDragAndDropForNewSpaceController() {
|
||||||
|
EpoxyTouchHelper.initDragging(newSpaceController)
|
||||||
|
.withRecyclerView(views.groupListView)
|
||||||
|
.forVerticalList()
|
||||||
|
.withTarget(NewSpaceSummaryItem::class.java)
|
||||||
|
.andCallbacks(object : EpoxyTouchHelper.DragCallbacks<NewSpaceSummaryItem>() {
|
||||||
|
var toPositionM: Int? = null
|
||||||
|
var fromPositionM: Int? = null
|
||||||
|
var initialElevation: Float? = null
|
||||||
|
|
||||||
|
override fun onDragStarted(model: NewSpaceSummaryItem?, itemView: View?, adapterPosition: Int) {
|
||||||
|
toPositionM = null
|
||||||
|
fromPositionM = null
|
||||||
|
model?.matrixItem?.id?.let {
|
||||||
|
viewModel.handle(SpaceListAction.OnStartDragging(it, false))
|
||||||
|
}
|
||||||
|
itemView?.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
|
initialElevation = itemView?.elevation
|
||||||
|
itemView?.elevation = 6f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDragReleased(model: NewSpaceSummaryItem?, itemView: View?) {
|
||||||
|
if (toPositionM == null || fromPositionM == null) return
|
||||||
|
val movedSpaceId = model?.matrixItem?.id ?: return
|
||||||
|
viewModel.handle(SpaceListAction.MoveSpace(movedSpaceId, toPositionM!! - fromPositionM!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(model: NewSpaceSummaryItem?, itemView: View?) {
|
||||||
|
itemView?.elevation = initialElevation ?: 0f
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onModelMoved(fromPosition: Int, toPosition: Int, modelBeingMoved: NewSpaceSummaryItem?, itemView: View?) {
|
||||||
|
if (fromPositionM == null) {
|
||||||
|
fromPositionM = fromPosition
|
||||||
|
}
|
||||||
|
if (toPositionM != toPosition) {
|
||||||
|
toPositionM = toPosition
|
||||||
|
itemView?.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enableDragAndDropForSpaceController() {
|
||||||
EpoxyTouchHelper.initDragging(spaceController)
|
EpoxyTouchHelper.initDragging(spaceController)
|
||||||
.withRecyclerView(views.groupListView)
|
.withRecyclerView(views.groupListView)
|
||||||
.forVerticalList()
|
.forVerticalList()
|
||||||
|
@ -100,14 +168,14 @@ class SpaceListFragment @Inject constructor(
|
||||||
return model?.canDrag == true
|
return model?.canDrag == true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.observeViewEvents {
|
private fun observeViewEvents() = viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id))
|
is SpaceListViewEvents.OpenSpaceSummary -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id))
|
||||||
is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
is SpaceListViewEvents.AddSpace -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
||||||
is SpaceListViewEvents.OpenSpaceInvite -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id))
|
is SpaceListViewEvents.OpenSpaceInvite -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id))
|
||||||
SpaceListViewEvents.CloseDrawer -> sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
|
SpaceListViewEvents.CloseDrawer -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,11 +192,17 @@ class SpaceListFragment @Inject constructor(
|
||||||
is Success -> views.stateView.state = StateView.State.Content
|
is Success -> views.stateView.state = StateView.State.Content
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
spaceController.update(state)
|
|
||||||
|
if (vectorFeatures.isNewAppLayoutEnabled()) {
|
||||||
|
newSpaceController.update(state)
|
||||||
|
} else {
|
||||||
|
spaceController.update(state)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSpaceSelected(spaceSummary: RoomSummary?) {
|
override fun onSpaceSelected(spaceSummary: RoomSummary?) {
|
||||||
viewModel.handle(SpaceListAction.SelectSpace(spaceSummary))
|
viewModel.handle(SpaceListAction.SelectSpace(spaceSummary))
|
||||||
|
roomListSharedActionViewModel.post(RoomListSharedAction.CloseBottomSheet)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSpaceInviteSelected(spaceSummary: RoomSummary) {
|
override fun onSpaceInviteSelected(spaceSummary: RoomSummary) {
|
||||||
|
@ -136,7 +210,7 @@ class SpaceListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSpaceSettings(spaceSummary: RoomSummary) {
|
override fun onSpaceSettings(spaceSummary: RoomSummary) {
|
||||||
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId))
|
homeActivitySharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onToggleExpand(spaceSummary: RoomSummary) {
|
override fun onToggleExpand(spaceSummary: RoomSummary) {
|
||||||
|
@ -148,6 +222,6 @@ class SpaceListFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendFeedBack() {
|
override fun sendFeedBack() {
|
||||||
sharedActionViewModel.post(HomeActivitySharedAction.SendSpaceFeedBack)
|
homeActivitySharedActionViewModel.post(HomeActivitySharedAction.SendSpaceFeedBack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ class SpaceListViewModel @AssistedInject constructor(
|
||||||
val moved = removeAt(index)
|
val moved = removeAt(index)
|
||||||
add(index + action.delta, moved)
|
add(index + action.delta, moved)
|
||||||
},
|
},
|
||||||
spaceOrderLocalEchos = updatedLocalEchos
|
spaceOrderLocalEchos = updatedLocalEchos,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
session.coroutineScope.launch {
|
session.coroutineScope.launch {
|
||||||
|
@ -257,29 +257,29 @@ class SpaceListViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
combine(
|
combine(
|
||||||
session.flow()
|
session.flow().liveSpaceSummaries(params),
|
||||||
.liveSpaceSummaries(params),
|
|
||||||
session.accountDataService()
|
session.accountDataService()
|
||||||
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
|
.getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER))
|
||||||
.asFlow()
|
.asFlow()
|
||||||
) { spaces, _ ->
|
) { spaces, _ ->
|
||||||
spaces
|
spaces
|
||||||
|
}.execute { asyncSpaces ->
|
||||||
|
val spaces = asyncSpaces.invoke().orEmpty()
|
||||||
|
val rootSpaces = asyncSpaces.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() }
|
||||||
|
val orders = rootSpaces.associate {
|
||||||
|
it.roomId to session.getRoom(it.roomId)
|
||||||
|
?.roomAccountDataService()
|
||||||
|
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
|
||||||
|
?.content.toModel<SpaceOrderContent>()
|
||||||
|
?.safeOrder()
|
||||||
|
}
|
||||||
|
copy(
|
||||||
|
asyncSpaces = asyncSpaces,
|
||||||
|
spaces = spaces,
|
||||||
|
rootSpacesOrdered = rootSpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
||||||
|
spaceOrderInfo = orders
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.execute { async ->
|
|
||||||
val rootSpaces = async.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() }
|
|
||||||
val orders = rootSpaces.associate {
|
|
||||||
it.roomId to session.getRoom(it.roomId)
|
|
||||||
?.roomAccountDataService()
|
|
||||||
?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)
|
|
||||||
?.content.toModel<SpaceOrderContent>()
|
|
||||||
?.safeOrder()
|
|
||||||
}
|
|
||||||
copy(
|
|
||||||
asyncSpaces = async,
|
|
||||||
rootSpacesOrdered = rootSpaces.sortedWith(TopLevelSpaceComparator(orders)),
|
|
||||||
spaceOrderInfo = orders
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear local echos on update
|
// clear local echos on update
|
||||||
session.accountDataService()
|
session.accountDataService()
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
data class SpaceListViewState(
|
data class SpaceListViewState(
|
||||||
val myMxItem: Async<MatrixItem.UserItem> = Uninitialized,
|
val myMxItem: Async<MatrixItem.UserItem> = Uninitialized,
|
||||||
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
||||||
|
val spaces: List<RoomSummary> = emptyList(),
|
||||||
val selectedSpace: RoomSummary? = null,
|
val selectedSpace: RoomSummary? = null,
|
||||||
val rootSpacesOrdered: List<RoomSummary>? = null,
|
val rootSpacesOrdered: List<RoomSummary>? = null,
|
||||||
val spaceOrderInfo: Map<String, String?>? = null,
|
val spaceOrderInfo: Map<String, String?>? = null,
|
||||||
|
|
11
vector/src/main/res/drawable/ic_plus.xml
Normal file
11
vector/src/main/res/drawable/ic_plus.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<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="M12.7822,4.2963C12.7822,3.8641 12.4318,3.5137 11.9996,3.5137C11.5673,3.5137 11.217,3.8641 11.217,4.2963V11.2173L4.2963,11.2173C3.8641,11.2173 3.5137,11.5676 3.5137,11.9999C3.5137,12.4321 3.8641,12.7825 4.2963,12.7825H11.217V19.7038C11.217,20.136 11.5673,20.4864 11.9996,20.4864C12.4318,20.4864 12.7822,20.136 12.7822,19.7038V12.7825H19.7038C20.136,12.7825 20.4864,12.4321 20.4864,11.9999C20.4864,11.5676 20.136,11.2173 19.7038,11.2173L12.7822,11.2173V4.2963Z"
|
||||||
|
android:fillColor="#17191C"
|
||||||
|
android:fillType="evenOdd"/>
|
||||||
|
</vector>
|
||||||
|
|
11
vector/src/main/res/drawable/new_space_home_background.xml
Normal file
11
vector/src/main/res/drawable/new_space_home_background.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<size android:width="40dp" android:height="40dp"/>
|
||||||
|
|
||||||
|
<solid android:color="?android:colorBackground" />
|
||||||
|
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
|
||||||
|
</shape>
|
|
@ -10,4 +10,4 @@
|
||||||
|
|
||||||
<corners android:radius="8dp" />
|
<corners android:radius="8dp" />
|
||||||
|
|
||||||
</shape>
|
</shape>
|
||||||
|
|
|
@ -1,101 +1,107 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<im.vector.app.core.platform.StateView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/stateView"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:background="?android:colorBackground">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<im.vector.app.core.platform.StateView
|
||||||
android:id="@+id/roomListView"
|
android:id="@+id/stateView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:overScrollMode="always"
|
android:background="?android:colorBackground">
|
||||||
tools:itemCount="5"
|
|
||||||
tools:listitem="@layout/item_room" />
|
|
||||||
|
|
||||||
<im.vector.app.features.home.room.list.widget.NotifsFabMenuView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/createChatFabMenu"
|
android:id="@+id/roomListView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"
|
android:overScrollMode="always"
|
||||||
app:layoutDescription="@xml/motion_scene_notifs_fab_menu"
|
tools:itemCount="5"
|
||||||
tools:showPaths="true"
|
tools:listitem="@layout/item_room" />
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<im.vector.app.features.home.room.list.widget.NotifsFabMenuView
|
||||||
android:id="@+id/createChatRoomButton"
|
android:id="@+id/createChatFabMenu"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:accessibilityTraversalBefore="@id/roomListView"
|
|
||||||
android:contentDescription="@string/a11y_create_direct_message"
|
|
||||||
android:scaleType="center"
|
|
||||||
android:src="@drawable/ic_fab_add_chat"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:maxImageSize="34dp"
|
|
||||||
tools:layout_marginEnd="80dp"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/createGroupRoomButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:accessibilityTraversalBefore="@id/roomListView"
|
|
||||||
android:contentDescription="@string/a11y_create_room"
|
|
||||||
android:src="@drawable/ic_fab_add_room"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:maxImageSize="32dp"
|
|
||||||
tools:layout_marginEnd="144dp"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_gravity="bottom|end">
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/newLayoutOpenSpacesButton"
|
|
||||||
style="@style/Widget.Vector.FloatingActionButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="20dp"
|
|
||||||
android:accessibilityTraversalAfter="@id/newLayoutCreateChatButton"
|
|
||||||
android:contentDescription="@string/a11y_open_spaces"
|
|
||||||
android:src="@drawable/ic_open_spaces"
|
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:backgroundTint="?attr/vctr_toolbar_background"
|
app:layoutDescription="@xml/motion_scene_notifs_fab_menu"
|
||||||
app:fabSize="mini"
|
tools:showPaths="true"
|
||||||
app:layout_constraintBottom_toTopOf="@id/newLayoutCreateChatButton"
|
tools:visibility="visible" />
|
||||||
app:layout_constraintEnd_toEndOf="@id/newLayoutCreateChatButton"
|
|
||||||
app:layout_constraintStart_toStartOf="@id/newLayoutCreateChatButton"
|
|
||||||
app:tint="?attr/colorPrimary"
|
|
||||||
tools:visibility="visible"
|
|
||||||
tools:targetApi="lollipop_mr1" />
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/newLayoutCreateChatButton"
|
android:id="@+id/createChatRoomButton"
|
||||||
style="@style/Widget.Vector.FloatingActionButton"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:accessibilityTraversalBefore="@id/roomListView"
|
android:accessibilityTraversalBefore="@id/roomListView"
|
||||||
android:contentDescription="@string/a11y_create_message"
|
android:contentDescription="@string/a11y_create_direct_message"
|
||||||
android:src="@drawable/ic_new_chat"
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_fab_add_chat"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:maxImageSize="34dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
tools:layout_marginEnd="80dp"
|
||||||
tools:visibility="visible"
|
tools:visibility="visible" />
|
||||||
tools:targetApi="lollipop_mr1" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/createGroupRoomButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:accessibilityTraversalBefore="@id/roomListView"
|
||||||
|
android:contentDescription="@string/a11y_create_room"
|
||||||
|
android:src="@drawable/ic_fab_add_room"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:maxImageSize="32dp"
|
||||||
|
tools:layout_marginEnd="144dp"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
</im.vector.app.core.platform.StateView>
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="bottom|end">
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/newLayoutOpenSpacesButton"
|
||||||
|
style="@style/Widget.Vector.FloatingActionButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:accessibilityTraversalAfter="@id/newLayoutCreateChatButton"
|
||||||
|
android:contentDescription="@string/a11y_open_spaces"
|
||||||
|
android:src="@drawable/ic_open_spaces"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:backgroundTint="?attr/vctr_toolbar_background"
|
||||||
|
app:fabSize="mini"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/newLayoutCreateChatButton"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/newLayoutCreateChatButton"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/newLayoutCreateChatButton"
|
||||||
|
app:tint="?attr/colorPrimary"
|
||||||
|
tools:targetApi="lollipop_mr1"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/newLayoutCreateChatButton"
|
||||||
|
style="@style/Widget.Vector.FloatingActionButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:accessibilityTraversalBefore="@id/roomListView"
|
||||||
|
android:contentDescription="@string/a11y_create_message"
|
||||||
|
android:src="@drawable/ic_new_chat"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
tools:targetApi="lollipop_mr1"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</im.vector.app.core.platform.StateView>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
11
vector/src/main/res/layout/fragment_spaces_bottom_sheet.xml
Normal file
11
vector/src/main/res/layout/fragment_spaces_bottom_sheet.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.fragment.app.FragmentContainerView
|
||||||
|
android:id="@+id/space_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
77
vector/src/main/res/layout/item_new_space.xml
Normal file
77
vector/src/main/res/layout/item_new_space.xml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<im.vector.app.core.platform.CheckableConstraintLayout 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/root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="65dp"
|
||||||
|
android:background="@drawable/bg_space_item"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
tools:viewBindingIgnore="true">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/avatar"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:src="@sample/space_avatars" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/name"
|
||||||
|
style="@style/Widget.Vector.TextView.Subtitle"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?vctr_content_primary"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/unread_counter"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Element Corp" />
|
||||||
|
|
||||||
|
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
android:id="@+id/unread_counter"
|
||||||
|
style="@style/Widget.Vector.TextView.Micro"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="16dp"
|
||||||
|
android:minHeight="16dp"
|
||||||
|
android:paddingStart="4dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
|
android:textColor="?colorOnError"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/chevron"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
tools:background="@drawable/bg_unread_highlight"
|
||||||
|
tools:text="147"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/chevron"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="21dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_arrow_right"
|
||||||
|
android:visibility="visible"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:tint="?vctr_content_secondary"
|
||||||
|
tools:ignore="MissingPrefix" />
|
||||||
|
|
||||||
|
</im.vector.app.core.platform.CheckableConstraintLayout>
|
54
vector/src/main/res/layout/item_new_space_add.xml
Normal file
54
vector/src/main/res/layout/item_new_space_add.xml
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<im.vector.app.core.platform.CheckableConstraintLayout 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/itemGroupLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="65dp"
|
||||||
|
android:background="@drawable/bg_space_item"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
tools:viewBindingIgnore="true">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="26dp"
|
||||||
|
android:background="?attr/vctr_system"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/plus"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:background="@drawable/rounded_rect_shape_8"
|
||||||
|
android:backgroundTint="#4D8D97A5"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/ic_plus"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/groupNameView"
|
||||||
|
style="@style/Widget.Vector.TextView.Subtitle.Medium"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/create_space"
|
||||||
|
android:textColor="?vctr_message_text_color"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/plus"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</im.vector.app.core.platform.CheckableConstraintLayout>
|
16
vector/src/main/res/layout/item_new_space_list_header.xml
Normal file
16
vector/src/main/res/layout/item_new_space_list_header.xml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
style="@style/TextAppearance.Vector.Body.Medium"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_space_item"
|
||||||
|
android:ellipsize="middle"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/change_space"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="?vctr_content_tertiary"
|
||||||
|
android:textSize="14sp"
|
||||||
|
tools:viewBindingIgnore="true" />
|
|
@ -137,6 +137,7 @@
|
||||||
|
|
||||||
<!-- Home Screen -->
|
<!-- Home Screen -->
|
||||||
<string name="all_chats">All Chats</string>
|
<string name="all_chats">All Chats</string>
|
||||||
|
<string name="change_space">Change Space</string>
|
||||||
|
|
||||||
<!-- Last seen time -->
|
<!-- Last seen time -->
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue