Skip to content

Commit 37d047a

Browse files
authored
Merge pull request #9770 from wmontwe/refactor-message-list-fragment
refactor: message list fragment
2 parents f555f60 + a8caa14 commit 37d047a

105 files changed

Lines changed: 1580 additions & 379 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app-common/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ dependencies {
4343
implementation(projects.feature.widget.messageList)
4444

4545
implementation(projects.mail.protocols.imap)
46+
implementation(projects.backend.imap)
4647

4748
implementation(libs.androidx.work.runtime)
4849
implementation(libs.androidx.lifecycle.process)

app-common/src/main/kotlin/net/thunderbird/app/common/account/AccountColorPicker.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ package net.thunderbird.app.common.account
22

33
import android.content.res.Resources
44
import app.k9mail.core.ui.legacy.theme2.common.R
5-
import net.thunderbird.core.android.account.AccountManager
5+
import net.thunderbird.core.android.account.LegacyAccountDtoManager
66

77
internal class AccountColorPicker(
8-
private val accountManager: AccountManager,
8+
private val accountManager: LegacyAccountDtoManager,
99
private val resources: Resources,
1010
) {
1111
fun pickColor(): Int {

app-common/src/main/kotlin/net/thunderbird/app/common/account/AppCommonAccountModule.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import app.k9mail.feature.account.setup.AccountSetupExternalContract
44
import net.thunderbird.app.common.account.data.DefaultAccountProfileLocalDataSource
55
import net.thunderbird.app.common.account.data.DefaultLegacyAccountManager
66
import net.thunderbird.core.android.account.AccountDefaultsProvider
7+
import net.thunderbird.core.android.account.LegacyAccount
78
import net.thunderbird.core.android.account.LegacyAccountManager
89
import net.thunderbird.feature.account.avatar.AvatarMonogramCreator
910
import net.thunderbird.feature.account.avatar.DefaultAvatarMonogramCreator
1011
import net.thunderbird.feature.account.core.AccountCoreExternalContract.AccountProfileLocalDataSource
1112
import net.thunderbird.feature.account.core.featureAccountCoreModule
1213
import net.thunderbird.feature.account.storage.legacy.featureAccountStorageLegacyModule
14+
import net.thunderbird.feature.mail.account.api.AccountManager
1315
import org.koin.android.ext.koin.androidApplication
16+
import org.koin.dsl.binds
1417
import org.koin.dsl.module
1518

1619
internal val appCommonAccountModule = module {
@@ -19,12 +22,12 @@ internal val appCommonAccountModule = module {
1922
featureAccountStorageLegacyModule,
2023
)
2124

22-
single<LegacyAccountManager> {
25+
single<AccountManager<LegacyAccount>> {
2326
DefaultLegacyAccountManager(
2427
accountManager = get(),
2528
accountDataMapper = get(),
2629
)
27-
}
30+
} binds arrayOf(LegacyAccountManager::class)
2831

2932
single<AccountProfileLocalDataSource> {
3033
DefaultAccountProfileLocalDataSource(

app-common/src/main/kotlin/net/thunderbird/app/common/account/data/DefaultLegacyAccountManager.kt

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ package net.thunderbird.app.common.account.data
22

33
import kotlinx.coroutines.flow.Flow
44
import kotlinx.coroutines.flow.map
5-
import net.thunderbird.core.android.account.AccountManager
65
import net.thunderbird.core.android.account.LegacyAccount
6+
import net.thunderbird.core.android.account.LegacyAccountDtoManager
77
import net.thunderbird.core.android.account.LegacyAccountManager
88
import net.thunderbird.feature.account.AccountId
9-
import net.thunderbird.feature.account.storage.legacy.mapper.DefaultLegacyAccountWrapperDataMapper
9+
import net.thunderbird.feature.account.storage.legacy.mapper.LegacyAccountDataMapper
1010

1111
internal class DefaultLegacyAccountManager(
12-
private val accountManager: AccountManager,
13-
private val accountDataMapper: DefaultLegacyAccountWrapperDataMapper,
12+
private val accountManager: LegacyAccountDtoManager,
13+
private val accountDataMapper: LegacyAccountDataMapper,
1414
) : LegacyAccountManager {
1515

1616
override fun getAll(): Flow<List<LegacyAccount>> {
@@ -35,4 +35,34 @@ internal class DefaultLegacyAccountManager(
3535
accountDataMapper.toDto(account),
3636
)
3737
}
38+
39+
override fun getAccounts(): List<LegacyAccount> {
40+
return accountManager.getAccounts()
41+
.map { account ->
42+
accountDataMapper.toDomain(account)
43+
}
44+
}
45+
46+
override fun getAccountsFlow(): Flow<List<LegacyAccount>> = getAll()
47+
48+
override fun getAccount(accountUuid: String): LegacyAccount? {
49+
val dto = accountManager.getAccount(accountUuid)
50+
return dto?.let { accountDataMapper.toDomain(it) }
51+
}
52+
53+
override fun getAccountFlow(accountUuid: String): Flow<LegacyAccount?> {
54+
return accountManager.getAccountFlow(accountUuid).map { account ->
55+
account?.let {
56+
accountDataMapper.toDomain(it)
57+
}
58+
}
59+
}
60+
61+
override fun moveAccount(account: LegacyAccount, newPosition: Int) {
62+
accountManager.moveAccount(accountDataMapper.toDto(account), newPosition)
63+
}
64+
65+
override fun saveAccount(account: LegacyAccount) {
66+
accountManager.saveAccount(accountDataMapper.toDto(account))
67+
}
3868
}

app-common/src/main/kotlin/net/thunderbird/app/common/feature/AppCommonFeatureModule.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package net.thunderbird.app.common.feature
22

33
import app.k9mail.feature.launcher.FeatureLauncherExternalContract
44
import app.k9mail.feature.launcher.di.featureLauncherModule
5+
import net.thunderbird.app.common.feature.mail.appCommonFeatureMailModule
56
import net.thunderbird.feature.navigation.drawer.api.NavigationDrawerExternalContract
67
import net.thunderbird.feature.notification.impl.inject.featureNotificationModule
78
import org.koin.android.ext.koin.androidContext
@@ -10,6 +11,7 @@ import org.koin.dsl.module
1011
internal val appCommonFeatureModule = module {
1112
includes(featureLauncherModule)
1213
includes(featureNotificationModule)
14+
includes(appCommonFeatureMailModule)
1315

1416
factory<FeatureLauncherExternalContract.AccountSetupFinishedLauncher> {
1517
AccountSetupFinishedLauncher(
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package net.thunderbird.app.common.feature.mail
2+
3+
import com.fsck.k9.backend.api.BackendStorage
4+
import com.fsck.k9.mailstore.LegacyAccountDtoBackendStorageFactory
5+
import net.thunderbird.backend.api.BackendStorageFactory
6+
import net.thunderbird.core.android.account.LegacyAccount
7+
import net.thunderbird.core.android.account.LegacyAccountDto
8+
import net.thunderbird.feature.account.storage.legacy.mapper.LegacyAccountDataMapper
9+
import net.thunderbird.feature.mail.account.api.BaseAccount
10+
11+
/**
12+
* A [BackendStorageFactory] that supports both [LegacyAccountDto] and [LegacyAccount].
13+
*/
14+
class BaseAccountBackendStorageFactory(
15+
private val legacyFactory: LegacyAccountDtoBackendStorageFactory,
16+
private val legacyMapper: LegacyAccountDataMapper,
17+
) : BackendStorageFactory<BaseAccount> {
18+
override fun createBackendStorage(account: BaseAccount): BackendStorage {
19+
return when (account) {
20+
is LegacyAccountDto -> legacyFactory.createBackendStorage(account)
21+
is LegacyAccount -> {
22+
val legacyAccountDto = legacyMapper.toDto(account)
23+
legacyFactory.createBackendStorage(legacyAccountDto)
24+
}
25+
else -> throw IllegalArgumentException("Unsupported account type: ${account::class.java.name}")
26+
}
27+
}
28+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package net.thunderbird.app.common.feature.mail
2+
3+
import com.fsck.k9.backend.api.Backend
4+
import com.fsck.k9.backends.ImapBackendFactory
5+
import net.thunderbird.backend.api.BackendFactory
6+
import net.thunderbird.core.android.account.LegacyAccount
7+
import net.thunderbird.core.android.account.LegacyAccountDto
8+
import net.thunderbird.core.common.mail.Protocols
9+
import net.thunderbird.feature.account.storage.legacy.mapper.LegacyAccountDataMapper
10+
import net.thunderbird.feature.mail.account.api.BaseAccount
11+
12+
/**
13+
* A [BackendFactory] that supports both [LegacyAccountDto] and [LegacyAccount].
14+
*/
15+
class BaseAccountImapBackendFactory(
16+
private val legacyFactory: ImapBackendFactory,
17+
private val legacyMapper: LegacyAccountDataMapper,
18+
) : BackendFactory<BaseAccount> {
19+
override fun createBackend(account: BaseAccount): Backend {
20+
val dto = when (account) {
21+
is LegacyAccountDto -> account
22+
is LegacyAccount -> legacyMapper.toDto(account)
23+
else -> error("Unsupported account type ${account::class.qualifiedName}")
24+
}
25+
require(dto.incomingServerSettings.type == Protocols.IMAP) {
26+
"IMAP backend requested for non‑IMAP account (id=${dto.id}, type=${dto.incomingServerSettings.type})"
27+
}
28+
return legacyFactory.createBackend(dto)
29+
}
30+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package net.thunderbird.app.common.feature.mail
2+
3+
import com.fsck.k9.mailstore.LegacyAccountDtoSpecialFolderUpdaterFactory
4+
import net.thunderbird.core.android.account.LegacyAccount
5+
import net.thunderbird.core.android.account.LegacyAccountDto
6+
import net.thunderbird.feature.account.storage.legacy.mapper.LegacyAccountDataMapper
7+
import net.thunderbird.feature.mail.account.api.BaseAccount
8+
import net.thunderbird.feature.mail.folder.api.SpecialFolderUpdater
9+
10+
/**
11+
* A [SpecialFolderUpdater.Factory] that supports both [LegacyAccountDto] and [LegacyAccount].
12+
*/
13+
class BaseAccountSpecialFolderUpdaterFactory(
14+
private val legacyFactory: LegacyAccountDtoSpecialFolderUpdaterFactory,
15+
private val legacyMapper: LegacyAccountDataMapper,
16+
) : SpecialFolderUpdater.Factory<BaseAccount> {
17+
override fun create(account: BaseAccount): SpecialFolderUpdater {
18+
return when (account) {
19+
is LegacyAccountDto -> legacyFactory.create(account)
20+
is LegacyAccount -> {
21+
val legacyAccountDto = legacyMapper.toDto(account)
22+
legacyFactory.create(legacyAccountDto)
23+
}
24+
25+
else -> throw IllegalArgumentException("Unsupported account type: ${account::class.java.name}")
26+
}
27+
}
28+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package net.thunderbird.app.common.feature.mail
2+
3+
import com.fsck.k9.mailstore.DefaultSpecialFolderUpdater
4+
import com.fsck.k9.mailstore.LegacyAccountDtoSpecialFolderUpdaterFactory
5+
import net.thunderbird.backend.api.BackendFactory
6+
import net.thunderbird.backend.api.BackendStorageFactory
7+
import net.thunderbird.backend.api.folder.RemoteFolderCreator
8+
import net.thunderbird.backend.imap.DefaultImapRemoteFolderCreatorFactory
9+
import net.thunderbird.backend.imap.ImapRemoteFolderCreatorFactory
10+
import net.thunderbird.feature.mail.account.api.BaseAccount
11+
import net.thunderbird.feature.mail.folder.api.SpecialFolderUpdater
12+
import org.koin.dsl.module
13+
14+
internal val appCommonFeatureMailModule = module {
15+
16+
single<BackendStorageFactory<BaseAccount>> {
17+
BaseAccountBackendStorageFactory(
18+
legacyFactory = get(),
19+
legacyMapper = get(),
20+
)
21+
}
22+
23+
factory<LegacyAccountDtoSpecialFolderUpdaterFactory> {
24+
DefaultSpecialFolderUpdater.Factory(
25+
folderRepository = get(),
26+
specialFolderSelectionStrategy = get(),
27+
preferences = get(),
28+
)
29+
}
30+
31+
factory<SpecialFolderUpdater.Factory<BaseAccount>> {
32+
BaseAccountSpecialFolderUpdaterFactory(
33+
legacyFactory = get(),
34+
legacyMapper = get(),
35+
)
36+
}
37+
38+
single<BackendFactory<BaseAccount>> {
39+
BaseAccountImapBackendFactory(
40+
legacyFactory = get(),
41+
legacyMapper = get(),
42+
)
43+
}
44+
45+
single<ImapRemoteFolderCreatorFactory> {
46+
DefaultImapRemoteFolderCreatorFactory(
47+
logger = get(),
48+
backendFactory = get(),
49+
)
50+
}
51+
52+
single<RemoteFolderCreator.Factory> {
53+
RemoteFolderCreatorResolver(
54+
imapFactory = get(),
55+
)
56+
}
57+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package net.thunderbird.app.common.feature.mail
2+
3+
import com.fsck.k9.mail.FolderType
4+
import com.fsck.k9.mail.folders.FolderServerId
5+
import net.thunderbird.backend.api.folder.RemoteFolderCreationOutcome
6+
import net.thunderbird.backend.api.folder.RemoteFolderCreator
7+
import net.thunderbird.core.outcome.Outcome
8+
9+
/**
10+
* A [RemoteFolderCreator] that does nothing and always returns [RemoteFolderCreationOutcome.Success.AlreadyExists].
11+
*/
12+
object NoOpRemoteFolderCreator : RemoteFolderCreator {
13+
override suspend fun create(
14+
folderServerId: FolderServerId,
15+
mustCreate: Boolean,
16+
folderType: FolderType,
17+
): Outcome<RemoteFolderCreationOutcome.Success, RemoteFolderCreationOutcome.Error> {
18+
return Outcome.success(RemoteFolderCreationOutcome.Success.AlreadyExists)
19+
}
20+
}

0 commit comments

Comments
 (0)