Merge pull request #7384 from thunderbird/change_server_settings_form_to_loading_view

Change ServerSettings to support loading state
This commit is contained in:
Wolf-Martell Montwé 2023-11-28 16:26:02 +00:00 committed by GitHub
commit 2c38500608
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 106 additions and 44 deletions

View file

@ -7,7 +7,7 @@ import app.k9mail.core.featureflag.FeatureFlagKey
class InMemoryFeatureFlagFactory : FeatureFlagFactory {
override fun createFeatureCatalog(): List<FeatureFlag> {
return listOf(
FeatureFlag(FeatureFlagKey("new_account_edit"), false),
FeatureFlag(FeatureFlagKey("new_account_edit"), true),
)
}
}

View file

@ -81,6 +81,8 @@ class ModifyIncomingServerSettingsViewModelTest {
imapPrefix = StringInputField(value = ""),
imapUseCompression = true,
imapSendClientId = true,
isLoading = false,
),
)
}

View file

@ -70,6 +70,8 @@ class ModifyOutgoingServerSettingsViewModelTest {
authenticationType = AuthenticationType.PasswordCleartext,
username = StringInputField(value = "username"),
password = StringInputField(value = "password"),
isLoading = false,
),
)
}

View file

@ -13,11 +13,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import app.k9mail.core.ui.compose.common.PreviewDevices
import app.k9mail.core.ui.compose.designsystem.molecule.ContentLoadingErrorView
import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer
import app.k9mail.core.ui.compose.theme.K9Theme
import app.k9mail.core.ui.compose.theme.MainTheme
import app.k9mail.core.ui.compose.theme.ThunderbirdTheme
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.common.ui.loadingerror.rememberContentLoadingErrorViewState
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.Event
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.State
import app.k9mail.feature.account.server.settings.ui.incoming.content.incomingFormItems
@ -39,19 +41,25 @@ internal fun IncomingServerSettingsContent(
.fillMaxWidth()
.then(modifier),
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.imePadding(),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
ContentLoadingErrorView(
state = rememberContentLoadingErrorViewState(state = state),
loading = { /* no-op */ },
error = { /* no-op */ },
) {
incomingFormItems(
mode = mode,
state = state,
onEvent = onEvent,
resources = resources,
)
LazyColumn(
modifier = Modifier
.fillMaxSize()
.imePadding(),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
) {
incomingFormItems(
mode = mode,
state = state,
onEvent = onEvent,
resources = resources,
)
}
}
}
}

View file

