Signal-Android/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/ContactSearchViewModel.kt

106 wiersze
4.1 KiB
Kotlin

package org.thoughtcrime.securesms.contacts.paged
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.signal.paging.LivePagedData
import org.signal.paging.PagedData
import org.signal.paging.PagingConfig
import org.signal.paging.PagingController
import org.thoughtcrime.securesms.groups.SelectionLimits
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.livedata.Store
/**
* Simple, reusable view model that manages a ContactSearchPagedDataSource as well as filter and expansion state.
*/
class ContactSearchViewModel(
private val selectionLimits: SelectionLimits,
private val contactSearchRepository: ContactSearchRepository
) : ViewModel() {
private val disposables = CompositeDisposable()
private val pagingConfig = PagingConfig.Builder()
.setBufferPages(1)
.setPageSize(20)
.setStartIndex(0)
.build()
private val pagedData = MutableLiveData<LivePagedData<ContactSearchKey, ContactSearchData>>()
private val configurationStore = Store(ContactSearchState())
private val selectionStore = Store<Set<ContactSearchKey>>(emptySet())
val controller: LiveData<PagingController<ContactSearchKey>> = Transformations.map(pagedData) { it.controller }
val data: LiveData<List<ContactSearchData>> = Transformations.switchMap(pagedData) { it.data }
val configurationState: LiveData<ContactSearchState> = configurationStore.stateLiveData
val selectionState: LiveData<Set<ContactSearchKey>> = selectionStore.stateLiveData
override fun onCleared() {
disposables.clear()
}
fun setConfiguration(contactSearchConfiguration: ContactSearchConfiguration) {
val pagedDataSource = ContactSearchPagedDataSource(contactSearchConfiguration)
pagedData.value = PagedData.createForLiveData(pagedDataSource, pagingConfig)
}
fun setQuery(query: String?) {
configurationStore.update { it.copy(query = query) }
}
fun expandSection(sectionKey: ContactSearchConfiguration.SectionKey) {
configurationStore.update { it.copy(expandedSections = it.expandedSections + sectionKey) }
}
fun setKeysSelected(contactSearchKeys: Set<ContactSearchKey>) {
disposables += contactSearchRepository.filterOutUnselectableContactSearchKeys(contactSearchKeys).subscribe { results ->
if (results.any { !it.isSelectable }) {
// TODO [alex] -- Pop an error.
return@subscribe
}
val newSelectionEntries = results.filter { it.isSelectable }.map { it.key } - getSelectedContacts()
val newSelectionSize = newSelectionEntries.size + getSelectedContacts().size
if (selectionLimits.hasRecommendedLimit() && getSelectedContacts().size < selectionLimits.recommendedLimit && newSelectionSize >= selectionLimits.recommendedLimit) {
// Pop a warning
} else if (selectionLimits.hasHardLimit() && newSelectionSize > selectionLimits.hardLimit) {
// Pop an error
return@subscribe
}
selectionStore.update { state -> state + newSelectionEntries }
}
}
fun setKeysNotSelected(contactSearchKeys: Set<ContactSearchKey>) {
selectionStore.update { it - contactSearchKeys }
}
fun getSelectedContacts(): Set<ContactSearchKey> {
return selectionStore.state
}
fun addToVisibleGroupStories(groupStories: Set<ContactSearchKey.Story>) {
configurationStore.update { state ->
state.copy(
groupStories = state.groupStories + groupStories.map {
val recipient = Recipient.resolved(it.recipientId)
ContactSearchData.Story(recipient, recipient.participants.size)
}
)
}
}
class Factory(private val selectionLimits: SelectionLimits, private val repository: ContactSearchRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.cast(ContactSearchViewModel(selectionLimits, repository)) as T
}
}
}