Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,47 +1,41 @@
package app.k9mail.legacy.mailstore
package net.thunderbird.feature.mail.folder.api.data.repository

import net.thunderbird.core.outcome.Outcome
import net.thunderbird.feature.account.AccountId
import net.thunderbird.feature.mail.folder.api.Folder
import net.thunderbird.feature.mail.folder.api.data.repository.PushFolderTrackingRepository
import net.thunderbird.feature.mail.folder.api.FolderServerId
import net.thunderbird.feature.mail.folder.api.data.FolderError

/**
* Provides access to local and remote folder information and management.
*
* TODO: Refactor FolderRepository into focused contracts.
* Problem: This interface mixes unrelated responsibilities (read models, remote listing, push tracking,
* and per-flag mutations), which makes it hard to test and evolve.
*/
@Suppress("TooManyFunctions")
interface FolderRepository : PushFolderTrackingRepository {
interface FolderQueryRepository {
/**
* Returns a [Folder] for the given [accountId] and [folderId].
*
* @param accountId The account identifier.
* @param folderId The folder identifier.
*/
suspend fun getFolder(accountId: AccountId, folderId: Long): Folder?
suspend fun findById(accountId: AccountId, folderId: Long): Outcome<Folder?, FolderError>

/**
* Returns the server ID for the given [accountId] and [folderId].
*
* @param accountId The account identifier.
* @param folderId The folder identifier.
*/
fun getFolderServerId(accountId: AccountId, folderId: Long): String?
suspend fun findFolderServerIdById(accountId: AccountId, folderId: Long): Outcome<FolderServerId?, FolderError>

/**
* Returns the folder ID for the given [accountId] and [folderServerId].
*
* @param accountId The account identifier.
* @param folderServerId The folder server identifier.
*/
fun getFolderId(accountId: AccountId, folderServerId: String): Long?
suspend fun findIdByServerId(accountId: AccountId, folderServerId: FolderServerId): Outcome<Long?, FolderError>

/**
* Returns `true` if the folder with [folderId] is present for the given [accountId].
*
* @param accountId The account identifier.
* @param folderId The folder identifier.
*/
fun isFolderPresent(accountId: AccountId, folderId: Long): Boolean
suspend fun isPresent(accountId: AccountId, folderId: Long): Boolean
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package net.thunderbird.feature.mail.message.list.internal.ui.state.sideeffect

import androidx.compose.ui.graphics.Color
import app.k9mail.legacy.mailstore.FolderRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import net.thunderbird.core.logging.Logger
Expand All @@ -10,6 +9,7 @@ import net.thunderbird.feature.account.AccountId
import net.thunderbird.feature.account.UnifiedAccountId
import net.thunderbird.feature.account.profile.AccountProfileRepository
import net.thunderbird.feature.mail.folder.api.FolderType
import net.thunderbird.feature.mail.folder.api.data.repository.FolderQueryRepository
import net.thunderbird.feature.mail.folder.api.data.repository.RemoteFolderQueryRepository
import net.thunderbird.feature.mail.message.list.ui.effect.MessageListEffect
import net.thunderbird.feature.mail.message.list.ui.event.FolderEvent
Expand All @@ -27,7 +27,7 @@ internal class LoadFolderInformationSideEffect(
private val folderId: Long?,
dispatch: suspend (MessageListEvent) -> Unit,
private val logger: Logger,
private val folderRepository: FolderRepository,
private val folderQueryRepository: FolderQueryRepository,
private val remoteFolderQueryRepository: RemoteFolderQueryRepository,
private val profileRepository: AccountProfileRepository,
) : MessageListStateSideEffectHandler(logger, dispatch) {
Expand Down Expand Up @@ -64,7 +64,9 @@ internal class LoadFolderInformationSideEffect(

private suspend fun consumeSingleAccountFolder(folderId: Long): ConsumeResult {
val accountId = accountIds.first()
val folder = folderRepository.getFolder(accountId, folderId)
val folder = folderQueryRepository
.findById(accountId, folderId)
.fold(onSuccess = { it }, onFailure = { null })
return if (folder != null) {
val remoteFolder = if (!folder.isLocalOnly) {
remoteFolderQueryRepository
Expand Down Expand Up @@ -97,7 +99,7 @@ internal class LoadFolderInformationSideEffect(
private val accountIds: Set<AccountId>,
private val folderId: Long?,
private val logger: Logger,
private val folderRepository: FolderRepository,
private val folderQueryRepository: FolderQueryRepository,
private val remoteFolderQueryRepository: RemoteFolderQueryRepository,
private val profileRepository: AccountProfileRepository,
) : MessageListStateSideEffectHandlerFactory {
Expand All @@ -110,7 +112,7 @@ internal class LoadFolderInformationSideEffect(
folderId = folderId,
dispatch = dispatch,
logger = logger,
folderRepository = folderRepository,
folderQueryRepository = folderQueryRepository,
remoteFolderQueryRepository = remoteFolderQueryRepository,
profileRepository = profileRepository,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ internal val messageListSideEffectsModule = module {
accountIds = args.accountIds,
folderId = args.folderId,
logger = get(),
folderRepository = get(),
folderQueryRepository = get(),
remoteFolderQueryRepository = get(),
profileRepository = get(),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package net.thunderbird.feature.mail.message.list.internal.fakes

import net.thunderbird.core.outcome.Outcome
import net.thunderbird.feature.account.AccountId
import net.thunderbird.feature.mail.folder.api.Folder
import net.thunderbird.feature.mail.folder.api.FolderServerId
import net.thunderbird.feature.mail.folder.api.data.FolderError
import net.thunderbird.feature.mail.folder.api.data.repository.FolderQueryRepository

class FakeFolderQueryRepository(
private val localFolders: Map<AccountId, List<Folder>> = emptyMap(),
) : FolderQueryRepository {
override suspend fun findById(accountId: AccountId, folderId: Long): Outcome<Folder?, FolderError> =
Outcome.success(localFolders[accountId]?.find { it.id == folderId })

override suspend fun findFolderServerIdById(
accountId: AccountId,
folderId: Long,
): Outcome<FolderServerId?, FolderError> = error("Not implemented")

override suspend fun findIdByServerId(
accountId: AccountId,
folderServerId: FolderServerId,
): Outcome<Long?, FolderError> = error("Not implemented")

override suspend fun isPresent(accountId: AccountId, folderId: Long): Boolean = error("Not implemented")
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package net.thunderbird.feature.mail.message.list.internal.ui.state.sideeffect

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import app.k9mail.legacy.mailstore.FolderRepository
import assertk.assertThat
import assertk.assertions.containsExactly
import assertk.assertions.isEmpty
Expand All @@ -30,8 +29,9 @@ import net.thunderbird.feature.account.profile.AccountProfile
import net.thunderbird.feature.account.profile.AccountProfileRepository
import net.thunderbird.feature.mail.folder.api.FolderType
import net.thunderbird.feature.mail.folder.api.RemoteFolder
import net.thunderbird.feature.mail.folder.api.data.repository.FolderQueryRepository
import net.thunderbird.feature.mail.folder.api.data.repository.RemoteFolderQueryRepository
import net.thunderbird.feature.mail.message.list.internal.fakes.FakeFolderRepository
import net.thunderbird.feature.mail.message.list.internal.fakes.FakeFolderQueryRepository
import net.thunderbird.feature.mail.message.list.internal.fakes.FakeRemoteFolderQueryRepository
import net.thunderbird.feature.mail.message.list.internal.fakes.RecordingSuspendFunction
import net.thunderbird.feature.mail.message.list.ui.event.FolderEvent
Expand All @@ -52,7 +52,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
val testSubject = createTestSubject(
accountIds = setOf(accountId),
folderId = folderId,
folderRepository = createFolderRepository(
folderQueryRepository = createFolderQueryRepository(
accountId = accountId,
folderId = folderId,
folder = folder,
Expand Down Expand Up @@ -151,7 +151,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(firstAccountId, secondAccountId),
folderId = folderId,
dispatch = dispatch.function,
folderRepository = createFolderRepository(
folderQueryRepository = createFolderQueryRepository(
accountId = firstAccountId,
folderId = folderId,
folder = folder,
Expand Down Expand Up @@ -192,7 +192,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
val folderId = 7L
val folder = createMailFolder(id = folderId, name = "Local", isLocalOnly = true)
val dispatch = RecordingSuspendFunction<MessageListEvent>()
val folderRepository = createFolderRepository(
val folderQueryRepository = createFolderQueryRepository(
accountId = accountId,
folderId = folderId,
folder = folder,
Expand All @@ -202,7 +202,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(accountId),
folderId = folderId,
dispatch = dispatch.function,
folderRepository = folderRepository,
folderQueryRepository = folderQueryRepository,
profileRepository = FakeAccountProfileRepository(
profiles = listOf(createAccountProfile(accountId = accountId, expectedColor)),
),
Expand Down Expand Up @@ -241,7 +241,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
type = FolderType.INBOX,
)
val dispatch = RecordingSuspendFunction<MessageListEvent>()
val folderRepository = createFolderRepository(
val folderQueryRepository = createFolderQueryRepository(
accountId = accountId,
folderId = folderId,
folder = folder,
Expand All @@ -255,7 +255,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(accountId),
folderId = folderId,
dispatch = dispatch.function,
folderRepository = folderRepository,
folderQueryRepository = folderQueryRepository,
remoteFolderQueryRepository = remoteFolderQueryRepository,
profileRepository = FakeAccountProfileRepository(
profiles = listOf(createAccountProfile(accountId = accountId, expectedColor)),
Expand Down Expand Up @@ -294,7 +294,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(accountId),
folderId = folderId,
dispatch = dispatch.function,
folderRepository = createFolderRepository(
folderQueryRepository = createFolderQueryRepository(
accountId = accountId,
folderId = folderId,
folder = folder,
Expand Down Expand Up @@ -337,7 +337,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
val accountId = AccountIdFactory.create()
val folderId = 10L
val dispatch = RecordingSuspendFunction<MessageListEvent>()
val folderRepository = createFolderRepository(
val folderQueryRepository = createFolderQueryRepository(
accountId = accountId,
folderId = folderId,
folder = null,
Expand All @@ -346,7 +346,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(accountId),
folderId = folderId,
dispatch = dispatch.function,
folderRepository = folderRepository,
folderQueryRepository = folderQueryRepository,
)

// Act
Expand Down Expand Up @@ -374,7 +374,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
type = FolderType.INBOX,
)
val dispatch = RecordingSuspendFunction<MessageListEvent>()
val folderRepository = createFolderRepository(
val folderQueryRepository = createFolderQueryRepository(
accountId = accountId,
folderId = folderId,
folder = folder,
Expand All @@ -388,7 +388,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(accountId),
folderId = folderId,
dispatch = dispatch.function,
folderRepository = folderRepository,
folderQueryRepository = folderQueryRepository,
remoteFolderQueryRepository = remoteFolderQueryRepository,
profileRepository = FakeAccountProfileRepository(
profiles = listOf(createAccountProfile(accountId = accountId, expectedColor)),
Expand Down Expand Up @@ -422,7 +422,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
accountIds = setOf(AccountIdFactory.create()),
folderId = 1L,
logger = TestLogger(),
folderRepository = createFolderRepository(
folderQueryRepository = createFolderQueryRepository(
accountId = AccountIdFactory.create(),
folderId = 1L,
folder = null,
Expand All @@ -447,7 +447,7 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
folderId: Long? = 1L,
dispatch: suspend (MessageListEvent) -> Unit = {},
logger: Logger = TestLogger(),
folderRepository: FolderRepository = FakeFolderRepository(),
folderQueryRepository: FolderQueryRepository = FakeFolderQueryRepository(),
remoteFolderQueryRepository: RemoteFolderQueryRepository = FakeRemoteFolderQueryRepository(),
profileRepository: AccountProfileRepository = FakeAccountProfileRepository(
profiles = accountIds.map(::createAccountProfile),
Expand All @@ -457,16 +457,16 @@ class LoadFolderInformationSideEffectTest : BaseSideEffectHandlerTest() {
folderId = folderId,
dispatch = dispatch,
logger = logger,
folderRepository = folderRepository,
folderQueryRepository = folderQueryRepository,
remoteFolderQueryRepository = remoteFolderQueryRepository,
profileRepository = profileRepository,
)

private fun createFolderRepository(
private fun createFolderQueryRepository(
accountId: AccountId,
folderId: Long,
folder: MailFolder?,
): FolderRepository = FakeFolderRepository(
): FolderQueryRepository = FakeFolderQueryRepository(
localFolders = mapOf(accountId to listOfNotNull(folder?.copy(id = folderId))),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ val unreadWidgetModule = module {
preferences = get(),
messageCountsProvider = get(),
defaultFolderProvider = get(),
folderRepository = get(),
folderQueryRepository = get(),
folderNameFormatter = get(),
coreResourceProvider = get(),
logger = get(),
Expand All @@ -34,5 +34,5 @@ val unreadWidgetModule = module {
logger = get(),
)
}
single { UnreadWidgetMigrations(accountRepository = get(), folderRepository = get()) }
single { UnreadWidgetMigrations(accountRepository = get(), folderQueryRepository = get()) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package app.k9mail.feature.widget.unread

import android.content.Context
import android.content.Intent
import app.k9mail.legacy.mailstore.FolderRepository
import app.k9mail.legacy.message.controller.MessageCountsProvider
import app.k9mail.legacy.ui.folder.FolderNameFormatter
import com.fsck.k9.CoreResourceProvider
Expand All @@ -13,6 +12,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.thunderbird.core.android.account.LegacyAccountDto
import net.thunderbird.core.logging.Logger
import net.thunderbird.core.outcome.fold
import net.thunderbird.feature.mail.folder.api.data.repository.FolderQueryRepository
import net.thunderbird.feature.search.legacy.LocalMessageSearch
import net.thunderbird.feature.search.legacy.SearchAccount

Expand All @@ -24,7 +25,7 @@ class UnreadWidgetDataProvider(
private val preferences: Preferences,
private val messageCountsProvider: MessageCountsProvider,
private val defaultFolderProvider: DefaultFolderProvider,
private val folderRepository: FolderRepository,
private val folderQueryRepository: FolderQueryRepository,
private val folderNameFormatter: FolderNameFormatter,
private val coreResourceProvider: CoreResourceProvider,
private val logger: Logger,
Expand Down Expand Up @@ -103,7 +104,8 @@ class UnreadWidgetDataProvider(
}

private suspend fun getFolderDisplayName(account: LegacyAccountDto, folderId: Long): String {
val folder = folderRepository.getFolder(account.id, folderId)
val folder = folderQueryRepository.findById(account.id, folderId)
.fold(onSuccess = { it }, onFailure = { null })
return if (folder != null) {
folderNameFormatter.displayName(folder)
} else {
Expand Down
Loading
Loading