@ -9,6 +9,7 @@ import app.k9mail.feature.account.common.domain.entity.toDefaultPort
import app.k9mail.feature.account.common.domain.input.NumberInputField
import app.k9mail.feature.account.common.domain.input.StringInputField
import app.k9mail.feature.account.common.ui.WithInteractionMode
import app.k9mail.feature.account.common.ui.loadingerror.LoadingErrorState
interface IncomingServerSettingsContract {
@ -29,7 +30,10 @@ interface IncomingServerSettingsContract {
val imapPrefix: StringInputField = StringInputField(),
val imapUseCompression: Boolean = true,
val imapSendClientId: Boolean = true,
)
override val isLoading: Boolean = true,
override val error: Error? = null,
) : LoadingErrorState<Error>
sealed interface Event {
data class ProtocolTypeChanged(val protocolType: IncomingProtocolType) : Event
@ -45,15 +49,15 @@ interface IncomingServerSettingsContract {
data class ImapUseCompressionChanged(val useCompression: Boolean) : Event
data class ImapSendClientIdChanged(val sendClientId: Boolean) : Event
object LoadAccountState : Event
data object LoadAccountState : Event
object OnNextClicked : Event
object OnBackClicked : Event
data object OnNextClicked : Event
data object OnBackClicked : Event
}
sealed interface Effect {
object NavigateNext : Effect
object NavigateBack : Effect
data object NavigateNext : Effect
data object NavigateBack : Effect
}
interface Validator {

View file

@ -17,7 +17,10 @@ import com.fsck.k9.mail.store.imap.ImapStoreSettings.isUseCompression
import com.fsck.k9.mail.store.imap.ImapStoreSettings.pathPrefix
fun AccountState.toIncomingServerSettingsState() = incomingServerSettings?.toIncomingServerSettingsState()
?: State(username = StringInputField(value = emailAddress ?: ""))
?: State(
username = StringInputField(value = emailAddress ?: ""),
isLoading = false,
)
private fun ServerSettings.toIncomingServerSettingsState(): State {
return State(
@ -33,6 +36,9 @@ private fun ServerSettings.toIncomingServerSettingsState(): State {
imapPrefix = StringInputField(value = pathPrefix ?: ""),
imapUseCompression = isUseCompression,
imapSendClientId = isSendClientId,
isLoading = false,
error = null,
)
}

View file

@ -14,10 +14,10 @@ import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSett
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract.ViewModel
open class IncomingServerSettingsViewModel(
initialState: State = State(),
override val mode: InteractionMode,
private val validator: Validator,
private val accountStateRepository: AccountDomainContract.AccountStateRepository,
initialState: State = State(),
) : BaseViewModel<State, Event, Effect>(initialState = initialState), ViewModel {
@Suppress("CyclomaticComplexMethod")

View file

@ -13,11 +13,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import app.k9mail.core.ui.compose.common.PreviewDevices
import app.k9mail.core.ui.compose.designsystem.molecule.ContentLoadingErrorView
import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer
import app.k9mail.core.ui.compose.theme.K9Theme
import app.k9mail.core.ui.compose.theme.MainTheme
import app.k9mail.core.ui.compose.theme.ThunderbirdTheme
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.common.ui.loadingerror.rememberContentLoadingErrorViewState
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.Event
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.State
import app.k9mail.feature.account.server.settings.ui.outgoing.content.outgoingFormItems
@ -39,19 +41,25 @@ internal fun OutgoingServerSettingsContent(
.fillMaxWidth()
.then(modifier),
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.imePadding(),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
ContentLoadingErrorView(
state = rememberContentLoadingErrorViewState(state = state),
loading = { /* no-op */ },
error = { /* no-op */ },
) {
outgoingFormItems(
mode = mode,
state = state,
onEvent = onEvent,
resources = resources,
)
LazyColumn(
modifier = Modifier
.fillMaxSize()
.imePadding(),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
) {
outgoingFormItems(
mode = mode,
state = state,
onEvent = onEvent,
resources = resources,
)
}
}
}
}

View file

@ -8,6 +8,7 @@ import app.k9mail.feature.account.common.domain.entity.toSmtpDefaultPort
import app.k9mail.feature.account.common.domain.input.NumberInputField
import app.k9mail.feature.account.common.domain.input.StringInputField
import app.k9mail.feature.account.common.ui.WithInteractionMode
import app.k9mail.feature.account.common.ui.loadingerror.LoadingErrorState
interface OutgoingServerSettingsContract {
@ -21,7 +22,10 @@ interface OutgoingServerSettingsContract {
val username: StringInputField = StringInputField(),
val password: StringInputField = StringInputField(),
val clientCertificateAlias: String? = null,
)
override val isLoading: Boolean = true,
override val error: Error? = null,
) : LoadingErrorState<Error>
sealed interface Event {
data class ServerChanged(val server: String) : Event
@ -32,15 +36,15 @@ interface OutgoingServerSettingsContract {
data class PasswordChanged(val password: String) : Event
data class ClientCertificateChanged(val clientCertificateAlias: String?) : Event
object LoadAccountState : Event
data object LoadAccountState : Event
object OnNextClicked : Event
object OnBackClicked : Event
data object OnNextClicked : Event
data object OnBackClicked : Event
}
sealed interface Effect {
object NavigateNext : Effect
object NavigateBack : Effect
data object NavigateNext : Effect
data object NavigateBack : Effect
}
interface Validator {

View file

@ -17,6 +17,8 @@ fun AccountState.toOutgoingServerSettingsState(): State {
?: State(
username = StringInputField(value = emailAddress ?: ""),
password = StringInputField(value = password),
isLoading = false,
)
}
@ -32,6 +34,9 @@ private fun ServerSettings.toOutgoingServerSettingsState(password: String): Stat
authenticationType = authenticationType.toAuthenticationType(),
username = StringInputField(value = username),
password = StringInputField(value = password),
isLoading = false,
error = null,
)
}

View file

@ -13,10 +13,10 @@ import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSett
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract.ViewModel
open class OutgoingServerSettingsViewModel(
initialState: State = State(),
override val mode: InteractionMode,
private val validator: Validator,
private val accountStateRepository: AccountDomainContract.AccountStateRepository,
initialState: State = State(),
) : BaseViewModel<State, Event, Effect>(initialState = initialState), ViewModel {
override fun event(event: Event) {

View file

@ -26,7 +26,12 @@ class IncomingServerSettingsStateMapperKtTest {
val result = accountState.toIncomingServerSettingsState()
assertThat(result).isEqualTo(State(username = StringInputField(value = "test@example.com")))
assertThat(result).isEqualTo(
State(
username = StringInputField(value = "test@example.com"),
isLoading = false,
),
)
}
@Test
@ -37,7 +42,7 @@ class IncomingServerSettingsStateMapperKtTest {
val result = serverSettings.toIncomingServerSettingsState()
assertThat(result).isEqualTo(INCOMING_IMAP_STATE)
assertThat(result).isEqualTo(INCOMING_IMAP_STATE.copy(isLoading = false))
}
@Test

View file

@ -30,6 +30,9 @@ class IncomingServerSettingsStateTest {
imapAutodetectNamespaceEnabled = true,
imapUseCompression = true,
imapSendClientId = true,
isLoading = true,
error = null,
),
)
}

View file

@ -86,6 +86,8 @@ class IncomingServerSettingsViewModelTest {
imapPrefix = StringInputField(value = ""),
imapUseCompression = true,
imapSendClientId = true,
isLoading = false,
),
)
}

View file

@ -24,7 +24,12 @@ class OutgoingServerSettingsStateMapperKtTest {
val result = accountState.toOutgoingServerSettingsState()
assertThat(result).isEqualTo(State(username = StringInputField(value = "test@example.com")))
assertThat(result).isEqualTo(
State(
username = StringInputField(value = "test@example.com"),
isLoading = false,
),
)
}
@Test
@ -41,6 +46,7 @@ class OutgoingServerSettingsStateMapperKtTest {
State(
username = StringInputField(value = "test@domain.example"),
password = StringInputField(value = INCOMING_SERVER_PASSWORD),
isLoading = false,
),
)
}
@ -53,7 +59,7 @@ class OutgoingServerSettingsStateMapperKtTest {
val result = accountState.toOutgoingServerSettingsState()
assertThat(result).isEqualTo(OUTGOING_STATE)
assertThat(result).isEqualTo(OUTGOING_STATE.copy(isLoading = false))
}
@Test
@ -68,6 +74,7 @@ class OutgoingServerSettingsStateMapperKtTest {
assertThat(result).isEqualTo(
OUTGOING_STATE.copy(
password = StringInputField(value = INCOMING_SERVER_PASSWORD),
isLoading = false,
),
)
}
@ -83,6 +90,7 @@ class OutgoingServerSettingsStateMapperKtTest {
assertThat(result).isEqualTo(
OUTGOING_STATE.copy(
password = StringInputField(value = ""),
isLoading = false,
),
)
}

View file

@ -25,6 +25,9 @@ class OutgoingServerSettingsStateTest {
username = StringInputField(),
password = StringInputField(),
clientCertificateAlias = null,
isLoading = true,
error = null,
),
)
}

View file

@ -73,6 +73,8 @@ class OutgoingServerSettingsViewModelTest {
authenticationType = AuthenticationType.PasswordCleartext,
username = StringInputField(value = "username"),
password = StringInputField(value = "password"),
isLoading = false,
),
)
}