Fix / Add unread count in hamburger menu

This commit is contained in:
Valere 2021-04-21 15:33:32 +02:00
parent d42761f98a
commit 733d4185c4
5 changed files with 194 additions and 19 deletions

View file

@ -85,6 +85,7 @@ class HomeActivity :
ToolbarConfigurable,
UnknownDeviceDetectorSharedViewModel.Factory,
ServerBackupStatusViewModel.Factory,
UnreadMessagesSharedViewModel.Factory,
NavigationInterceptor {
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
@ -103,6 +104,7 @@ class HomeActivity :
@Inject lateinit var popupAlertManager: PopupAlertManager
@Inject lateinit var shortcutsHandler: ShortcutsHandler
@Inject lateinit var unknownDeviceViewModelFactory: UnknownDeviceDetectorSharedViewModel.Factory
@Inject lateinit var unreadMessagesSharedViewModelFactory: UnreadMessagesSharedViewModel.Factory
@Inject lateinit var permalinkHandler: PermalinkHandler
@Inject lateinit var avatarRenderer: AvatarRenderer
@Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter
@ -140,6 +142,10 @@ class HomeActivity :
return serverBackupviewModelFactory.create(initialState)
}
override fun create(initialState: UnreadMessagesState): UnreadMessagesSharedViewModel {
return unreadMessagesSharedViewModelFactory.create(initialState)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice())

View file

@ -43,6 +43,7 @@ import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.webrtc.WebRtcCallManager
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.UnreadCounterBadgeView
import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.popup.VerificationVectorAlert
import im.vector.app.features.settings.VectorPreferences
@ -71,6 +72,7 @@ class HomeDetailFragment @Inject constructor(
private val viewModel: HomeDetailViewModel by fragmentViewModel()
private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel()
private val unreadMessagesSharedViewModel: UnreadMessagesSharedViewModel by activityViewModel()
private val serverBackupStatusViewModel: ServerBackupStatusViewModel by activityViewModel()
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
@ -157,6 +159,19 @@ class HomeDetailFragment @Inject constructor(
}
}
unreadMessagesSharedViewModel.subscribe { state ->
if (vectorPreferences.labSpaces()) {
views.drawerUnreadCounterBadgeView.render(
UnreadCounterBadgeView.State(
count = state.otherSpacesUnread.totalCount,
highlighted = state.otherSpacesUnread.isHighlight
)
)
} else {
views.drawerUnreadCounterBadgeView.isVisible = false
}
}
sharedCallActionViewModel
.liveKnownCalls
.observe(viewLifecycleOwner, {

View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.home
import com.airbnb.mvrx.ActivityViewModelContext
import com.airbnb.mvrx.FragmentViewModelContext
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.AppStateHandler
import im.vector.app.core.platform.EmptyAction
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.settings.VectorPreferences
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.schedulers.Schedulers
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
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.model.Membership
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
import org.matrix.android.sdk.rx.asObservable
import java.util.concurrent.TimeUnit
data class UnreadMessagesState(
val homeSpaceUnread: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0),
val otherSpacesUnread: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
) : MvRxState
data class CountInfo(
val homeCount: RoomAggregateNotificationCount,
val otherCount: RoomAggregateNotificationCount
)
class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initialState: UnreadMessagesState,
session: Session,
appStateHandler: AppStateHandler,
private val vectorPreferences: VectorPreferences)
: VectorViewModel<UnreadMessagesState, EmptyAction, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory {
fun create(initialState: UnreadMessagesState): UnreadMessagesSharedViewModel
}
companion object : MvRxViewModelFactory<UnreadMessagesSharedViewModel, UnreadMessagesState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: UnreadMessagesState): UnreadMessagesSharedViewModel? {
val factory = when (viewModelContext) {
is FragmentViewModelContext -> viewModelContext.fragment as? UnreadMessagesSharedViewModel.Factory
is ActivityViewModelContext -> viewModelContext.activity as? UnreadMessagesSharedViewModel.Factory
}
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
}
}
override fun handle(action: EmptyAction) {}
init {
session.getPagedRoomSummariesLive(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.activeSpaceId = ActiveSpaceFilter.ActiveSpace(null)
}, sortOrder = RoomSortOrder.NONE
).asObservable()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.subscribe {
val counts = session.getNotificationCountForRooms(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.activeSpaceId = ActiveSpaceFilter.ActiveSpace(null)
}
)
val invites = session.getRoomSummaries(roomSummaryQueryParams {
this.memberships = listOf(Membership.INVITE)
this.activeSpaceId = ActiveSpaceFilter.ActiveSpace(null)
}).size
setState {
copy(
homeSpaceUnread = RoomAggregateNotificationCount(
counts.notificationCount + invites,
highlightCount = counts.highlightCount + invites
)
)
}
}.disposeOnClear()
Observable.combineLatest(
appStateHandler.selectedSpaceObservable.distinctUntilChanged(),
appStateHandler.selectedSpaceObservable.switchMap {
session.getPagedRoomSummariesLive(
roomSummaryQueryParams {
this.memberships = Membership.activeMemberships()
}, sortOrder = RoomSortOrder.NONE
).asObservable()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.computation())
},
BiFunction { _, _ ->
val selectedSpace = appStateHandler.safeActiveSpaceId()
val counts = session.getNotificationCountForRooms(
roomSummaryQueryParams {
this.memberships = listOf(Membership.JOIN)
this.activeSpaceId = ActiveSpaceFilter.ActiveSpace(null)
}
)
val rootCounts = session.spaceService().getRootSpaceSummaries()
.filter {
// filter out current selection
it.roomId != selectedSpace
}
CountInfo(
homeCount = counts,
otherCount = RoomAggregateNotificationCount(
rootCounts.fold(0, { acc, rs ->
acc + rs.notificationCount
}) + (counts.notificationCount.takeIf { selectedSpace != null } ?: 0),
rootCounts.fold(0, { acc, rs ->
acc + rs.highlightCount
}) + (counts.highlightCount.takeIf { selectedSpace != null } ?: 0)
)
)
}
).execute {
copy(
homeSpaceUnread = it.invoke()?.homeCount ?: RoomAggregateNotificationCount(0, 0),
otherSpacesUnread = it.invoke()?.otherCount ?: RoomAggregateNotificationCount(0, 0)
)
}
}
}

