Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 288486e2 authored by cketti's avatar cketti
Browse files

Rewrite FoldersViewModel to use Flow

parent a36d7e9d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+44 −0
Original line number Diff line number Diff line
@@ -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)
+3 −1
Original line number Diff line number Diff line
@@ -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
+26 −27
Original line number Diff line number Diff line
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

class FoldersViewModel(private val foldersLiveDataFactory: FoldersLiveDataFactory) : ViewModel() {
    private var currentFoldersLiveData: FoldersLiveData? = null
    private val foldersLiveData = MediatorLiveData<List<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

@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

        removeCurrentFoldersLiveData()

        val liveData = foldersLiveDataFactory.create(account)
        currentFoldersLiveData = liveData

        foldersLiveData.addSource(liveData) { items ->
            foldersLiveData.value = items
        }
    }

    fun stopLoadingFolders() {
        removeCurrentFoldersLiveData()
        foldersLiveData.value = null
    }
        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)

    private fun removeCurrentFoldersLiveData() {
        currentFoldersLiveData?.let {
            foldersLiveData.value = emptyList()
            currentFoldersLiveData = null
            foldersLiveData.removeSource(it)
            inputFlow.emit(account)
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -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()) }
}