new app layouts invites (#6911)
This commit is contained in:
parent
225d05e0be
commit
70cfe00271
1
changelog.d/6889.wip
Normal file
1
changelog.d/6889.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[App Layout] new room invites screen
|
@ -349,6 +349,7 @@
|
|||||||
<activity android:name=".features.location.live.map.LiveLocationMapViewActivity" />
|
<activity android:name=".features.location.live.map.LiveLocationMapViewActivity" />
|
||||||
<activity android:name=".features.settings.font.FontScaleSettingActivity"/>
|
<activity android:name=".features.settings.font.FontScaleSettingActivity"/>
|
||||||
<activity android:name=".features.call.dialpad.PstnDialActivity" />
|
<activity android:name=".features.call.dialpad.PstnDialActivity" />
|
||||||
|
<activity android:name=".features.home.room.list.home.invites.InvitesActivity"/>
|
||||||
|
|
||||||
<!-- Services -->
|
<!-- Services -->
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsV
|
|||||||
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomViewModel
|
import im.vector.app.features.home.room.detail.upgrade.MigrateRoomViewModel
|
||||||
import im.vector.app.features.home.room.list.RoomListViewModel
|
import im.vector.app.features.home.room.list.RoomListViewModel
|
||||||
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
|
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
|
||||||
|
import im.vector.app.features.home.room.list.home.invites.InvitesViewModel
|
||||||
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
|
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
|
||||||
import im.vector.app.features.invite.InviteUsersToRoomViewModel
|
import im.vector.app.features.invite.InviteUsersToRoomViewModel
|
||||||
import im.vector.app.features.location.LocationSharingViewModel
|
import im.vector.app.features.location.LocationSharingViewModel
|
||||||
@ -618,4 +619,9 @@ interface MavericksViewModelModule {
|
|||||||
@IntoMap
|
@IntoMap
|
||||||
@MavericksViewModelKey(HomeRoomListViewModel::class)
|
@MavericksViewModelKey(HomeRoomListViewModel::class)
|
||||||
fun homeRoomListViewModel(factory: HomeRoomListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
fun homeRoomListViewModel(factory: HomeRoomListViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@MavericksViewModelKey(InvitesViewModel::class)
|
||||||
|
fun invitesViewModel(factory: InvitesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home.room.list.home
|
package im.vector.app.features.home.room.list.home
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -48,6 +49,8 @@ import im.vector.app.features.home.room.list.actions.RoomListSharedAction
|
|||||||
import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
|
import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel
|
||||||
import im.vector.app.features.home.room.list.home.filter.HomeFilteredRoomsController
|
import im.vector.app.features.home.room.list.home.filter.HomeFilteredRoomsController
|
||||||
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
|
import im.vector.app.features.home.room.list.home.filter.HomeRoomFilter
|
||||||
|
import im.vector.app.features.home.room.list.home.invites.InvitesActivity
|
||||||
|
import im.vector.app.features.home.room.list.home.invites.InvitesCounterController
|
||||||
import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController
|
import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController
|
||||||
import im.vector.app.features.spaces.SpaceListBottomSheet
|
import im.vector.app.features.spaces.SpaceListBottomSheet
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@ -66,6 +69,7 @@ class HomeRoomListFragment :
|
|||||||
@Inject lateinit var roomSummaryItemFactory: RoomSummaryItemFactory
|
@Inject lateinit var roomSummaryItemFactory: RoomSummaryItemFactory
|
||||||
@Inject lateinit var userPreferencesProvider: UserPreferencesProvider
|
@Inject lateinit var userPreferencesProvider: UserPreferencesProvider
|
||||||
@Inject lateinit var recentRoomCarouselController: RecentRoomCarouselController
|
@Inject lateinit var recentRoomCarouselController: RecentRoomCarouselController
|
||||||
|
@Inject lateinit var invitesCounterController: InvitesCounterController
|
||||||
|
|
||||||
private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel()
|
private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel()
|
||||||
private lateinit var sharedQuickActionsViewModel: RoomListQuickActionsSharedActionViewModel
|
private lateinit var sharedQuickActionsViewModel: RoomListQuickActionsSharedActionViewModel
|
||||||
@ -266,9 +270,19 @@ class HomeRoomListFragment :
|
|||||||
controller.submitList(list)
|
controller.submitList(list)
|
||||||
}
|
}
|
||||||
}.adapter
|
}.adapter
|
||||||
|
is HomeRoomSection.InvitesCountData -> invitesCounterController.also { controller ->
|
||||||
|
controller.clickListener = ::onInvitesCounterClicked
|
||||||
|
section.count.observe(viewLifecycleOwner) { count ->
|
||||||
|
controller.submitData(count)
|
||||||
|
}
|
||||||
|
}.adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onInvitesCounterClicked() {
|
||||||
|
startActivity(Intent(activity, InvitesActivity::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
private fun onRoomFilterChanged(filter: HomeRoomFilter) {
|
private fun onRoomFilterChanged(filter: HomeRoomFilter) {
|
||||||
roomListViewModel.handle(HomeRoomListAction.ChangeRoomFilter(filter))
|
roomListViewModel.handle(HomeRoomListAction.ChangeRoomFilter(filter))
|
||||||
}
|
}
|
||||||
@ -285,6 +299,7 @@ class HomeRoomListFragment :
|
|||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
views.roomListView.cleanup()
|
views.roomListView.cleanup()
|
||||||
recentRoomCarouselController.listener = null
|
recentRoomCarouselController.listener = null
|
||||||
|
invitesCounterController.clickListener = null
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home.room.list.home
|
package im.vector.app.features.home.room.list.home
|
||||||
|
|
||||||
|
import androidx.lifecycle.map
|
||||||
import androidx.paging.PagedList
|
import androidx.paging.PagedList
|
||||||
import arrow.core.toOption
|
import arrow.core.toOption
|
||||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
@ -100,9 +101,9 @@ class HomeRoomListViewModel @AssistedInject constructor(
|
|||||||
|
|
||||||
private fun configureSections() = viewModelScope.launch {
|
private fun configureSections() = viewModelScope.launch {
|
||||||
val newSections = mutableSetOf<HomeRoomSection>()
|
val newSections = mutableSetOf<HomeRoomSection>()
|
||||||
|
newSections.add(getInvitesCountSection())
|
||||||
|
|
||||||
val areSettingsEnabled = preferencesStore.areRecentsEnabledFlow.first()
|
val areSettingsEnabled = preferencesStore.areRecentsEnabledFlow.first()
|
||||||
|
|
||||||
if (areSettingsEnabled) {
|
if (areSettingsEnabled) {
|
||||||
newSections.add(getRecentRoomsSection())
|
newSections.add(getRecentRoomsSection())
|
||||||
}
|
}
|
||||||
@ -127,6 +128,19 @@ class HomeRoomListViewModel @AssistedInject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getInvitesCountSection(): HomeRoomSection.InvitesCountData {
|
||||||
|
val builder = RoomSummaryQueryParams.Builder().also {
|
||||||
|
it.memberships = listOf(Membership.INVITE)
|
||||||
|
}
|
||||||
|
|
||||||
|
val liveCount = session.roomService().getRoomSummariesLive(
|
||||||
|
builder.build(),
|
||||||
|
RoomSortOrder.ACTIVITY
|
||||||
|
).map { it.count() }
|
||||||
|
|
||||||
|
return HomeRoomSection.InvitesCountData(liveCount)
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun getFilteredRoomsSection(): HomeRoomSection.RoomSummaryData {
|
private suspend fun getFilteredRoomsSection(): HomeRoomSection.RoomSummaryData {
|
||||||
val builder = RoomSummaryQueryParams.Builder().also {
|
val builder = RoomSummaryQueryParams.Builder().also {
|
||||||
it.memberships = listOf(Membership.JOIN)
|
it.memberships = listOf(Membership.JOIN)
|
||||||
|
@ -32,4 +32,8 @@ sealed class HomeRoomSection {
|
|||||||
data class RecentRoomsData(
|
data class RecentRoomsData(
|
||||||
val list: LiveData<List<RoomSummary>>
|
val list: LiveData<List<RoomSummary>>
|
||||||
) : HomeRoomSection()
|
) : HomeRoomSection()
|
||||||
|
|
||||||
|
data class InvitesCountData(
|
||||||
|
val count: LiveData<Int>
|
||||||
|
) : HomeRoomSection()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class InviteCounterItem : VectorEpoxyModel<InviteCounterItem.Holder>(R.layout.item_invites_count) {
|
||||||
|
|
||||||
|
@EpoxyAttribute var invitesCount: Int = 0
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.view.setOnClickListener(listener)
|
||||||
|
holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(invitesCount, true))
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.invites_count_badge)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
sealed class InvitesAction : VectorViewModelAction {
|
||||||
|
data class AcceptInvitation(val roomSummary: RoomSummary) : InvitesAction()
|
||||||
|
data class RejectInvitation(val roomSummary: RoomSummary) : InvitesAction()
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.core.extensions.addFragment
|
||||||
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class InvitesActivity : VectorBaseActivity<ActivitySimpleBinding>() {
|
||||||
|
|
||||||
|
override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
override fun initUiAndData() {
|
||||||
|
if (isFirstCreation()) {
|
||||||
|
addFragment(views.simpleFragmentContainer, InvitesFragment::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
|
import com.airbnb.epoxy.paging.PagedListEpoxyController
|
||||||
|
import im.vector.app.core.utils.createUIHandler
|
||||||
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
|
import im.vector.app.features.home.room.list.RoomListListener
|
||||||
|
import im.vector.app.features.home.room.list.RoomSummaryItemFactory
|
||||||
|
import im.vector.app.features.home.room.list.RoomSummaryItemPlaceHolder_
|
||||||
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class InvitesController @Inject constructor(
|
||||||
|
private val roomSummaryItemFactory: RoomSummaryItemFactory,
|
||||||
|
) : PagedListEpoxyController<RoomSummary>(
|
||||||
|
// Important it must match the PageList builder notify Looper
|
||||||
|
modelBuildingHandler = createUIHandler()
|
||||||
|
) {
|
||||||
|
|
||||||
|
var roomChangeMembershipStates: Map<String, ChangeMembershipState>? = null
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
requestForcedModelBuild()
|
||||||
|
}
|
||||||
|
|
||||||
|
var listener: RoomListListener? = null
|
||||||
|
|
||||||
|
override fun buildItemModel(currentPosition: Int, item: RoomSummary?): EpoxyModel<*> {
|
||||||
|
item ?: return RoomSummaryItemPlaceHolder_().apply { id(currentPosition) }
|
||||||
|
return roomSummaryItemFactory.create(item, roomChangeMembershipStates.orEmpty(), emptySet(), RoomListDisplayMode.ROOMS, listener)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyController
|
||||||
|
import im.vector.app.core.resources.StringProvider
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class InvitesCounterController @Inject constructor(
|
||||||
|
val stringProvider: StringProvider
|
||||||
|
) : EpoxyController() {
|
||||||
|
|
||||||
|
private var count = 0
|
||||||
|
var clickListener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
override fun buildModels() {
|
||||||
|
val host = this
|
||||||
|
if (count != 0) {
|
||||||
|
inviteCounterItem {
|
||||||
|
id("invites_counter")
|
||||||
|
invitesCount(host.count)
|
||||||
|
listener { host.clickListener?.invoke() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun submitData(count: Int?) {
|
||||||
|
this.count = count ?: 0
|
||||||
|
requestModelBuild()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.core.extensions.configureWith
|
||||||
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
|
import im.vector.app.databinding.FragmentInvitesBinding
|
||||||
|
import im.vector.app.features.analytics.plan.ViewRoom
|
||||||
|
import im.vector.app.features.home.room.list.RoomListListener
|
||||||
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class InvitesFragment : VectorBaseFragment<FragmentInvitesBinding>(), RoomListListener {
|
||||||
|
|
||||||
|
@Inject lateinit var controller: InvitesController
|
||||||
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
|
|
||||||
|
private val viewModel by fragmentViewModel(InvitesViewModel::class)
|
||||||
|
|
||||||
|
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentInvitesBinding {
|
||||||
|
return FragmentInvitesBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
setupToolbar(views.invitesToolbar)
|
||||||
|
.allowBack()
|
||||||
|
|
||||||
|
views.invitesRecycler.configureWith(controller)
|
||||||
|
controller.listener = this
|
||||||
|
|
||||||
|
viewModel.onEach(InvitesViewState::roomMembershipChanges) {
|
||||||
|
controller.roomChangeMembershipStates = it
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.observeViewEvents {
|
||||||
|
when (it) {
|
||||||
|
is InvitesViewEvents.Failure -> showFailure(it.throwable)
|
||||||
|
is InvitesViewEvents.OpenRoom -> handleOpenRoom(it.roomSummary, it.shouldCloseInviteView)
|
||||||
|
InvitesViewEvents.Close -> handleClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleClose() {
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleOpenRoom(roomSummary: RoomSummary, shouldCloseInviteView: Boolean) {
|
||||||
|
navigator.openRoom(
|
||||||
|
context = requireActivity(),
|
||||||
|
roomId = roomSummary.roomId,
|
||||||
|
isInviteAlreadyAccepted = true,
|
||||||
|
trigger = ViewRoom.Trigger.RoomList // #6508
|
||||||
|
)
|
||||||
|
if (shouldCloseInviteView) {
|
||||||
|
requireActivity().finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate(): Unit = withState(viewModel) { state ->
|
||||||
|
super.invalidate()
|
||||||
|
|
||||||
|
state.pagedList?.observe(viewLifecycleOwner) { list ->
|
||||||
|
controller.submitList(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRejectRoomInvitation(room: RoomSummary) {
|
||||||
|
notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
|
||||||
|
viewModel.handle(InvitesAction.RejectInvitation(room))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAcceptRoomInvitation(room: RoomSummary) {
|
||||||
|
notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
|
||||||
|
viewModel.handle(InvitesAction.AcceptInvitation(room))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onJoinSuggestedRoom(room: SpaceChildInfo) = Unit
|
||||||
|
|
||||||
|
override fun onSuggestedRoomClicked(room: SpaceChildInfo) = Unit
|
||||||
|
|
||||||
|
override fun onRoomClicked(room: RoomSummary) = Unit
|
||||||
|
|
||||||
|
override fun onRoomLongClicked(room: RoomSummary): Boolean = false
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import im.vector.app.core.platform.VectorViewEvents
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
sealed class InvitesViewEvents : VectorViewEvents {
|
||||||
|
data class Failure(val throwable: Throwable) : InvitesViewEvents()
|
||||||
|
data class OpenRoom(val roomSummary: RoomSummary, val shouldCloseInviteView: Boolean) : InvitesViewEvents()
|
||||||
|
object Close : InvitesViewEvents()
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import androidx.paging.PagedList
|
||||||
|
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedFactory
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import im.vector.app.core.di.MavericksAssistedViewModelFactory
|
||||||
|
import im.vector.app.core.di.hiltMavericksViewModelFactory
|
||||||
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
|
import org.matrix.android.sdk.api.session.room.RoomSummaryQueryParams
|
||||||
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
class InvitesViewModel @AssistedInject constructor(
|
||||||
|
@Assisted val initialState: InvitesViewState,
|
||||||
|
private val session: Session,
|
||||||
|
) : VectorViewModel<InvitesViewState, InvitesAction, InvitesViewEvents>(initialState) {
|
||||||
|
|
||||||
|
private val pagedListConfig = PagedList.Config.Builder()
|
||||||
|
.setPageSize(10)
|
||||||
|
.setInitialLoadSizeHint(20)
|
||||||
|
.setEnablePlaceholders(true)
|
||||||
|
.setPrefetchDistance(10)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
@AssistedFactory
|
||||||
|
interface Factory : MavericksAssistedViewModelFactory<InvitesViewModel, InvitesViewState> {
|
||||||
|
override fun create(initialState: InvitesViewState): InvitesViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MavericksViewModelFactory<InvitesViewModel, InvitesViewState> by hiltMavericksViewModelFactory()
|
||||||
|
|
||||||
|
init {
|
||||||
|
observeInvites()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: InvitesAction) {
|
||||||
|
when (action) {
|
||||||
|
is InvitesAction.AcceptInvitation -> handleAcceptInvitation(action)
|
||||||
|
is InvitesAction.RejectInvitation -> handleRejectInvitation(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleRejectInvitation(action: InvitesAction.RejectInvitation) = withState { state ->
|
||||||
|
val roomId = action.roomSummary.roomId
|
||||||
|
val roomMembershipChange = state.roomMembershipChanges[roomId]
|
||||||
|
if (roomMembershipChange?.isInProgress().orFalse()) {
|
||||||
|
// Request already sent, should not happen
|
||||||
|
Timber.w("Try to left an already leaving or joining room. Should not happen")
|
||||||
|
return@withState
|
||||||
|
}
|
||||||
|
|
||||||
|
val shouldCloseInviteView = state.pagedList?.value?.size == 1
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
session.roomService().leaveRoom(roomId)
|
||||||
|
// We do not update the rejectingRoomsIds here, because, the room is not rejected yet regarding the sync data.
|
||||||
|
// Instead, we wait for the room to be rejected
|
||||||
|
// Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons.
|
||||||
|
// If we update the state, the button will be displayed again, so it's not ideal...
|
||||||
|
if (shouldCloseInviteView) {
|
||||||
|
_viewEvents.post(InvitesViewEvents.Close)
|
||||||
|
}
|
||||||
|
} catch (failure: Throwable) {
|
||||||
|
// Notify the user
|
||||||
|
_viewEvents.post(InvitesViewEvents.Failure(failure))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleAcceptInvitation(action: InvitesAction.AcceptInvitation) = withState { state ->
|
||||||
|
val roomId = action.roomSummary.roomId
|
||||||
|
val roomMembershipChange = state.roomMembershipChanges[roomId]
|
||||||
|
if (roomMembershipChange?.isInProgress().orFalse()) {
|
||||||
|
// Request already sent, should not happen
|
||||||
|
Timber.w("Try to join an already joining room. Should not happen")
|
||||||
|
return@withState
|
||||||
|
}
|
||||||
|
// close invites view when navigate to a room from the last one invite
|
||||||
|
|
||||||
|
val shouldCloseInviteView = state.pagedList?.value?.size == 1
|
||||||
|
|
||||||
|
_viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView))
|
||||||
|
|
||||||
|
// quick echo
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
roomMembershipChanges = roomMembershipChanges.mapValues {
|
||||||
|
if (it.key == roomId) {
|
||||||
|
ChangeMembershipState.Joining
|
||||||
|
} else {
|
||||||
|
it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeInvites() {
|
||||||
|
val builder = RoomSummaryQueryParams.Builder().also {
|
||||||
|
it.memberships = listOf(Membership.INVITE)
|
||||||
|
}
|
||||||
|
val pagedList = session.roomService().getPagedRoomSummariesLive(
|
||||||
|
queryParams = builder.build(),
|
||||||
|
pagedListConfig = pagedListConfig,
|
||||||
|
sortOrder = RoomSortOrder.ACTIVITY
|
||||||
|
)
|
||||||
|
|
||||||
|
setState {
|
||||||
|
copy(pagedList = pagedList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.home.room.list.home.invites
|
||||||
|
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.paging.PagedList
|
||||||
|
import com.airbnb.mvrx.MavericksState
|
||||||
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
|
data class InvitesViewState(
|
||||||
|
val pagedList: LiveData<PagedList<RoomSummary>>? = null,
|
||||||
|
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||||
|
) : MavericksState
|
36
vector/src/main/res/layout/fragment_invites.xml
Normal file
36
vector/src/main/res/layout/fragment_invites.xml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/appBarLayout"
|
||||||
|
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">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
|
android:id="@+id/invites_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?actionBarSize"
|
||||||
|
app:title="@string/invites_title" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/invites_recycler"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:fastScrollEnabled="true"
|
||||||
|
android:overScrollMode="always"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/appBarLayout" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
48
vector/src/main/res/layout/item_invites_count.xml
Normal file
48
vector/src/main/res/layout/item_invites_count.xml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?vctr_toolbar_background"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
|
||||||
|
tools:viewBindingIgnore="true">
|
||||||
|
|
||||||
|
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
android:id="@+id/invites_count_badge"
|
||||||
|
style="@style/Widget.Vector.TextView.Micro"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:minWidth="16dp"
|
||||||
|
android:minHeight="16dp"
|
||||||
|
android:paddingStart="4dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
|
android:textColor="?colorOnError"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:background="@drawable/bg_unread_highlight"
|
||||||
|
tools:text="4"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/invites_count_title"
|
||||||
|
style="@style/Widget.Vector.TextView.Body"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical|end"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@string/invites_title"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="?colorSecondary"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/invites_count_badge"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -441,6 +441,9 @@
|
|||||||
<string name="system_alerts_header">"System Alerts"</string>
|
<string name="system_alerts_header">"System Alerts"</string>
|
||||||
<string name="suggested_header">Suggested Rooms</string>
|
<string name="suggested_header">Suggested Rooms</string>
|
||||||
|
|
||||||
|
<!-- Invites fragment -->
|
||||||
|
<string name="invites_title">Invites</string>
|
||||||
|
|
||||||
<!-- People fragment -->
|
<!-- People fragment -->
|
||||||
<string name="direct_chats_header">Conversations</string>
|
<string name="direct_chats_header">Conversations</string>
|
||||||
<string name="matrix_only_filter">Matrix contacts only</string>
|
<string name="matrix_only_filter">Matrix contacts only</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user