Loading app/core/src/main/java/com/fsck/k9/DI.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt +44 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 -> Loading Loading @@ -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) Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } Loading Loading @@ -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 Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersViewModel.kt +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) } } } app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/KoinModule.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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()) } } Loading
app/core/src/main/java/com/fsck/k9/DI.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
app/core/src/main/java/com/fsck/k9/mailstore/FolderRepository.kt +44 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 -> Loading Loading @@ -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) Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/K9Drawer.kt +3 −1 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) } } Loading Loading @@ -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 Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/FoldersViewModel.kt +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) } } }
app/ui/legacy/src/main/java/com/fsck/k9/ui/folders/KoinModule.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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()) } }