1
0
mirror of https://github.com/vector-im/riotX-android synced 2025-10-06 00:02:48 +02:00

Compare commits

...

5 Commits

Author SHA1 Message Date
ganfra
ad9f67b3bd Change tab background color 2020-09-09 23:42:15 +02:00
ganfra
3ae0586dac Change app id 2020-09-09 23:42:00 +02:00
ganfra
19b411776a Home: handle fabs 2020-09-09 20:22:40 +02:00
ganfra
ddbc2b0ade Room list : continue to experiment 2020-09-09 15:28:16 +02:00
ganfra
5f79530c4c Room list tab: start creating all classes and init ui 2020-09-08 20:02:41 +02:00
27 changed files with 560 additions and 309 deletions

View File

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

View File

@@ -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": [

View File

@@ -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": [

View File

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

View File

@@ -123,7 +123,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable, UnknownDeviceDet
drawerLayout.closeDrawer(GravityCompat.START)
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
}
}.exhaustive
}
}
.disposeOnDestroy()

View File

@@ -25,4 +25,5 @@ sealed class HomeActivitySharedAction : VectorSharedAction {
object OpenDrawer : HomeActivitySharedAction()
object CloseDrawer : HomeActivitySharedAction()
object OpenGroup : HomeActivitySharedAction()
data class OnDisplayModeSelected(val displayMode: RoomListDisplayMode): HomeActivitySharedAction()
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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>

View File

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

View File

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

View 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>

View File

@@ -3,4 +3,5 @@
<style name="Vector.PopupMenu" parent="Vector.PopupMenuBase" />
</resources>

View File

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