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/choosefolder/ChooseFolderActivity.kt +7 −15 Original line number Diff line number Diff line Loading @@ -7,7 +7,6 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.widget.SearchView import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode Loading @@ -20,7 +19,6 @@ import com.fsck.k9.ui.R import com.fsck.k9.ui.base.K9Activity import com.fsck.k9.ui.folders.FolderIconProvider import com.fsck.k9.ui.folders.FolderNameFormatter import com.fsck.k9.ui.folders.FoldersLiveData import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter import java.util.Locale Loading @@ -42,11 +40,6 @@ class ChooseFolderActivity : K9Activity() { private var scrollToFolderId: Long? = null private var messageReference: String? = null private var showDisplayableOnly = false private var foldersLiveData: FoldersLiveData? = null private val folderListObserver = Observer<List<DisplayFolder>> { folders -> updateFolderList(folders) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading @@ -60,12 +53,14 @@ class ChooseFolderActivity : K9Activity() { initializeFolderList() viewModel.getFolders().observe(this) { folders -> updateFolderList(folders) } val savedDisplayMode = savedInstanceState?.getString(STATE_DISPLAY_MODE)?.let { FolderMode.valueOf(it) } val displayMode = savedDisplayMode ?: getInitialDisplayMode() foldersLiveData = viewModel.getFolders(account, displayMode).apply { observe(this@ChooseFolderActivity, folderListObserver) } viewModel.setDisplayMode(account, displayMode) } private fun decodeArguments(savedInstanceState: Bundle?): Boolean { Loading Loading @@ -137,7 +132,7 @@ class ChooseFolderActivity : K9Activity() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) scrollToFolderId?.let { folderId -> outState.putLong(STATE_SCROLL_TO_FOLDER_ID, folderId) } outState.putString(STATE_DISPLAY_MODE, foldersLiveData?.displayMode?.name) outState.putString(STATE_DISPLAY_MODE, viewModel.currentDisplayMode?.name) } override fun onCreateOptionsMenu(menu: Menu): Boolean { Loading Loading @@ -181,10 +176,7 @@ class ChooseFolderActivity : K9Activity() { } private fun setDisplayMode(displayMode: FolderMode) { foldersLiveData?.removeObserver(folderListObserver) foldersLiveData = viewModel.getFolders(account, displayMode).apply { observe(this@ChooseFolderActivity, folderListObserver) } viewModel.setDisplayMode(account, displayMode) } private fun returnResult(folderId: Long, displayName: String) { Loading app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt +28 −11 Original line number Diff line number Diff line package com.fsck.k9.ui.choosefolder import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode import com.fsck.k9.ui.folders.FoldersLiveData import com.fsck.k9.ui.folders.FoldersLiveDataFactory 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.launch class ChooseFolderViewModel(private val foldersLiveDataFactory: FoldersLiveDataFactory) : ViewModel() { private var foldersLiveData: FoldersLiveData? = null @OptIn(ExperimentalCoroutinesApi::class) class ChooseFolderViewModel(private val folderRepository: FolderRepository) : ViewModel() { private val inputFlow = MutableSharedFlow<DisplayMode>(replay = 1) private val foldersFlow = inputFlow .flatMapLatest { (account, displayMode) -> folderRepository.getDisplayFoldersFlow(account, displayMode) } var currentDisplayMode: FolderMode? = null private set fun getFolders(account: Account, displayMode: FolderMode): FoldersLiveData { val liveData = foldersLiveData if (liveData != null && liveData.account.uuid == account.uuid && liveData.displayMode == displayMode) { return liveData fun getFolders(): LiveData<List<DisplayFolder>> { return foldersFlow.asLiveData() } return foldersLiveDataFactory.create(account, displayMode).also { foldersLiveData = it fun setDisplayMode(account: Account, displayMode: FolderMode) { currentDisplayMode = displayMode viewModelScope.launch { inputFlow.emit(DisplayMode(account, displayMode)) } } } private data class DisplayMode(val account: Account, val displayMode: FolderMode) 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/choosefolder/ChooseFolderActivity.kt +7 −15 Original line number Diff line number Diff line Loading @@ -7,7 +7,6 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.widget.SearchView import androidx.lifecycle.Observer import androidx.recyclerview.widget.RecyclerView import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode Loading @@ -20,7 +19,6 @@ import com.fsck.k9.ui.R import com.fsck.k9.ui.base.K9Activity import com.fsck.k9.ui.folders.FolderIconProvider import com.fsck.k9.ui.folders.FolderNameFormatter import com.fsck.k9.ui.folders.FoldersLiveData import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.adapters.ItemAdapter import java.util.Locale Loading @@ -42,11 +40,6 @@ class ChooseFolderActivity : K9Activity() { private var scrollToFolderId: Long? = null private var messageReference: String? = null private var showDisplayableOnly = false private var foldersLiveData: FoldersLiveData? = null private val folderListObserver = Observer<List<DisplayFolder>> { folders -> updateFolderList(folders) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Loading @@ -60,12 +53,14 @@ class ChooseFolderActivity : K9Activity() { initializeFolderList() viewModel.getFolders().observe(this) { folders -> updateFolderList(folders) } val savedDisplayMode = savedInstanceState?.getString(STATE_DISPLAY_MODE)?.let { FolderMode.valueOf(it) } val displayMode = savedDisplayMode ?: getInitialDisplayMode() foldersLiveData = viewModel.getFolders(account, displayMode).apply { observe(this@ChooseFolderActivity, folderListObserver) } viewModel.setDisplayMode(account, displayMode) } private fun decodeArguments(savedInstanceState: Bundle?): Boolean { Loading Loading @@ -137,7 +132,7 @@ class ChooseFolderActivity : K9Activity() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) scrollToFolderId?.let { folderId -> outState.putLong(STATE_SCROLL_TO_FOLDER_ID, folderId) } outState.putString(STATE_DISPLAY_MODE, foldersLiveData?.displayMode?.name) outState.putString(STATE_DISPLAY_MODE, viewModel.currentDisplayMode?.name) } override fun onCreateOptionsMenu(menu: Menu): Boolean { Loading Loading @@ -181,10 +176,7 @@ class ChooseFolderActivity : K9Activity() { } private fun setDisplayMode(displayMode: FolderMode) { foldersLiveData?.removeObserver(folderListObserver) foldersLiveData = viewModel.getFolders(account, displayMode).apply { observe(this@ChooseFolderActivity, folderListObserver) } viewModel.setDisplayMode(account, displayMode) } private fun returnResult(folderId: Long, displayName: String) { Loading
app/ui/legacy/src/main/java/com/fsck/k9/ui/choosefolder/ChooseFolderViewModel.kt +28 −11 Original line number Diff line number Diff line package com.fsck.k9.ui.choosefolder import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import com.fsck.k9.Account import com.fsck.k9.Account.FolderMode import com.fsck.k9.ui.folders.FoldersLiveData import com.fsck.k9.ui.folders.FoldersLiveDataFactory 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.launch class ChooseFolderViewModel(private val foldersLiveDataFactory: FoldersLiveDataFactory) : ViewModel() { private var foldersLiveData: FoldersLiveData? = null @OptIn(ExperimentalCoroutinesApi::class) class ChooseFolderViewModel(private val folderRepository: FolderRepository) : ViewModel() { private val inputFlow = MutableSharedFlow<DisplayMode>(replay = 1) private val foldersFlow = inputFlow .flatMapLatest { (account, displayMode) -> folderRepository.getDisplayFoldersFlow(account, displayMode) } var currentDisplayMode: FolderMode? = null private set fun getFolders(account: Account, displayMode: FolderMode): FoldersLiveData { val liveData = foldersLiveData if (liveData != null && liveData.account.uuid == account.uuid && liveData.displayMode == displayMode) { return liveData fun getFolders(): LiveData<List<DisplayFolder>> { return foldersFlow.asLiveData() } return foldersLiveDataFactory.create(account, displayMode).also { foldersLiveData = it fun setDisplayMode(account: Account, displayMode: FolderMode) { currentDisplayMode = displayMode viewModelScope.launch { inputFlow.emit(DisplayMode(account, displayMode)) } } } private data class DisplayMode(val account: Account, val displayMode: FolderMode)