View file

@ -30,6 +30,7 @@ import im.vector.app.core.resources.StringProvider
import im.vector.app.features.ui.UiStateRepository
import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
@ -90,6 +91,7 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
}, sortOrder = RoomSortOrder.NONE
).asObservable()
.throttleFirst(300, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.computation())
.subscribe {
val counts = session.getNotificationCountForRooms(
roomSummaryQueryParams {
@ -168,7 +170,7 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
}
private fun observeSpaceSummaries() {
val spaceSummaryQueryParams = roomSummaryQueryParams() {
val spaceSummaryQueryParams = roomSummaryQueryParams {
memberships = listOf(Membership.JOIN, Membership.INVITE)
displayName = QueryStringValue.IsNotEmpty
excludeType = listOf(/**RoomType.MESSAGING,$*/

View file

@ -44,24 +44,24 @@
/>
<!-- Not yet done -->
<!-- <im.vector.app.features.home.room.list.UnreadCounterBadgeView-->
<!-- android:id="@+id/roomUnreadCounterBadgeView"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginEnd="0dp"-->
<!-- android:gravity="center"-->
<!-- android:minWidth="16dp"-->
<!-- android:minHeight="16dp"-->
<!-- android:paddingStart="4dp"-->
<!-- android:paddingEnd="4dp"-->
<!-- android:textColor="@android:color/white"-->
<!-- android:textSize="10sp"-->
<!-- android:visibility="gone"-->
<!-- android:layout_alignParentTop="true"-->
<!-- android:layout_alignParentEnd="true"-->
<!-- tools:background="@drawable/bg_unread_highlight"-->
<!-- tools:text="4"-->
<!-- tools:visibility="visible" />-->
<im.vector.app.features.home.room.list.UnreadCounterBadgeView
android:id="@+id/drawerUnreadCounterBadgeView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:gravity="center"
android:minWidth="16dp"
android:minHeight="16dp"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:textColor="@android:color/white"
android:textSize="10sp"
android:visibility="gone"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
tools:background="@drawable/bg_unread_highlight"
tools:text="4"
tools:visibility="visible" />
</RelativeLayout>
<LinearLayout