mirror of
https://github.com/vector-im/riotX-android
synced 2025-10-06 00:02:48 +02:00
Compare commits
5 Commits
bug/eric/f
...
feature/ro
Author | SHA1 | Date | |
---|---|---|---|
|
ad9f67b3bd | ||
|
3ae0586dac | ||
|
19b411776a | ||
|
ddbc2b0ade | ||
|
5f79530c4c |
@@ -112,7 +112,7 @@ android {
|
||||
ndkVersion "21.3.6528147"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "im.vector.app"
|
||||
applicationId "im.vector.app.tabs"
|
||||
// Set to API 21: see #405
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
@@ -186,7 +186,7 @@ android {
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
resValue "string", "app_name", "Element dbg"
|
||||
resValue "string", "app_name", "Element Tabs"
|
||||
|
||||
resValue "bool", "debug_mode", "true"
|
||||
buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false"
|
||||
|
@@ -10,7 +10,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:912726360885:android:4ef8f3a0021e774d",
|
||||
"android_client_info": {
|
||||
"package_name": "im.vector.app.debug"
|
||||
"package_name": "im.vector.app.tabs.debug"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
|
@@ -10,7 +10,7 @@
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:912726360885:android:4ef8f3a0021e774d",
|
||||
"android_client_info": {
|
||||
"package_name": "im.vector.app"
|
||||
"package_name": "im.vector.app.tabs"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
|
@@ -52,6 +52,7 @@ import im.vector.app.features.home.LoadingFragment
|
||||
import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment
|
||||
import im.vector.app.features.home.room.detail.RoomDetailFragment
|
||||
import im.vector.app.features.home.room.list.RoomListFragment
|
||||
import im.vector.app.features.home.room.list.tabs.RoomListTabsFragment
|
||||
import im.vector.app.features.login.LoginCaptchaFragment
|
||||
import im.vector.app.features.login.LoginFragment
|
||||
import im.vector.app.features.login.LoginGenericTextInputFormFragment
|
||||
@@ -124,6 +125,11 @@ interface FragmentModule {
|
||||
@FragmentKey(RoomListFragment::class)
|
||||
fun bindRoomListFragment(fragment: RoomListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(RoomListTabsFragment::class)
|
||||
fun bindRoomListTabsFragment(fragment: RoomListTabsFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(LocalePickerFragment::class)
|
||||
|
@@ -123,7 +123,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
|
||||
drawerLayout.closeDrawer(GravityCompat.START)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
.disposeOnDestroy()
|
||||
|
||||
|
@@ -25,4 +25,5 @@ sealed class HomeActivitySharedAction : VectorSharedAction {
|
||||
object OpenDrawer : HomeActivitySharedAction()
|
||||
object CloseDrawer : HomeActivitySharedAction()
|
||||
object OpenGroup : HomeActivitySharedAction()
|
||||
data class OnDisplayModeSelected(val displayMode: RoomListDisplayMode): HomeActivitySharedAction()
|
||||
}
|
||||
|
@@ -18,13 +18,17 @@ package im.vector.app.features.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Observer
|
||||
import com.airbnb.mvrx.activityViewModel
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.badge.BadgeDrawable
|
||||
import com.google.android.material.behavior.HideBottomViewOnScrollBehavior
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.extensions.addFragment
|
||||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.glide.GlideApp
|
||||
import im.vector.app.core.platform.ToolbarConfigurable
|
||||
@@ -38,6 +42,8 @@ import im.vector.app.features.call.VectorCallActivity
|
||||
import im.vector.app.features.call.WebRtcPeerConnectionManager
|
||||
import im.vector.app.features.home.room.list.RoomListFragment
|
||||
import im.vector.app.features.home.room.list.RoomListParams
|
||||
import im.vector.app.features.home.room.list.tabs.RoomListTabsFragment
|
||||
import im.vector.app.features.home.room.list.widget.FabMenuView
|
||||
import im.vector.app.features.popup.PopupAlertManager
|
||||
import im.vector.app.features.popup.VerificationVectorAlert
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
@@ -64,7 +70,7 @@ class HomeDetailFragment @Inject constructor(
|
||||
private val alertManager: PopupAlertManager,
|
||||
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager,
|
||||
private val vectorPreferences: VectorPreferences
|
||||
) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory {
|
||||
) : VectorBaseFragment(), KeysBackupBanner.Delegate, ActiveCallView.Callback, ServerBackupStatusViewModel.Factory, FabMenuView.Listener {
|
||||
|
||||
private val viewModel: HomeDetailViewModel by fragmentViewModel()
|
||||
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
|
||||
@@ -81,7 +87,7 @@ class HomeDetailFragment @Inject constructor(
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
sharedCallActionViewModel = activityViewModelProvider.get(SharedActiveCallViewModel::class.java)
|
||||
|
||||
setupCreateRoomButton()
|
||||
setupBottomNavigationView()
|
||||
setupToolbar()
|
||||
setupKeysBackupBanner()
|
||||
@@ -95,9 +101,6 @@ class HomeDetailFragment @Inject constructor(
|
||||
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
|
||||
onGroupChange(groupSummary.orNull())
|
||||
}
|
||||
viewModel.selectSubscribe(this, HomeDetailViewState::displayMode) { displayMode ->
|
||||
switchDisplayMode(displayMode)
|
||||
}
|
||||
|
||||
unknownDeviceDetectorSharedViewModel.subscribe { state ->
|
||||
state.unknownSessions.invoke()?.let { unknownDevices ->
|
||||
@@ -117,12 +120,71 @@ class HomeDetailFragment @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
sharedActionViewModel.observe()
|
||||
.subscribe {
|
||||
when (it) {
|
||||
is HomeActivitySharedAction.OnDisplayModeSelected -> renderDisplayMode(it.displayMode)
|
||||
}
|
||||
}
|
||||
.disposeOnDestroyView()
|
||||
|
||||
sharedCallActionViewModel
|
||||
.activeCall
|
||||
.observe(viewLifecycleOwner, Observer {
|
||||
activeCallViewHolder.updateCall(it, webRtcPeerConnectionManager)
|
||||
invalidateOptionsMenu()
|
||||
})
|
||||
|
||||
addFragment(R.id.roomListContainer, RoomListTabsFragment::class.java)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
createChatFabMenu.listener = null
|
||||
}
|
||||
|
||||
private fun renderDisplayMode(displayMode: RoomListDisplayMode) {
|
||||
when (displayMode) {
|
||||
RoomListDisplayMode.ALL,
|
||||
RoomListDisplayMode.NOTIFICATIONS,
|
||||
RoomListDisplayMode.FAVORITES,
|
||||
RoomListDisplayMode.LOW_PRIORITY,
|
||||
RoomListDisplayMode.INVITES -> {
|
||||
createChatFabMenu.getHideBottomViewOnScrollBehavior().slideUp(createChatFabMenu)
|
||||
createChatFabMenu.show()
|
||||
createChatRoomButton.isVisible = false
|
||||
createGroupRoomButton.isVisible = false
|
||||
}
|
||||
RoomListDisplayMode.PEOPLE -> {
|
||||
createChatFabMenu.isVisible = false
|
||||
createChatRoomButton.isVisible = true
|
||||
createChatRoomButton.getHideBottomViewOnScrollBehavior().slideUp(createChatRoomButton)
|
||||
createChatRoomButton.show()
|
||||
createGroupRoomButton.isVisible = false
|
||||
}
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
createChatFabMenu.isVisible = false
|
||||
createChatRoomButton.isVisible = false
|
||||
createGroupRoomButton.isVisible = true
|
||||
createGroupRoomButton.getHideBottomViewOnScrollBehavior().slideUp(createGroupRoomButton)
|
||||
createGroupRoomButton.show()
|
||||
}
|
||||
else -> {
|
||||
createChatFabMenu.isVisible = false
|
||||
createChatRoomButton.isVisible = false
|
||||
createGroupRoomButton.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCreateRoomButton() {
|
||||
createChatFabMenu.listener = this
|
||||
createChatRoomButton.debouncedClicks {
|
||||
createDirectChat()
|
||||
}
|
||||
createGroupRoomButton.debouncedClicks {
|
||||
openRoomDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@@ -205,6 +267,7 @@ class HomeDetailFragment @Inject constructor(
|
||||
groupSummary?.let {
|
||||
// Use GlideApp with activity context to avoid the glideRequests to be paused
|
||||
avatarRenderer.render(it.toMatrixItem(), groupToolbarAvatarImageView, GlideApp.with(requireActivity()))
|
||||
groupToolbarTitleView.text = it.displayName
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +405,19 @@ class HomeDetailFragment @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun openRoomDirectory(initialFilter: String) {
|
||||
navigator.openRoomDirectory(requireActivity(), initialFilter)
|
||||
}
|
||||
|
||||
override fun createDirectChat() {
|
||||
navigator.openCreateDirectRoom(requireActivity())
|
||||
}
|
||||
|
||||
override fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel {
|
||||
return serverBackupStatusViewModelFactory.create(initialState)
|
||||
}
|
||||
|
||||
private fun View.getHideBottomViewOnScrollBehavior(): HideBottomViewOnScrollBehavior<View> {
|
||||
return (layoutParams as CoordinatorLayout.LayoutParams).behavior as HideBottomViewOnScrollBehavior
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,11 @@ import androidx.annotation.StringRes
|
||||
import im.vector.app.R
|
||||
|
||||
enum class RoomListDisplayMode(@StringRes val titleRes: Int) {
|
||||
ALL(R.string.room_list_tabs_all),
|
||||
NOTIFICATIONS(R.string.bottom_action_notification),
|
||||
FAVORITES(R.string.room_recents_favourites),
|
||||
LOW_PRIORITY(R.string.room_recents_low_priority),
|
||||
INVITES(R.string.invitations_header),
|
||||
PEOPLE(R.string.bottom_action_people_x),
|
||||
ROOMS(R.string.bottom_action_rooms),
|
||||
FILTERED(/* Not used */ 0)
|
||||
|
@@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.room.notification.RoomNotificationStat
|
||||
|
||||
sealed class RoomListAction : VectorViewModelAction {
|
||||
data class SelectRoom(val roomSummary: RoomSummary) : RoomListAction()
|
||||
data class ToggleCategory(val category: RoomCategory) : RoomListAction()
|
||||
data class AcceptInvitation(val roomSummary: RoomSummary) : RoomListAction()
|
||||
data class RejectInvitation(val roomSummary: RoomSummary) : RoomListAction()
|
||||
data class FilterWith(val filter: String) : RoomListAction()
|
||||
|
@@ -17,9 +17,11 @@
|
||||
package im.vector.app.features.home.room.list
|
||||
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import io.reactivex.functions.Predicate
|
||||
import org.matrix.android.sdk.api.session.room.model.Invite
|
||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import io.reactivex.functions.Predicate
|
||||
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
|
||||
|
||||
class RoomListDisplayModeFilter(private val displayMode: RoomListDisplayMode) : Predicate<RoomSummary> {
|
||||
|
||||
@@ -30,9 +32,13 @@ class RoomListDisplayModeFilter(private val displayMode: RoomListDisplayMode) :
|
||||
return when (displayMode) {
|
||||
RoomListDisplayMode.NOTIFICATIONS ->
|
||||
roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE || roomSummary.userDrafts.isNotEmpty()
|
||||
RoomListDisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership.isActive()
|
||||
RoomListDisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership.isActive()
|
||||
RoomListDisplayMode.FILTERED -> roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.FILTERED -> roomSummary.membership == Membership.JOIN
|
||||
RoomListDisplayMode.ALL -> roomSummary.membership.isActive()
|
||||
RoomListDisplayMode.FAVORITES -> roomSummary.membership == Membership.JOIN && roomSummary.tags.any { it.name == RoomTag.ROOM_TAG_FAVOURITE }
|
||||
RoomListDisplayMode.LOW_PRIORITY -> roomSummary.membership == Membership.JOIN && roomSummary.tags.any { it.name == RoomTag.ROOM_TAG_LOW_PRIORITY }
|
||||
RoomListDisplayMode.INVITES -> roomSummary.membership == Membership.INVITE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@ import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.epoxy.OnModelBuildFinishedListener
|
||||
@@ -37,7 +36,6 @@ import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.LayoutManagerStateRestorer
|
||||
import im.vector.app.core.extensions.cleanup
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.OnBackPressed
|
||||
import im.vector.app.core.platform.StateView
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
@@ -45,14 +43,14 @@ import im.vector.app.features.home.room.list.actions.RoomListActionsArgs
|
||||
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.RoomListQuickActionsSharedActionViewModel
|
||||
import im.vector.app.features.home.room.list.widget.FabMenuView
|
||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import org.matrix.android.sdk.api.failure.Failure
|
||||
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.notification.RoomNotificationState
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@Parcelize
|
||||
@@ -66,7 +64,7 @@ class RoomListFragment @Inject constructor(
|
||||
private val notificationDrawerManager: NotificationDrawerManager,
|
||||
private val sharedViewPool: RecyclerView.RecycledViewPool
|
||||
|
||||
) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener {
|
||||
) : VectorBaseFragment(), RoomSummaryController.Listener {
|
||||
|
||||
private var modelBuildListener: OnModelBuildFinishedListener? = null
|
||||
private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel
|
||||
@@ -98,7 +96,6 @@ class RoomListFragment @Inject constructor(
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupCreateRoomButton()
|
||||
setupRecyclerView()
|
||||
sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java)
|
||||
roomListViewModel.observeViewEvents {
|
||||
@@ -109,9 +106,6 @@ class RoomListFragment @Inject constructor(
|
||||
is RoomListViewEvents.Done -> Unit
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
createChatFabMenu.listener = this
|
||||
|
||||
sharedActionViewModel
|
||||
.observe()
|
||||
.subscribe { handleQuickActions(it) }
|
||||
@@ -128,7 +122,6 @@ class RoomListFragment @Inject constructor(
|
||||
roomListView.cleanup()
|
||||
roomController.listener = null
|
||||
stateRestorer.clear()
|
||||
createChatFabMenu.listener = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@@ -136,45 +129,6 @@ class RoomListFragment @Inject constructor(
|
||||
navigator.openRoom(requireActivity(), event.roomSummary.roomId)
|
||||
}
|
||||
|
||||
private fun setupCreateRoomButton() {
|
||||
when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.isVisible = true
|
||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.isVisible = true
|
||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.isVisible = true
|
||||
else -> Unit // No button in this mode
|
||||
}
|
||||
|
||||
createChatRoomButton.debouncedClicks {
|
||||
createDirectChat()
|
||||
}
|
||||
createGroupRoomButton.debouncedClicks {
|
||||
openRoomDirectory()
|
||||
}
|
||||
|
||||
// Hide FAB when list is scrolling
|
||||
roomListView.addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||
createChatFabMenu.removeCallbacks(showFabRunnable)
|
||||
|
||||
when (newState) {
|
||||
RecyclerView.SCROLL_STATE_IDLE -> {
|
||||
createChatFabMenu.postDelayed(showFabRunnable, 250)
|
||||
}
|
||||
RecyclerView.SCROLL_STATE_DRAGGING,
|
||||
RecyclerView.SCROLL_STATE_SETTLING -> {
|
||||
when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.hide()
|
||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.hide()
|
||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.hide()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun filterRoomsWith(filter: String) {
|
||||
// Scroll the list to top
|
||||
roomListView.scrollToPosition(0)
|
||||
@@ -182,14 +136,6 @@ class RoomListFragment @Inject constructor(
|
||||
roomListViewModel.handle(RoomListAction.FilterWith(filter))
|
||||
}
|
||||
|
||||
override fun openRoomDirectory(initialFilter: String) {
|
||||
navigator.openRoomDirectory(requireActivity(), initialFilter)
|
||||
}
|
||||
|
||||
override fun createDirectChat() {
|
||||
navigator.openCreateDirectRoom(requireActivity())
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||
@@ -204,17 +150,6 @@ class RoomListFragment @Inject constructor(
|
||||
stateView.contentView = roomListView
|
||||
}
|
||||
|
||||
private val showFabRunnable = Runnable {
|
||||
if (isAdded) {
|
||||
when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.NOTIFICATIONS -> createChatFabMenu.show()
|
||||
RoomListDisplayMode.PEOPLE -> createChatRoomButton.show()
|
||||
RoomListDisplayMode.ROOMS -> createGroupRoomButton.show()
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) {
|
||||
when (quickAction) {
|
||||
is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> {
|
||||
@@ -258,6 +193,10 @@ class RoomListFragment @Inject constructor(
|
||||
roomController.update(state)
|
||||
// Mark all as read menu
|
||||
when (roomListParams.displayMode) {
|
||||
RoomListDisplayMode.ALL,
|
||||
RoomListDisplayMode.FAVORITES,
|
||||
RoomListDisplayMode.LOW_PRIORITY,
|
||||
RoomListDisplayMode.INVITES,
|
||||
RoomListDisplayMode.NOTIFICATIONS,
|
||||
RoomListDisplayMode.PEOPLE,
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
@@ -302,21 +241,22 @@ class RoomListFragment @Inject constructor(
|
||||
getString(R.string.room_list_catchup_empty_body))
|
||||
}
|
||||
}
|
||||
RoomListDisplayMode.PEOPLE ->
|
||||
RoomListDisplayMode.PEOPLE ->
|
||||
StateView.State.Empty(
|
||||
getString(R.string.room_list_people_empty_title),
|
||||
ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_bottom_chat),
|
||||
getString(R.string.room_list_people_empty_body)
|
||||
)
|
||||
RoomListDisplayMode.ROOMS ->
|
||||
RoomListDisplayMode.FILTERED -> {
|
||||
// Always display the content in this mode, because if the footer
|
||||
StateView.State.Content
|
||||
}
|
||||
else ->
|
||||
StateView.State.Empty(
|
||||
getString(R.string.room_list_rooms_empty_title),
|
||||
ContextCompat.getDrawable(requireContext(), R.drawable.ic_home_bottom_group),
|
||||
getString(R.string.room_list_rooms_empty_body)
|
||||
)
|
||||
else ->
|
||||
// Always display the content in this mode, because if the footer
|
||||
StateView.State.Content
|
||||
}
|
||||
stateView.state = emptyState
|
||||
}
|
||||
@@ -333,13 +273,6 @@ class RoomListFragment @Inject constructor(
|
||||
stateView.state = StateView.State.Error(message)
|
||||
}
|
||||
|
||||
override fun onBackPressed(toolbarButton: Boolean): Boolean {
|
||||
if (createChatFabMenu.onBackPressed()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RoomSummaryController.Callback **************************************************************
|
||||
|
||||
override fun onRoomClicked(room: RoomSummary) {
|
||||
@@ -364,11 +297,15 @@ class RoomListFragment @Inject constructor(
|
||||
roomListViewModel.handle(RoomListAction.RejectInvitation(room))
|
||||
}
|
||||
|
||||
override fun onToggleRoomCategory(roomCategory: RoomCategory) {
|
||||
roomListViewModel.handle(RoomListAction.ToggleCategory(roomCategory))
|
||||
}
|
||||
|
||||
override fun createRoom(initialName: String) {
|
||||
navigator.openCreateRoom(requireActivity(), initialName)
|
||||
}
|
||||
|
||||
override fun openRoomDirectory(initialFilter: String) {
|
||||
navigator.openRoomDirectory(requireActivity(), initialFilter)
|
||||
}
|
||||
|
||||
override fun createDirectChat() {
|
||||
navigator.openCreateDirectRoom(requireActivity())
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import com.airbnb.mvrx.ViewModelContext
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.utils.DataSource
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.matrix.android.sdk.api.MatrixCallback
|
||||
import org.matrix.android.sdk.api.NoOpMatrixCallback
|
||||
import org.matrix.android.sdk.api.extensions.orFalse
|
||||
@@ -29,7 +30,6 @@ import org.matrix.android.sdk.api.session.Session
|
||||
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.tag.RoomTag
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@@ -63,7 +63,6 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
||||
override fun handle(action: RoomListAction) {
|
||||
when (action) {
|
||||
is RoomListAction.SelectRoom -> handleSelectRoom(action)
|
||||
is RoomListAction.ToggleCategory -> handleToggleCategory(action)
|
||||
is RoomListAction.AcceptInvitation -> handleAcceptInvitation(action)
|
||||
is RoomListAction.RejectInvitation -> handleRejectInvitation(action)
|
||||
is RoomListAction.FilterWith -> handleFilter(action)
|
||||
@@ -80,10 +79,6 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
||||
_viewEvents.post(RoomListViewEvents.SelectRoom(action.roomSummary))
|
||||
}
|
||||
|
||||
private fun handleToggleCategory(action: RoomListAction.ToggleCategory) = setState {
|
||||
this.toggle(action.category)
|
||||
}
|
||||
|
||||
private fun handleFilter(action: RoomListAction.FilterWith) {
|
||||
setState {
|
||||
copy(
|
||||
@@ -212,34 +207,20 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
|
||||
}
|
||||
|
||||
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
||||
// Set up init size on directChats and groupRooms as they are the biggest ones
|
||||
val invites = ArrayList<RoomSummary>()
|
||||
val favourites = ArrayList<RoomSummary>()
|
||||
val directChats = ArrayList<RoomSummary>(rooms.size)
|
||||
val groupRooms = ArrayList<RoomSummary>(rooms.size)
|
||||
val lowPriorities = ArrayList<RoomSummary>()
|
||||
val serverNotices = ArrayList<RoomSummary>()
|
||||
|
||||
val others = ArrayList<RoomSummary>(rooms.size)
|
||||
rooms
|
||||
.filter { roomListDisplayModeFilter.test(it) }
|
||||
.forEach { room ->
|
||||
val tags = room.tags.map { it.name }
|
||||
when {
|
||||
room.membership == Membership.INVITE -> invites.add(room)
|
||||
tags.contains(RoomTag.ROOM_TAG_SERVER_NOTICE) -> serverNotices.add(room)
|
||||
tags.contains(RoomTag.ROOM_TAG_FAVOURITE) -> favourites.add(room)
|
||||
tags.contains(RoomTag.ROOM_TAG_LOW_PRIORITY) -> lowPriorities.add(room)
|
||||
room.isDirect -> directChats.add(room)
|
||||
else -> groupRooms.add(room)
|
||||
if (room.membership == Membership.INVITE) {
|
||||
invites.add(room)
|
||||
} else {
|
||||
others.add(room)
|
||||
}
|
||||
}
|
||||
return RoomSummaries().apply {
|
||||
put(RoomCategory.INVITE, invites)
|
||||
put(RoomCategory.FAVOURITE, favourites)
|
||||
put(RoomCategory.DIRECT, directChats)
|
||||
put(RoomCategory.GROUP, groupRooms)
|
||||
put(RoomCategory.LOW_PRIORITY, lowPriorities)
|
||||
put(RoomCategory.SERVER_NOTICE, serverNotices)
|
||||
put(RoomCategory.OTHER, others)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -31,39 +31,11 @@ data class RoomListViewState(
|
||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
val roomFilter: String = "",
|
||||
val asyncFilteredRooms: Async<RoomSummaries> = Uninitialized,
|
||||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val isInviteExpanded: Boolean = true,
|
||||
val isFavouriteRoomsExpanded: Boolean = true,
|
||||
val isDirectRoomsExpanded: Boolean = true,
|
||||
val isGroupRoomsExpanded: Boolean = true,
|
||||
val isLowPriorityRoomsExpanded: Boolean = true,
|
||||
val isServerNoticeRoomsExpanded: Boolean = true
|
||||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap()
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomListParams) : this(displayMode = args.displayMode)
|
||||
|
||||
fun isCategoryExpanded(roomCategory: RoomCategory): Boolean {
|
||||
return when (roomCategory) {
|
||||
RoomCategory.INVITE -> isInviteExpanded
|
||||
RoomCategory.FAVOURITE -> isFavouriteRoomsExpanded
|
||||
RoomCategory.DIRECT -> isDirectRoomsExpanded
|
||||
RoomCategory.GROUP -> isGroupRoomsExpanded
|
||||
RoomCategory.LOW_PRIORITY -> isLowPriorityRoomsExpanded
|
||||
RoomCategory.SERVER_NOTICE -> isServerNoticeRoomsExpanded
|
||||
}
|
||||
}
|
||||
|
||||
fun toggle(roomCategory: RoomCategory): RoomListViewState {
|
||||
return when (roomCategory) {
|
||||
RoomCategory.INVITE -> copy(isInviteExpanded = !isInviteExpanded)
|
||||
RoomCategory.FAVOURITE -> copy(isFavouriteRoomsExpanded = !isFavouriteRoomsExpanded)
|
||||
RoomCategory.DIRECT -> copy(isDirectRoomsExpanded = !isDirectRoomsExpanded)
|
||||
RoomCategory.GROUP -> copy(isGroupRoomsExpanded = !isGroupRoomsExpanded)
|
||||
RoomCategory.LOW_PRIORITY -> copy(isLowPriorityRoomsExpanded = !isLowPriorityRoomsExpanded)
|
||||
RoomCategory.SERVER_NOTICE -> copy(isServerNoticeRoomsExpanded = !isServerNoticeRoomsExpanded)
|
||||
}
|
||||
}
|
||||
|
||||
val hasUnread: Boolean
|
||||
get() = asyncFilteredRooms.invoke()
|
||||
?.flatMap { it.value }
|
||||
@@ -76,11 +48,7 @@ typealias RoomSummaries = LinkedHashMap<RoomCategory, List<RoomSummary>>
|
||||
|
||||
enum class RoomCategory(@StringRes val titleRes: Int) {
|
||||
INVITE(R.string.invitations_header),
|
||||
FAVOURITE(R.string.bottom_action_favourites),
|
||||
DIRECT(R.string.bottom_action_people_x),
|
||||
GROUP(R.string.bottom_action_rooms),
|
||||
LOW_PRIORITY(R.string.low_priority_header),
|
||||
SERVER_NOTICE(R.string.system_alerts_header)
|
||||
OTHER(R.string.bottom_action_favourites),
|
||||
}
|
||||
|
||||
fun RoomSummaries?.isNullOrEmpty(): Boolean {
|
||||
|
@@ -86,18 +86,12 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
||||
if (summaries.isEmpty()) {
|
||||
return@forEach
|
||||
} else {
|
||||
val isExpanded = viewState.isCategoryExpanded(category)
|
||||
buildRoomCategory(viewState, summaries, category.titleRes, viewState.isCategoryExpanded(category)) {
|
||||
listener?.onToggleRoomCategory(category)
|
||||
}
|
||||
if (isExpanded) {
|
||||
buildRoomModels(summaries,
|
||||
viewState.roomMembershipChanges,
|
||||
emptySet())
|
||||
// Never set showHelp to true for invitation
|
||||
if (category != RoomCategory.INVITE) {
|
||||
showHelp = userPreferencesProvider.shouldShowLongClickOnRoomHelp()
|
||||
}
|
||||
buildRoomModels(summaries,
|
||||
viewState.roomMembershipChanges,
|
||||
emptySet())
|
||||
// Never set showHelp to true for invitation
|
||||
if (category != RoomCategory.INVITE) {
|
||||
showHelp = userPreferencesProvider.shouldShowLongClickOnRoomHelp()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,7 +155,6 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
||||
}
|
||||
|
||||
interface Listener : FilteredRoomFooterItem.FilteredRoomFooterItemListener {
|
||||
fun onToggleRoomCategory(roomCategory: RoomCategory)
|
||||
fun onRoomClicked(room: RoomSummary)
|
||||
fun onRoomLongClicked(room: RoomSummary): Boolean
|
||||
fun onRejectRoomInvitation(room: RoomSummary)
|
||||
|
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.tabs
|
||||
|
||||
import im.vector.app.core.platform.VectorViewModelAction
|
||||
|
||||
sealed class RoomListTabsAction : VectorViewModelAction
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.tabs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.platform.VectorBaseFragment
|
||||
import im.vector.app.features.home.HomeActivitySharedAction
|
||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
||||
import kotlinx.android.synthetic.main.fragment_room_list_tabs.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
class RoomListTabsFragment @Inject constructor(
|
||||
private val viewModelFactory: RoomListTabsViewModel.Factory
|
||||
) : VectorBaseFragment(), RoomListTabsViewModel.Factory by viewModelFactory {
|
||||
|
||||
private val viewModel: RoomListTabsViewModel by fragmentViewModel()
|
||||
private lateinit var pagerAdapter: RoomListTabsPagerAdapter
|
||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
||||
|
||||
override fun getLayoutResId() = R.layout.fragment_room_list_tabs
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
pagerAdapter = RoomListTabsPagerAdapter(this, requireContext())
|
||||
viewPager.adapter = pagerAdapter
|
||||
TabLayoutMediator(tabLayout, viewPager) { tab, position ->
|
||||
val item = RoomListTabsPagerAdapter.TABS[position]
|
||||
tab.text = getString(item.titleRes).toLowerCase().capitalize()
|
||||
}.attach()
|
||||
|
||||
val onPageChangeListener: ViewPager2.OnPageChangeCallback = object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
val item = RoomListTabsPagerAdapter.TABS[position]
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.OnDisplayModeSelected(item))
|
||||
}
|
||||
}
|
||||
viewPager.registerOnPageChangeCallback(onPageChangeListener)
|
||||
}
|
||||
|
||||
override fun invalidate() = withState(viewModel) { state ->
|
||||
Timber.v("Invalidate state: $state")
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.tabs
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.airbnb.mvrx.MvRx
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.home.room.list.RoomListFragment
|
||||
import im.vector.app.features.home.room.list.RoomListParams
|
||||
|
||||
|
||||
class RoomListTabsPagerAdapter(private val fragment: Fragment,
|
||||
private val context: Context) : FragmentStateAdapter(fragment) {
|
||||
|
||||
companion object {
|
||||
val TABS = listOf(
|
||||
RoomListDisplayMode.ALL,
|
||||
RoomListDisplayMode.NOTIFICATIONS,
|
||||
RoomListDisplayMode.FAVORITES,
|
||||
RoomListDisplayMode.ROOMS,
|
||||
RoomListDisplayMode.PEOPLE,
|
||||
RoomListDisplayMode.INVITES,
|
||||
RoomListDisplayMode.LOW_PRIORITY
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount() = TABS.count()
|
||||
|
||||
override fun createFragment(position: Int): Fragment {
|
||||
val roomListFragment = fragment.childFragmentManager.fragmentFactory.instantiate(context.classLoader, RoomListFragment::class.java.name)
|
||||
val displayMode = TABS[position]
|
||||
val params = RoomListParams(displayMode)
|
||||
return roomListFragment.apply {
|
||||
arguments = Bundle().apply { putParcelable(MvRx.KEY_ARG, params) }
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.tabs
|
||||
|
||||
import com.airbnb.mvrx.ActivityViewModelContext
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import timber.log.Timber
|
||||
|
||||
class RoomListTabsViewModel @AssistedInject constructor(@Assisted initialState: RoomListTabsViewState)
|
||||
: VectorViewModel<RoomListTabsViewState, RoomListTabsAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedInject.Factory
|
||||
interface Factory {
|
||||
fun create(initialState: RoomListTabsViewState): RoomListTabsViewModel
|
||||
}
|
||||
|
||||
companion object : MvRxViewModelFactory<RoomListTabsViewModel, RoomListTabsViewState> {
|
||||
|
||||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: RoomListTabsViewState): RoomListTabsViewModel? {
|
||||
val factory = when (viewModelContext) {
|
||||
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||
}
|
||||
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||
}
|
||||
}
|
||||
|
||||
override fun handle(action: RoomListTabsAction) {
|
||||
Timber.v("Action $action not handled")
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2020 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.tabs
|
||||
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
|
||||
data class RoomListTabsViewState(val noop: Boolean = false) : MvRxState
|
@@ -1,118 +1,186 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/coordinatorLayout"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/groupToolbar"
|
||||
style="@style/VectorToolbarStyle"
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
app:elevation="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:elevation="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/groupToolbar"
|
||||
style="@style/VectorToolbarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:elevation="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_scrollFlags="scroll|enterAlways">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupToolbarAvatarImageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:contentDescription="@string/a11y_open_drawer"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupToolbarTitleView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
<ImageView
|
||||
android:id="@+id/groupToolbarAvatarImageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:contentDescription="@string/a11y_open_drawer"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/groupToolbarTitleView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textStyle="bold"
|
||||
app:autoSizeMaxTextSize="16sp"
|
||||
app:autoSizeMinTextSize="10sp"
|
||||
app:autoSizeStepGranularity="1sp"
|
||||
app:autoSizeTextType="uniform"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
</LinearLayout>
|
||||
|
||||
<im.vector.app.features.sync.widget.SyncStateView
|
||||
android:id="@+id/syncStateView"
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/groupToolbar" />
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<im.vector.app.core.ui.views.KeysBackupBanner
|
||||
android:id="@+id/homeKeysBackupBanner"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_keys_backup_banner_accent_color"
|
||||
android:minHeight="67dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView" />
|
||||
<im.vector.app.features.sync.widget.SyncStateView
|
||||
android:id="@+id/syncStateView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<im.vector.app.core.ui.views.ActiveCallView
|
||||
android:id="@+id/activeCallView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/roomListContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="?riotx_header_panel_background"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/activeCallView" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/activeCallPiPWrap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView">
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/activeCallPiP"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
<im.vector.app.core.ui.views.KeysBackupBanner
|
||||
android:id="@+id/homeKeysBackupBanner"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_keys_backup_banner_accent_color"
|
||||
android:minHeight="67dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/syncStateView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
<im.vector.app.core.ui.views.ActiveCallView
|
||||
android:id="@+id/activeCallView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/homeKeysBackupBanner"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottomNavigationView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?riotx_background"
|
||||
app:itemIconSize="20dp"
|
||||
app:itemIconTint="@color/bottom_navigation_icon_tint_selector"
|
||||
app:labelVisibilityMode="unlabeled"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:menu="@menu/home_bottom_navigation" />
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/roomListContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="?riotx_header_panel_background"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/activeCallView" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/activeCallPiPWrap"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/activeCallView">
|
||||
|
||||
<org.webrtc.SurfaceViewRenderer
|
||||
android:id="@+id/activeCallPiP"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottomNavigationView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?riotx_background"
|
||||
android:visibility="gone"
|
||||
app:itemIconSize="20dp"
|
||||
app:itemIconTint="@color/bottom_navigation_icon_tint_selector"
|
||||
app:labelVisibilityMode="unlabeled"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:menu="@menu/home_bottom_navigation" />
|
||||
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<im.vector.app.features.home.room.list.widget.FabMenuView
|
||||
android:id="@+id/createChatFabMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
app:layoutDescription="@xml/motion_scene_fab_menu"
|
||||
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
|
||||
tools:showPaths="true"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/createChatRoomButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
|
||||
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"
|
||||
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
|
||||
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.coordinatorlayout.widget.CoordinatorLayout>
|
@@ -13,44 +13,4 @@
|
||||
android:layout_height="match_parent"
|
||||
android:overScrollMode="always" />
|
||||
|
||||
<im.vector.app.features.home.room.list.widget.FabMenuView
|
||||
android:id="@+id/createChatFabMenu"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone"
|
||||
app:layoutDescription="@xml/motion_scene_fab_menu"
|
||||
tools:showPaths="true"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/createChatRoomButton"
|
||||
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_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" />
|
||||
|
||||
</im.vector.app.core.platform.StateView>
|
||||
|
22
vector/src/main/res/layout/fragment_room_list_tabs.xml
Normal file
22
vector/src/main/res/layout/fragment_room_list_tabs.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
app:tabMode="scrollable"
|
||||
app:tabBackground="?attr/riotx_background"
|
||||
style="@style/Vector.Widget.TabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
@@ -198,7 +198,7 @@
|
||||
android:background="?riotx_header_panel_border_mobile"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintStart_toStartOf="@+id/roomNameView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomBottomBarrier" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
@@ -150,6 +150,8 @@
|
||||
<string name="bottom_action_rooms">Rooms</string>
|
||||
<string name="bottom_action_groups">Communities</string>
|
||||
|
||||
<string name="room_list_tabs_all">All</string>
|
||||
|
||||
<!-- Home screen -->
|
||||
<string name="home_filter_placeholder_home">Filter room names</string>
|
||||
<string name="home_filter_placeholder_favorites">Filter favourites</string>
|
||||
|
8
vector/src/main/res/values/style_tab_layout.xml
Normal file
8
vector/src/main/res/values/style_tab_layout.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Vector.Widget.TabLayout" parent="Widget.Design.TabLayout">
|
||||
<item name="tabTextAppearance">@style/TextAppearance.Vector.Tabs</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
@@ -3,4 +3,5 @@
|
||||
|
||||
<style name="Vector.PopupMenu" parent="Vector.PopupMenuBase" />
|
||||
|
||||
|
||||
</resources>
|
@@ -60,4 +60,9 @@
|
||||
<item name="android:textColor">?riotx_android_secondary</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Vector.Tabs" parent="TextAppearance.Design.Tab">
|
||||
<item name="textAllCaps">false</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
Reference in New Issue
Block a user