11package net.thunderbird.app.common.account
22
33import android.content.Context
4+ import androidx.annotation.VisibleForTesting
45import app.k9mail.feature.account.common.domain.entity.Account
56import app.k9mail.feature.account.common.domain.entity.SpecialFolderOption
67import app.k9mail.feature.account.common.domain.entity.SpecialFolderSettings
@@ -9,8 +10,8 @@ import app.k9mail.feature.account.setup.AccountSetupExternalContract.AccountCrea
910import app.k9mail.legacy.mailstore.domain.GetFolderIdsForTypeUseCase
1011import app.k9mail.legacy.mailstore.domain.SetPushForFolderUseCase
1112import com.fsck.k9.Core
12- import com.fsck.k9.Preferences
1313import com.fsck.k9.account.DeletePolicyProvider
14+ import com.fsck.k9.backend.BackendManager
1415import com.fsck.k9.controller.MessagingController
1516import com.fsck.k9.mail.FolderType
1617import com.fsck.k9.mail.ServerSettings
@@ -24,14 +25,17 @@ import com.fsck.k9.preferences.UnifiedInboxConfigurator
2425import kotlinx.coroutines.CoroutineDispatcher
2526import kotlinx.coroutines.Dispatchers
2627import kotlinx.coroutines.withContext
27- import net.thunderbird.core.android.account.LegacyAccountDto
28+ import net.thunderbird.core.android.account.AccountDefaultsProvider
29+ import net.thunderbird.core.android.account.LegacyAccount
30+ import net.thunderbird.core.android.account.LegacyAccountManager
2831import net.thunderbird.core.common.mail.Protocols
2932import net.thunderbird.core.featureflag.FeatureFlagProvider
3033import net.thunderbird.core.featureflag.keys.GeneratedFeatureFlagKey
3134import net.thunderbird.feature.account.AccountId
3235import net.thunderbird.feature.account.avatar.AvatarMonogramCreator
3336import net.thunderbird.feature.account.storage.profile.AvatarDto
3437import net.thunderbird.feature.account.storage.profile.AvatarTypeDto
38+ import net.thunderbird.feature.account.storage.profile.ProfileDto
3539import net.thunderbird.feature.mail.folder.api.SpecialFolderSelection
3640import net.thunderbird.legacy.logging.Log
3741
@@ -42,12 +46,14 @@ private const val TAG = "AccountCreator"
4246internal class AccountCreator (
4347 private val accountColorPicker : AccountColorPicker ,
4448 private val localFoldersCreator : SpecialLocalFoldersCreator ,
45- private val preferences : Preferences ,
49+ private val accountManager : LegacyAccountManager ,
4650 private val context : Context ,
4751 private val messagingController : MessagingController ,
52+ private val backendManager : BackendManager ,
4853 private val deletePolicyProvider : DeletePolicyProvider ,
4954 private val avatarMonogramCreator : AvatarMonogramCreator ,
5055 private val unifiedInboxConfigurator : UnifiedInboxConfigurator ,
56+ private val accountDefaultsProvider : AccountDefaultsProvider ,
5157 private val featureFlagProvider : FeatureFlagProvider ,
5258 private val getFolderIdsForTypeUseCase : GetFolderIdsForTypeUseCase ,
5359 private val setPushForFolderUseCase : SetPushForFolderUseCase ,
@@ -65,54 +71,76 @@ internal class AccountCreator(
6571 }
6672 }
6773
68- private suspend fun create (account : Account ): AccountId {
69- val newAccount = preferences.newAccount(account.id)
70-
71- newAccount.email = account.emailAddress
72-
73- newAccount.avatar = AvatarDto (
74- avatarType = AvatarTypeDto .MONOGRAM ,
75- avatarMonogram = avatarMonogramCreator.create(
76- name = account.options.accountName,
74+ internal suspend fun createLegacyAccount (account : Account ): LegacyAccount {
75+ val accountId = account.id
76+ val profile = ProfileDto (
77+ id = accountId,
78+ name = account.options.accountName,
79+ color = accountColorPicker.pickColor(),
80+ avatar = AvatarDto (
81+ accountId = accountId,
82+ avatarType = AvatarTypeDto .MONOGRAM ,
83+ avatarMonogram = avatarMonogramCreator.create(
84+ name = account.options.accountName,
85+ email = account.emailAddress,
86+ ),
87+ avatarImageUri = null ,
88+ avatarIconName = null ,
89+ ),
90+ )
91+ val defaultAccount = accountDefaultsProvider.applyDefaults(
92+ LegacyAccount (
93+ id = accountId,
94+ name = account.options.accountName.takeIf { it.isNotEmpty() },
7795 email = account.emailAddress,
96+ profile = profile,
97+ incomingServerSettings = account.incomingServerSettings,
98+ outgoingServerSettings = account.outgoingServerSettings,
99+ identities = emptyList(),
78100 ),
79- avatarImageUri = null ,
80- avatarIconName = null ,
81101 )
102+ val identity = defaultAccount.identities.first().copy(
103+ name = account.options.displayName,
104+ email = account.emailAddress,
105+ signatureUse = account.options.emailSignature != null ,
106+ signature = account.options.emailSignature,
107+ )
108+ return defaultAccount.copy(
109+ identities = listOf (identity),
110+ senderName = identity.name,
111+ signatureUse = identity.signatureUse,
112+ signature = identity.signature,
113+ oAuthState = account.authorizationState,
114+ isNotifyNewMail = account.options.showNotification,
115+ automaticCheckIntervalMinutes = account.options.checkFrequencyInMinutes,
116+ displayCount = account.options.messageDisplayCount,
117+ ).setIncomingServerSettings(account.incomingServerSettings)
118+ }
82119
83- newAccount.setIncomingServerSettings(account.incomingServerSettings)
84- newAccount.outgoingServerSettings = account.outgoingServerSettings
85-
86- newAccount.oAuthState = account.authorizationState
87-
88- newAccount.name = account.options.accountName
89- newAccount.senderName = account.options.displayName
90- if (account.options.emailSignature != null ) {
91- newAccount.signatureUse = true
92- newAccount.signature = account.options.emailSignature
93- }
94- newAccount.isNotifyNewMail = account.options.showNotification
95- newAccount.automaticCheckIntervalMinutes = account.options.checkFrequencyInMinutes
96- newAccount.displayCount = account.options.messageDisplayCount
97-
98- newAccount.deletePolicy = deletePolicyProvider.getDeletePolicy(newAccount.incomingServerSettings.type)
99- newAccount.chipColor = accountColorPicker.pickColor()
120+ private suspend fun create (account : Account ): AccountId {
121+ var newAccount = createLegacyAccount(account)
100122
101- localFoldersCreator.createSpecialLocalFolders(newAccount)
123+ // this needs the updated incoming server settings
124+ newAccount = newAccount.copy(
125+ deletePolicy = deletePolicyProvider.getDeletePolicy(newAccount.incomingServerSettings.type),
126+ )
102127
103- account.specialFolderSettings?.let { specialFolderSettings ->
104- newAccount.setSpecialFolders(specialFolderSettings)
105- }
128+ accountManager.createSync(newAccount)
129+ localFoldersCreator.createSpecialLocalFolders(newAccount.id)
106130
107- newAccount.markSetupFinished()
131+ newAccount = accountManager.updateSync(newAccount.id) { createdAccount ->
132+ val accountWithSpecialFolders = account.specialFolderSettings?.let { specialFolderSettings ->
133+ createdAccount.setSpecialFolders(specialFolderSettings)
134+ } ? : createdAccount
108135
109- preferences.saveAccount(newAccount)
136+ accountWithSpecialFolders.copy(isFinishedSetup = true )
137+ } ? : error(" Account not found after creating local folders" )
110138
111139 unifiedInboxConfigurator.configureUnifiedInbox()
112140
113141 Core .setServicesEnabled(context)
114142
115- messagingController.refreshFolderListBlocking (newAccount)
143+ refreshInitialFolderList (newAccount.id )
116144
117145 featureFlagProvider.provide(GeneratedFeatureFlagKey .PUSH_ENABLED_ON_INBOX_BY_DEFAULT )
118146 .onEnabled {
@@ -127,33 +155,54 @@ internal class AccountCreator(
127155 }
128156
129157 if (account.options.checkFrequencyInMinutes == - 1 ) {
130- messagingController.checkMail(newAccount, false , true , false , null )
158+ messagingController.checkMail(newAccount.id , false , true , false , null )
131159 }
132160
133161 return newAccount.id
134162 }
135163
164+ /* *
165+ * Refreshes folders during setup without saving the account snapshot taken before the refresh.
166+ */
167+ @VisibleForTesting
168+ internal fun refreshInitialFolderList (accountId : AccountId ) {
169+ val folderPathDelimiter = backendManager.getBackend(accountId).refreshFolderList()
170+ val now = System .currentTimeMillis()
171+ accountManager.updateSync(accountId) { account ->
172+ val updatedAccount = if (
173+ ! folderPathDelimiter.isNullOrEmpty() && folderPathDelimiter != account.folderPathDelimiter
174+ ) {
175+ account.updateFolderDelimiter(folderPathDelimiter)
176+ } else {
177+ account
178+ }
179+ updatedAccount.updateLastFolderListRefreshTime(now)
180+ } ? : error(" Account not found after refreshing folder list" )
181+ }
182+
136183 /* *
137184 * Set special folders by name.
138185 *
139186 * Since the folder list hasn't been synced yet, we don't have database IDs for the folders. So we use the same
140187 * mechanism that is used when importing settings. See [com.fsck.k9.mailstore.SpecialFolderUpdater] for details.
141188 */
142- private fun LegacyAccountDto.setSpecialFolders (specialFolders : SpecialFolderSettings ) {
143- importedArchiveFolder = specialFolders.archiveSpecialFolderOption.toFolderServerId()
144- archiveFolderSelection = specialFolders.archiveSpecialFolderOption.toFolderSelection()
189+ private fun LegacyAccount.setSpecialFolders (specialFolders : SpecialFolderSettings ): LegacyAccount {
190+ return copy(
191+ importedArchiveFolder = specialFolders.archiveSpecialFolderOption.toFolderServerId(),
192+ archiveFolderSelection = specialFolders.archiveSpecialFolderOption.toFolderSelection(),
145193
146- importedDraftsFolder = specialFolders.draftsSpecialFolderOption.toFolderServerId()
147- draftsFolderSelection = specialFolders.draftsSpecialFolderOption.toFolderSelection()
194+ importedDraftsFolder = specialFolders.draftsSpecialFolderOption.toFolderServerId(),
195+ draftsFolderSelection = specialFolders.draftsSpecialFolderOption.toFolderSelection(),
148196
149- importedSentFolder = specialFolders.sentSpecialFolderOption.toFolderServerId()
150- sentFolderSelection = specialFolders.sentSpecialFolderOption.toFolderSelection()
197+ importedSentFolder = specialFolders.sentSpecialFolderOption.toFolderServerId(),
198+ sentFolderSelection = specialFolders.sentSpecialFolderOption.toFolderSelection(),
151199
152- importedSpamFolder = specialFolders.spamSpecialFolderOption.toFolderServerId()
153- spamFolderSelection = specialFolders.spamSpecialFolderOption.toFolderSelection()
200+ importedSpamFolder = specialFolders.spamSpecialFolderOption.toFolderServerId(),
201+ spamFolderSelection = specialFolders.spamSpecialFolderOption.toFolderSelection(),
154202
155- importedTrashFolder = specialFolders.trashSpecialFolderOption.toFolderServerId()
156- trashFolderSelection = specialFolders.trashSpecialFolderOption.toFolderSelection()
203+ importedTrashFolder = specialFolders.trashSpecialFolderOption.toFolderServerId(),
204+ trashFolderSelection = specialFolders.trashSpecialFolderOption.toFolderSelection(),
205+ )
157206 }
158207
159208 private fun SpecialFolderOption.toFolderServerId (): String? {
@@ -181,17 +230,21 @@ internal class AccountCreator(
181230 }
182231}
183232
184- private fun LegacyAccountDto.setIncomingServerSettings (serverSettings : ServerSettings ) {
185- if (serverSettings.type == Protocols .IMAP ) {
186- useCompression = serverSettings.isUseCompression
187- isSendClientInfoEnabled = serverSettings.isSendClientInfo
188- incomingServerSettings = serverSettings.copy(
189- extra = createExtra(
190- autoDetectNamespace = serverSettings.autoDetectNamespace,
191- pathPrefix = serverSettings.pathPrefix,
233+ private fun LegacyAccount.setIncomingServerSettings (serverSettings : ServerSettings ): LegacyAccount {
234+ return if (serverSettings.type == Protocols .IMAP ) {
235+ copy(
236+ useCompression = serverSettings.isUseCompression,
237+ isSendClientInfoEnabled = serverSettings.isSendClientInfo,
238+ incomingServerSettings = serverSettings.copy(
239+ extra = createExtra(
240+ autoDetectNamespace = serverSettings.autoDetectNamespace,
241+ pathPrefix = serverSettings.pathPrefix,
242+ ),
192243 ),
193244 )
194245 } else {
195- incomingServerSettings = serverSettings
246+ copy(
247+ incomingServerSettings = serverSettings,
248+ )
196249 }
197250}
0 commit comments