Merge pull request #593 from vector-im/feature/group_avatar
Group avatar live
This commit is contained in:
commit
aea34da81e
@ -13,6 +13,7 @@ Other changes:
|
|||||||
|
|
||||||
Bugfix:
|
Bugfix:
|
||||||
- Fix issue on upload error in loop (#587)
|
- Fix issue on upload error in loop (#587)
|
||||||
|
- after login, the icon in the top left is a green 'A' for (all communities) rather than my avatar (#267)
|
||||||
|
|
||||||
Translations:
|
Translations:
|
||||||
-
|
-
|
||||||
|
@ -20,7 +20,6 @@ import androidx.lifecycle.LiveData
|
|||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.android.MainThreadDisposable
|
import io.reactivex.android.MainThreadDisposable
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
private class LiveDataObservable<T>(
|
private class LiveDataObservable<T>(
|
||||||
|
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.room.model.RoomSummary
|
|||||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||||
import im.vector.matrix.android.api.session.sync.SyncState
|
import im.vector.matrix.android.api.session.sync.SyncState
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
|
import im.vector.matrix.android.api.util.Optional
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
|
|
||||||
@ -45,6 +46,10 @@ class RxSession(private val session: Session) {
|
|||||||
return session.livePushers().asObservable()
|
return session.livePushers().asObservable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun liveUser(userId: String): Observable<Optional<User>> {
|
||||||
|
return session.liveUser(userId).asObservable().distinctUntilChanged()
|
||||||
|
}
|
||||||
|
|
||||||
fun liveUsers(): Observable<List<User>> {
|
fun liveUsers(): Observable<List<User>> {
|
||||||
return session.liveUsers().asObservable()
|
return session.liveUsers().asObservable()
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import androidx.paging.PagedList
|
|||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.api.util.Optional
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface defines methods to get users. It's implemented at the session level.
|
* This interface defines methods to get users. It's implemented at the session level.
|
||||||
@ -47,9 +48,9 @@ interface UserService {
|
|||||||
/**
|
/**
|
||||||
* Observe a live user from a userId
|
* Observe a live user from a userId
|
||||||
* @param userId the userId to look for.
|
* @param userId the userId to look for.
|
||||||
* @return a Livedata of user with userId
|
* @return a LiveData of user with userId
|
||||||
*/
|
*/
|
||||||
fun liveUser(userId: String): LiveData<User?>
|
fun liveUser(userId: String): LiveData<Optional<User>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observe a live list of users sorted alphabetically
|
* Observe a live list of users sorted alphabetically
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package im.vector.matrix.android.api.util
|
||||||
|
|
||||||
|
data class Optional<T : Any> constructor(private val value: T?) {
|
||||||
|
|
||||||
|
fun get(): T {
|
||||||
|
return value!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOrNull(): T? {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getOrElse(fn: () -> T): T {
|
||||||
|
return value ?: fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun <T : Any> from(value: T?): Optional<T> {
|
||||||
|
return Optional(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> T?.toOptional() = Optional(this)
|
@ -26,6 +26,8 @@ import im.vector.matrix.android.api.MatrixCallback
|
|||||||
import im.vector.matrix.android.api.session.user.UserService
|
import im.vector.matrix.android.api.session.user.UserService
|
||||||
import im.vector.matrix.android.api.session.user.model.User
|
import im.vector.matrix.android.api.session.user.model.User
|
||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.api.util.Optional
|
||||||
|
import im.vector.matrix.android.api.util.toOptional
|
||||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||||
@ -66,7 +68,7 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona
|
|||||||
return userEntity.asDomain()
|
return userEntity.asDomain()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun liveUser(userId: String): LiveData<User?> {
|
override fun liveUser(userId: String): LiveData<Optional<User>> {
|
||||||
val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
||||||
UserEntity.where(realm, userId)
|
UserEntity.where(realm, userId)
|
||||||
}
|
}
|
||||||
@ -74,6 +76,7 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona
|
|||||||
results
|
results
|
||||||
.map { it.asDomain() }
|
.map { it.asDomain() }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
|
.toOptional()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,19 +20,31 @@ import com.jakewharton.rxrelay2.BehaviorRelay
|
|||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
|
||||||
open class RxStore<T>(defaultValue: T? = null) {
|
open class RxStore<T>(private val defaultValue: T? = null) {
|
||||||
|
|
||||||
private val storeSubject: BehaviorRelay<T> = if (defaultValue == null) {
|
var storeRelay = createRelay()
|
||||||
BehaviorRelay.create<T>()
|
|
||||||
} else {
|
fun clear() {
|
||||||
BehaviorRelay.createDefault(defaultValue)
|
storeRelay = createRelay()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(): T? {
|
||||||
|
return storeRelay.value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun observe(): Observable<T> {
|
fun observe(): Observable<T> {
|
||||||
return storeSubject.hide().observeOn(Schedulers.computation())
|
return storeRelay.hide().observeOn(Schedulers.computation())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun post(value: T) {
|
fun post(value: T) {
|
||||||
storeSubject.accept(value)
|
storeRelay.accept(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createRelay(): BehaviorRelay<T> {
|
||||||
|
return if (defaultValue == null) {
|
||||||
|
BehaviorRelay.create<T>()
|
||||||
|
} else {
|
||||||
|
BehaviorRelay.createDefault(defaultValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,8 @@ class HomeActivityViewModel @AssistedInject constructor(@Assisted initialState:
|
|||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
|
selectedGroupStore.clear()
|
||||||
|
homeRoomListStore.clear()
|
||||||
session.removeListener(this)
|
session.removeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,18 +17,17 @@
|
|||||||
package im.vector.riotx.features.home
|
package im.vector.riotx.features.home
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import androidx.core.view.forEachIndexed
|
import androidx.core.view.forEachIndexed
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import com.airbnb.mvrx.args
|
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationItemView
|
import com.google.android.material.bottomnavigation.BottomNavigationItemView
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
||||||
import im.vector.matrix.android.api.session.Session
|
import im.vector.matrix.android.api.session.Session
|
||||||
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
|
||||||
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ScreenComponent
|
import im.vector.riotx.core.di.ScreenComponent
|
||||||
import im.vector.riotx.core.platform.ToolbarConfigurable
|
import im.vector.riotx.core.platform.ToolbarConfigurable
|
||||||
@ -38,26 +37,17 @@ import im.vector.riotx.features.home.room.list.RoomListFragment
|
|||||||
import im.vector.riotx.features.home.room.list.RoomListParams
|
import im.vector.riotx.features.home.room.list.RoomListParams
|
||||||
import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
|
import im.vector.riotx.features.home.room.list.UnreadCounterBadgeView
|
||||||
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
import im.vector.riotx.features.workers.signout.SignOutViewModel
|
||||||
import kotlinx.android.parcel.Parcelize
|
|
||||||
import kotlinx.android.synthetic.main.fragment_home_detail.*
|
import kotlinx.android.synthetic.main.fragment_home_detail.*
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data class HomeDetailParams(
|
|
||||||
val groupId: String,
|
|
||||||
val groupName: String,
|
|
||||||
val groupAvatar: String
|
|
||||||
) : Parcelable
|
|
||||||
|
|
||||||
|
|
||||||
private const val INDEX_CATCHUP = 0
|
private const val INDEX_CATCHUP = 0
|
||||||
private const val INDEX_PEOPLE = 1
|
private const val INDEX_PEOPLE = 1
|
||||||
private const val INDEX_ROOMS = 2
|
private const val INDEX_ROOMS = 2
|
||||||
|
|
||||||
class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
||||||
|
|
||||||
private val params: HomeDetailParams by args()
|
|
||||||
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
|
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
|
||||||
|
|
||||||
private val viewModel: HomeDetailViewModel by fragmentViewModel()
|
private val viewModel: HomeDetailViewModel by fragmentViewModel()
|
||||||
@ -84,11 +74,25 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
|||||||
setupToolbar()
|
setupToolbar()
|
||||||
setupKeysBackupBanner()
|
setupKeysBackupBanner()
|
||||||
|
|
||||||
|
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
|
||||||
|
onGroupChange(groupSummary.orNull())
|
||||||
|
}
|
||||||
viewModel.selectSubscribe(this, HomeDetailViewState::displayMode) { displayMode ->
|
viewModel.selectSubscribe(this, HomeDetailViewState::displayMode) { displayMode ->
|
||||||
switchDisplayMode(displayMode)
|
switchDisplayMode(displayMode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||||
|
groupSummary?.let {
|
||||||
|
avatarRenderer.render(
|
||||||
|
it.avatarUrl,
|
||||||
|
it.groupId,
|
||||||
|
it.displayName,
|
||||||
|
groupToolbarAvatarImageView
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupKeysBackupBanner() {
|
private fun setupKeysBackupBanner() {
|
||||||
// Keys backup banner
|
// Keys backup banner
|
||||||
// Use the SignOutViewModel, it observe the keys backup state and this is what we need here
|
// Use the SignOutViewModel, it observe the keys backup state and this is what we need here
|
||||||
@ -130,12 +134,6 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
|||||||
parentActivity.configure(groupToolbar)
|
parentActivity.configure(groupToolbar)
|
||||||
}
|
}
|
||||||
groupToolbar.title = ""
|
groupToolbar.title = ""
|
||||||
avatarRenderer.render(
|
|
||||||
params.groupAvatar,
|
|
||||||
params.groupId,
|
|
||||||
params.groupName,
|
|
||||||
groupToolbarAvatarImageView
|
|
||||||
)
|
|
||||||
groupToolbarAvatarImageView.setOnClickListener {
|
groupToolbarAvatarImageView.setOnClickListener {
|
||||||
navigationViewModel.goTo(HomeActivity.Navigation.OpenDrawer)
|
navigationViewModel.goTo(HomeActivity.Navigation.OpenDrawer)
|
||||||
}
|
}
|
||||||
@ -199,6 +197,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) {
|
override fun invalidate() = withState(viewModel) {
|
||||||
|
Timber.v(it.toString())
|
||||||
unreadCounterBadgeViews[INDEX_CATCHUP].render(UnreadCounterBadgeView.State(it.notificationCountCatchup, it.notificationHighlightCatchup))
|
unreadCounterBadgeViews[INDEX_CATCHUP].render(UnreadCounterBadgeView.State(it.notificationCountCatchup, it.notificationHighlightCatchup))
|
||||||
unreadCounterBadgeViews[INDEX_PEOPLE].render(UnreadCounterBadgeView.State(it.notificationCountPeople, it.notificationHighlightPeople))
|
unreadCounterBadgeViews[INDEX_PEOPLE].render(UnreadCounterBadgeView.State(it.notificationCountPeople, it.notificationHighlightPeople))
|
||||||
unreadCounterBadgeViews[INDEX_ROOMS].render(UnreadCounterBadgeView.State(it.notificationCountRooms, it.notificationHighlightRooms))
|
unreadCounterBadgeViews[INDEX_ROOMS].render(UnreadCounterBadgeView.State(it.notificationCountRooms, it.notificationHighlightRooms))
|
||||||
@ -207,10 +206,8 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newInstance(args: HomeDetailParams): HomeDetailFragment {
|
fun newInstance(): HomeDetailFragment {
|
||||||
return HomeDetailFragment().apply {
|
return HomeDetailFragment()
|
||||||
setArguments(args)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ import im.vector.matrix.android.api.session.Session
|
|||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotx.core.di.HasScreenInjector
|
import im.vector.riotx.core.di.HasScreenInjector
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.features.home.group.SelectedGroupStore
|
||||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||||
import im.vector.riotx.features.ui.UiStateRepository
|
import im.vector.riotx.features.ui.UiStateRepository
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
@ -36,7 +38,9 @@ import io.reactivex.schedulers.Schedulers
|
|||||||
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val uiStateRepository: UiStateRepository,
|
private val uiStateRepository: UiStateRepository,
|
||||||
private val homeRoomListStore: HomeRoomListObservableStore)
|
private val selectedGroupStore: SelectedGroupStore,
|
||||||
|
private val homeRoomListStore: HomeRoomListObservableStore,
|
||||||
|
private val stringProvider: StringProvider)
|
||||||
: VectorViewModel<HomeDetailViewState>(initialState) {
|
: VectorViewModel<HomeDetailViewState>(initialState) {
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
@ -62,6 +66,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
observeSyncState()
|
observeSyncState()
|
||||||
|
observeSelectedGroupStore()
|
||||||
observeRoomSummaries()
|
observeRoomSummaries()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,42 +93,48 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun observeSelectedGroupStore() {
|
||||||
|
selectedGroupStore
|
||||||
|
.observe()
|
||||||
|
.subscribe {
|
||||||
|
setState {
|
||||||
|
copy(groupSummary = it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disposeOnClear()
|
||||||
|
}
|
||||||
|
|
||||||
private fun observeRoomSummaries() {
|
private fun observeRoomSummaries() {
|
||||||
homeRoomListStore
|
homeRoomListStore
|
||||||
.observe()
|
.observe()
|
||||||
.observeOn(Schedulers.computation())
|
.observeOn(Schedulers.computation())
|
||||||
.subscribe { list ->
|
.map { it.asSequence() }
|
||||||
list.let { summaries ->
|
.subscribe { summaries ->
|
||||||
val peopleNotifications = summaries
|
val peopleNotifications = summaries
|
||||||
.filter { it.isDirect }
|
.filter { it.isDirect }
|
||||||
.map { it.notificationCount }
|
.map { it.notificationCount }
|
||||||
.takeIf { it.isNotEmpty() }
|
.sumBy { i -> i }
|
||||||
?.sumBy { i -> i }
|
val peopleHasHighlight = summaries
|
||||||
?: 0
|
.filter { it.isDirect }
|
||||||
val peopleHasHighlight = summaries
|
.any { it.highlightCount > 0 }
|
||||||
.filter { it.isDirect }
|
|
||||||
.any { it.highlightCount > 0 }
|
|
||||||
|
|
||||||
val roomsNotifications = summaries
|
val roomsNotifications = summaries
|
||||||
.filter { !it.isDirect }
|
.filter { !it.isDirect }
|
||||||
.map { it.notificationCount }
|
.map { it.notificationCount }
|
||||||
.takeIf { it.isNotEmpty() }
|
.sumBy { i -> i }
|
||||||
?.sumBy { i -> i }
|
val roomsHasHighlight = summaries
|
||||||
?: 0
|
.filter { !it.isDirect }
|
||||||
val roomsHasHighlight = summaries
|
.any { it.highlightCount > 0 }
|
||||||
.filter { !it.isDirect }
|
|
||||||
.any { it.highlightCount > 0 }
|
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
notificationCountCatchup = peopleNotifications + roomsNotifications,
|
notificationCountCatchup = peopleNotifications + roomsNotifications,
|
||||||
notificationHighlightCatchup = peopleHasHighlight || roomsHasHighlight,
|
notificationHighlightCatchup = peopleHasHighlight || roomsHasHighlight,
|
||||||
notificationCountPeople = peopleNotifications,
|
notificationCountPeople = peopleNotifications,
|
||||||
notificationHighlightPeople = peopleHasHighlight,
|
notificationHighlightPeople = peopleHasHighlight,
|
||||||
notificationCountRooms = roomsNotifications,
|
notificationCountRooms = roomsNotifications,
|
||||||
notificationHighlightRooms = roomsHasHighlight
|
notificationHighlightRooms = roomsHasHighlight
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
|
@ -16,11 +16,14 @@
|
|||||||
|
|
||||||
package im.vector.riotx.features.home
|
package im.vector.riotx.features.home
|
||||||
|
|
||||||
|
import arrow.core.Option
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||||
import im.vector.matrix.android.api.session.sync.SyncState
|
import im.vector.matrix.android.api.session.sync.SyncState
|
||||||
import im.vector.riotx.features.home.room.list.RoomListFragment
|
import im.vector.riotx.features.home.room.list.RoomListFragment
|
||||||
|
|
||||||
data class HomeDetailViewState(
|
data class HomeDetailViewState(
|
||||||
|
val groupSummary: Option<GroupSummary> = Option.empty(),
|
||||||
val displayMode: RoomListFragment.DisplayMode = RoomListFragment.DisplayMode.HOME,
|
val displayMode: RoomListFragment.DisplayMode = RoomListFragment.DisplayMode.HOME,
|
||||||
val notificationCountCatchup: Int = 0,
|
val notificationCountCatchup: Int = 0,
|
||||||
val notificationHighlightCatchup: Boolean = false,
|
val notificationHighlightCatchup: Boolean = false,
|
||||||
|
@ -51,7 +51,8 @@ class HomeDrawerFragment : VectorBaseFragment() {
|
|||||||
val groupListFragment = GroupListFragment.newInstance()
|
val groupListFragment = GroupListFragment.newInstance()
|
||||||
replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer)
|
replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer)
|
||||||
}
|
}
|
||||||
session.liveUser(session.myUserId).observeK(this) { user ->
|
session.liveUser(session.myUserId).observeK(this) { optionalUser ->
|
||||||
|
val user = optionalUser?.getOrNull()
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
avatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView)
|
avatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView)
|
||||||
homeDrawerUsernameView.text = user.displayName
|
homeDrawerUsernameView.text = user.displayName
|
||||||
|
@ -36,8 +36,7 @@ class HomeNavigator @Inject constructor() {
|
|||||||
activity?.let {
|
activity?.let {
|
||||||
it.drawerLayout?.closeDrawer(GravityCompat.START)
|
it.drawerLayout?.closeDrawer(GravityCompat.START)
|
||||||
|
|
||||||
val args = HomeDetailParams(groupSummary.groupId, groupSummary.displayName, groupSummary.avatarUrl)
|
val homeDetailFragment = HomeDetailFragment.newInstance()
|
||||||
val homeDetailFragment = HomeDetailFragment.newInstance(args)
|
|
||||||
it.replaceFragment(homeDetailFragment, R.id.homeDetailFragmentContainer)
|
it.replaceFragment(homeDetailFragment, R.id.homeDetailFragmentContainer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,13 @@ import im.vector.riotx.core.extensions.postLiveEvent
|
|||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import im.vector.riotx.core.resources.StringProvider
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
import im.vector.riotx.core.utils.LiveEvent
|
import im.vector.riotx.core.utils.LiveEvent
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.functions.BiFunction
|
||||||
|
|
||||||
const val ALL_COMMUNITIES_GROUP_ID = "ALL_COMMUNITIES_GROUP_ID"
|
const val ALL_COMMUNITIES_GROUP_ID = "ALL_COMMUNITIES_GROUP_ID"
|
||||||
|
|
||||||
class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState,
|
class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState,
|
||||||
private val selectedGroupHolder: SelectedGroupStore,
|
private val selectedGroupStore: SelectedGroupStore,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val stringProvider: StringProvider
|
private val stringProvider: StringProvider
|
||||||
) : VectorViewModel<GroupListViewState>(initialState) {
|
) : VectorViewModel<GroupListViewState>(initialState) {
|
||||||
@ -69,9 +71,13 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
|
|||||||
private fun observeSelectionState() {
|
private fun observeSelectionState() {
|
||||||
selectSubscribe(GroupListViewState::selectedGroup) {
|
selectSubscribe(GroupListViewState::selectedGroup) {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
_openGroupLiveData.postLiveEvent(it)
|
val selectedGroup = selectedGroupStore.get()?.orNull()
|
||||||
|
// We only wan to open group if the updated selectedGroup is a different one.
|
||||||
|
if (selectedGroup?.groupId != it.groupId) {
|
||||||
|
_openGroupLiveData.postLiveEvent(it)
|
||||||
|
}
|
||||||
val optionGroup = Option.fromNullable(it)
|
val optionGroup = Option.fromNullable(it)
|
||||||
selectedGroupHolder.post(optionGroup)
|
selectedGroupStore.post(optionGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,22 +97,33 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun observeGroupSummaries() {
|
private fun observeGroupSummaries() {
|
||||||
session
|
Observable.combineLatest<GroupSummary, List<GroupSummary>, List<GroupSummary>>(
|
||||||
.rx()
|
session
|
||||||
.liveGroupSummaries()
|
.rx()
|
||||||
// Keep only joined groups. Group invitations will be managed later
|
.liveUser(session.myUserId)
|
||||||
.map { it.filter { groupSummary -> groupSummary.membership == Membership.JOIN } }
|
.map { optionalUser ->
|
||||||
.map {
|
GroupSummary(
|
||||||
val myUser = session.getUser(session.myUserId)
|
groupId = ALL_COMMUNITIES_GROUP_ID,
|
||||||
val allCommunityGroup = GroupSummary(
|
membership = Membership.JOIN,
|
||||||
groupId = ALL_COMMUNITIES_GROUP_ID,
|
displayName = stringProvider.getString(R.string.group_all_communities),
|
||||||
membership = Membership.JOIN,
|
avatarUrl = optionalUser.getOrNull()?.avatarUrl ?: "")
|
||||||
displayName = stringProvider.getString(R.string.group_all_communities),
|
},
|
||||||
avatarUrl = myUser?.avatarUrl ?: "")
|
session
|
||||||
listOf(allCommunityGroup) + it
|
.rx()
|
||||||
|
.liveGroupSummaries()
|
||||||
|
// Keep only joined groups. Group invitations will be managed later
|
||||||
|
.map { it.filter { groupSummary -> groupSummary.membership == Membership.JOIN } },
|
||||||
|
BiFunction { allCommunityGroup, communityGroups ->
|
||||||
|
listOf(allCommunityGroup) + communityGroups
|
||||||
}
|
}
|
||||||
|
)
|
||||||
.execute { async ->
|
.execute { async ->
|
||||||
val newSelectedGroup = selectedGroup ?: async()?.firstOrNull()
|
val currentSelectedGroupId = selectedGroup?.groupId
|
||||||
|
val newSelectedGroup = if (currentSelectedGroupId != null) {
|
||||||
|
async()?.find { it.groupId == currentSelectedGroupId }
|
||||||
|
} else {
|
||||||
|
async()?.firstOrNull()
|
||||||
|
}
|
||||||
copy(asyncGroups = async, selectedGroup = newSelectedGroup)
|
copy(asyncGroups = async, selectedGroup = newSelectedGroup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user