Rewrite FoldersViewModel to use Flow

This commit is contained in:
cketti 2021-08-26 22:02:29 +02:00
parent a36d7e9d78
commit 288486e247
5 changed files with 77 additions and 28 deletions

View file

@ -29,6 +29,10 @@ object DI {
fun <T : Any> get(clazz: Class<T>): T {
return koinGet(clazz)
}
inline fun <reified T : Any> get(): T {
return koinGet(T::class.java)
}
}
interface EarlyInit

View file

@ -2,6 +2,9 @@ package com.fsck.k9.mailstore
import com.fsck.k9.Account
import com.fsck.k9.Account.FolderMode
import com.fsck.k9.DI
import com.fsck.k9.controller.MessagingController
import com.fsck.k9.controller.SimpleMessagingListener
import com.fsck.k9.mail.FolderClass
import com.fsck.k9.preferences.AccountManager
import kotlinx.coroutines.CoroutineDispatcher
@ -52,6 +55,42 @@ class FolderRepository(
}.sortedWith(sortForDisplay)
}
fun getDisplayFoldersFlow(account: Account, displayMode: FolderMode): Flow<List<DisplayFolder>> {
val messagingController = DI.get<MessagingController>()
return callbackFlow {
send(getDisplayFolders(account, displayMode))
val listener = object : SimpleMessagingListener() {
override fun folderStatusChanged(statusChangedAccount: Account, folderId: Long) {
if (statusChangedAccount.uuid == account.uuid) {
launch {
send(getDisplayFolders(account, displayMode))
}
}
}
}
messagingController.addListener(listener)
awaitClose {
messagingController.removeListener(listener)
}
}.buffer(capacity = Channel.CONFLATED)
.distinctUntilChanged()
.flowOn(ioDispatcher)
}
fun getDisplayFoldersFlow(account: Account): Flow<List<DisplayFolder>> {
return accountManager.getAccountFlow(account.uuid)
.map { latestAccount ->
AccountContainer(latestAccount, latestAccount.folderDisplayMode)
}
.distinctUntilChanged()
.flatMapLatest { (account, folderDisplayMode) ->
getDisplayFoldersFlow(account, folderDisplayMode)
}
}
fun getFolder(account: Account, folderId: Long): Folder? {
val messageStore = messageStoreManager.getMessageStore(account)
return messageStore.getFolder(folderId) { folder ->
@ -244,6 +283,11 @@ class FolderRepository(
get() = if (syncClass == FolderClass.INHERITED) displayClass else syncClass
}
private data class AccountContainer(
val account: Account,
val folderDisplayMode: FolderMode
)
data class Folder(val id: Long, val name: String, val type: FolderType, val isLocalOnly: Boolean)
data class RemoteFolder(val id: Long, val serverId: String, val name: String, val type: FolderType)

View file

@ -94,6 +94,7 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
private var folderBadgeStyle: BadgeStyle? = null
private var openedAccountUuid: String? = null
private var openedFolderId: Long? = null
private var latestFolderList: List<DisplayFolder>? = null
val layout: DrawerLayout
get() = drawer
@ -292,7 +293,7 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
if (oldSelectedBackgroundColor != selectedBackgroundColor) {
// Recreate list of folders with updated account color
setUserFolders(foldersViewModel.getFolderListLiveData().value)
setUserFolders(latestFolderList)
}
}
@ -352,6 +353,7 @@ class K9Drawer(private val parent: MessageList, savedInstanceState: Bundle?) : K
}
private fun setUserFolders(folders: List<DisplayFolder>?) {
this.latestFolderList = folders
clearUserFolders()
var openedFolderDrawerId: Long = -1

View file

@ -1,42 +1,41 @@
package com.fsck.k9.ui.folders
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import com.fsck.k9.Account
import com.fsck.k9.mailstore.DisplayFolder
import com.fsck.k9.mailstore.FolderRepository
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
class FoldersViewModel(private val foldersLiveDataFactory: FoldersLiveDataFactory) : ViewModel() {
private var currentFoldersLiveData: FoldersLiveData? = null
private val foldersLiveData = MediatorLiveData<List<DisplayFolder>>()
@OptIn(ExperimentalCoroutinesApi::class)
class FoldersViewModel(private val folderRepository: FolderRepository) : ViewModel() {
private val inputFlow = MutableSharedFlow<Account?>(replay = 1)
private val foldersFlow = inputFlow
.flatMapLatest { account ->
if (account == null) {
flowOf(emptyList())
} else {
folderRepository.getDisplayFoldersFlow(account)
}
}
fun getFolderListLiveData(): LiveData<List<DisplayFolder>> {
return foldersLiveData
return foldersFlow.asLiveData()
}
fun loadFolders(account: Account) {
if (currentFoldersLiveData?.account?.uuid == account.uuid) return
viewModelScope.launch {
// When switching accounts we want to remove the old list right away, not keep it until the new list
// has been loaded.
inputFlow.emit(null)
removeCurrentFoldersLiveData()
val liveData = foldersLiveDataFactory.create(account)
currentFoldersLiveData = liveData
foldersLiveData.addSource(liveData) { items ->
foldersLiveData.value = items
}
}
fun stopLoadingFolders() {
removeCurrentFoldersLiveData()
foldersLiveData.value = null
}
private fun removeCurrentFoldersLiveData() {
currentFoldersLiveData?.let {
foldersLiveData.value = emptyList()
currentFoldersLiveData = null
foldersLiveData.removeSource(it)
inputFlow.emit(account)
}
}
}

View file

@ -8,5 +8,5 @@ val foldersUiModule = module {
single { FolderNameFormatterFactory() }
factory { (context: Context) -> FolderNameFormatter(context.resources) }
single { FoldersLiveDataFactory(get(), get(), get()) }
viewModel { FoldersViewModel(get()) }
viewModel { FoldersViewModel(folderRepository = get()) }
}