Skip to content

Commit

Permalink
Merge pull request #7245 from thundernest/add_server_settings_interac…
Browse files Browse the repository at this point in the history
…tion_mode

Add interaction mode to server settings
  • Loading branch information
wmontwe authored Oct 13, 2023
2 parents 61b76c3 + e898296 commit 7571469
Show file tree
Hide file tree
Showing 26 changed files with 450 additions and 267 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package app.k9mail.feature.account.common.domain.entity

/**
* Enum representing the mode a user is interacting with an account or setting.
*/
enum class InteractionMode {
Create,
Edit,
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.k9mail.core.ui.compose.common.DevicePreviews
import app.k9mail.core.ui.compose.designsystem.organism.TopAppBar
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.core.ui.compose.theme.PreviewWithThemes
import app.k9mail.feature.account.common.R

/**
* Top app bar for the account screens.
*/
@Composable
fun AccountTopAppBar(
title: String,
Expand All @@ -28,18 +30,8 @@ fun AccountTopAppBar(

@DevicePreviews
@Composable
internal fun AccountTopAppBarK9Preview() {
K9Theme {
AccountTopAppBar(
title = "Title",
)
}
}

@DevicePreviews
@Composable
internal fun AccountTopAppBarThunderbirdPreview() {
ThunderbirdTheme {
internal fun AccountTopAppBarPreview() {
PreviewWithThemes {
AccountTopAppBar(
title = "Title",
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package app.k9mail.feature.account.common.ui

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import app.k9mail.core.ui.compose.common.DevicePreviews
import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonIcon
import app.k9mail.core.ui.compose.designsystem.organism.TopAppBar
import app.k9mail.core.ui.compose.theme.Icons
import app.k9mail.core.ui.compose.theme.MainTheme
import app.k9mail.core.ui.compose.theme.PreviewWithThemes
import app.k9mail.feature.account.common.R

/**
* Top app bar for the account screens with a back button.
*/
@Composable
fun AccountTopAppBarWithBackButton(
title: String,
modifier: Modifier = Modifier,
onBackClicked: () -> Unit,
) {
TopAppBar(
title = title,
modifier = modifier,
subtitle = stringResource(id = R.string.account_common_title),
titleContentPadding = PaddingValues(
start = MainTheme.spacings.default,
),
navigationIcon = {
ButtonIcon(
onClick = onBackClicked,
imageVector = Icons.Outlined.arrowBack,
)
},
)
}

@DevicePreviews
@Composable
internal fun AccountTopAppBarWithBackButtonPreview() {
PreviewWithThemes {
AccountTopAppBarWithBackButton(
title = "Title",
onBackClicked = {},
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package app.k9mail.feature.account.common.ui

import app.k9mail.feature.account.common.domain.entity.InteractionMode

/**
* Interface for screens that can be used in different interaction modes.
*/
interface WithInteractionMode {
val mode: InteractionMode
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package app.k9mail.feature.account.edit.ui

import androidx.lifecycle.viewModelScope
import app.k9mail.feature.account.common.domain.AccountDomainContract
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.edit.domain.AccountEditDomainContract
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsViewModel
Expand All @@ -15,6 +16,7 @@ class EditIncomingServerSettingsViewModel(
accountStateRepository: AccountDomainContract.AccountStateRepository,
initialState: IncomingServerSettingsContract.State = IncomingServerSettingsContract.State(),
) : IncomingServerSettingsViewModel(
mode = InteractionMode.Edit,
validator = validator,
accountStateRepository = accountStateRepository,
initialState = initialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package app.k9mail.feature.account.edit.ui

import androidx.lifecycle.viewModelScope
import app.k9mail.feature.account.common.domain.AccountDomainContract
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.edit.domain.AccountEditDomainContract
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsViewModel
Expand All @@ -15,6 +16,7 @@ class EditOutgoingServerSettingsViewModel(
accountStateRepository: AccountDomainContract.AccountStateRepository,
initialState: OutgoingServerSettingsContract.State = OutgoingServerSettingsContract.State(),
) : OutgoingServerSettingsViewModel(
mode = InteractionMode.Edit,
validator = validator,
accountStateRepository = accountStateRepository,
initialState = initialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import app.k9mail.core.common.oauth.OAuthConfigurationFactory
import app.k9mail.feature.account.common.AccountCommonExternalContract
import app.k9mail.feature.account.common.domain.entity.AccountState
import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.server.certificate.ui.ServerCertificateErrorContract
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract
import app.k9mail.feature.account.server.settings.ui.outgoing.OutgoingServerSettingsContract
Expand Down Expand Up @@ -58,6 +59,7 @@ class AccountEditModuleKtTest : KoinTest {
ServerCertificateErrorContract.State::class,
IncomingServerSettingsContract.State::class,
OutgoingServerSettingsContract.State::class,
InteractionMode::class,
),
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package app.k9mail.feature.account.server.settings

import app.k9mail.feature.account.common.domain.entity.InteractionMode
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsContract
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsValidator
import app.k9mail.feature.account.server.settings.ui.incoming.IncomingServerSettingsViewModel
Expand All @@ -16,13 +17,15 @@ val featureAccountServerSettingsModule: Module = module {

viewModel {
IncomingServerSettingsViewModel(
mode = InteractionMode.Create,
validator = get(),
accountStateRepository = get(),
)
}

viewModel {
OutgoingServerSettingsViewModel(
mode = InteractionMode.Create,
validator = get(),
accountStateRepository = get(),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,29 @@ package app.k9mail.feature.account.server.settings.ui.incoming

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import app.k9mail.core.ui.compose.common.DevicePreviews
import app.k9mail.core.ui.compose.designsystem.molecule.input.CheckboxInput
import app.k9mail.core.ui.compose.designsystem.molecule.input.NumberInput
import app.k9mail.core.ui.compose.designsystem.molecule.input.PasswordInput
import app.k9mail.core.ui.compose.designsystem.molecule.input.SelectInput
import app.k9mail.core.ui.compose.designsystem.molecule.input.TextInput
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.ConnectionSecurity
import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType
import app.k9mail.feature.account.common.ui.item.defaultItemPadding
import app.k9mail.feature.account.server.settings.R
import app.k9mail.feature.account.server.settings.ui.common.ClientCertificateInput
import app.k9mail.feature.account.server.settings.ui.common.mapper.toResourceString
import app.k9mail.feature.account.common.domain.entity.InteractionMode
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

@Suppress("LongMethod")
@Composable
internal fun IncomingServerSettingsContent(
mode: InteractionMode,
state: State,
onEvent: (Event) -> Unit,
contentPadding: PaddingValues,
Expand All @@ -58,139 +46,12 @@ internal fun IncomingServerSettingsContent(
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(MainTheme.spacings.default),
) {
item {
Spacer(modifier = Modifier.requiredHeight(MainTheme.sizes.smaller))
}

item {
SelectInput(
options = IncomingProtocolType.all(),
selectedOption = state.protocolType,
onOptionChange = { onEvent(Event.ProtocolTypeChanged(it)) },
label = stringResource(id = R.string.account_server_settings_protocol_type_label),
contentPadding = defaultItemPadding(),
)
}

item {
TextInput(
text = state.server.value,
errorMessage = state.server.error?.toResourceString(resources),
onTextChange = { onEvent(Event.ServerChanged(it)) },
label = stringResource(id = R.string.account_server_settings_server_label),
contentPadding = defaultItemPadding(),
)
}

item {
SelectInput(
options = ConnectionSecurity.all(),
optionToStringTransformation = { it.toResourceString(resources) },
selectedOption = state.security,
onOptionChange = { onEvent(Event.SecurityChanged(it)) },
label = stringResource(id = R.string.account_server_settings_security_label),
contentPadding = defaultItemPadding(),
)
}

item {
NumberInput(
value = state.port.value,
errorMessage = state.port.error?.toResourceString(resources),
onValueChange = { onEvent(Event.PortChanged(it)) },
label = stringResource(id = R.string.account_server_settings_port_label),
contentPadding = defaultItemPadding(),
)
}

item {
SelectInput(
options = state.allowedAuthenticationTypes,
optionToStringTransformation = { it.toResourceString(resources) },
selectedOption = state.authenticationType,
onOptionChange = { onEvent(Event.AuthenticationTypeChanged(it)) },
label = stringResource(id = R.string.account_server_settings_authentication_label),
contentPadding = defaultItemPadding(),
)
}

item {
TextInput(
text = state.username.value,
errorMessage = state.username.error?.toResourceString(resources),
onTextChange = { onEvent(Event.UsernameChanged(it)) },
label = stringResource(id = R.string.account_server_settings_username_label),
contentPadding = defaultItemPadding(),
)
}

if (state.isPasswordFieldVisible) {
item {
PasswordInput(
password = state.password.value,
errorMessage = state.password.error?.toResourceString(resources),
onPasswordChange = { onEvent(Event.PasswordChanged(it)) },
contentPadding = defaultItemPadding(),
)
}
}

item {
ClientCertificateInput(
alias = state.clientCertificateAlias,
onValueChange = { onEvent(Event.ClientCertificateChanged(it)) },
label = stringResource(id = R.string.account_server_settings_client_certificate_label),
contentPadding = defaultItemPadding(),
)
}

if (state.protocolType == IncomingProtocolType.IMAP) {
item {
CheckboxInput(
text = stringResource(id = R.string.account_server_settings_incoming_imap_namespace_label),
checked = state.imapAutodetectNamespaceEnabled,
onCheckedChange = { onEvent(Event.ImapAutoDetectNamespaceChanged(it)) },
contentPadding = defaultItemPadding(),
)
}

item {
if (state.imapAutodetectNamespaceEnabled) {
TextInput(
onTextChange = {},
label = stringResource(id = R.string.account_server_settings_incoming_imap_prefix_label),
contentPadding = defaultItemPadding(),
isEnabled = false,
)
} else {
TextInput(
text = state.imapPrefix.value,
errorMessage = state.imapPrefix.error?.toResourceString(resources),
onTextChange = { onEvent(Event.ImapPrefixChanged(it)) },
label = stringResource(id = R.string.account_server_settings_incoming_imap_prefix_label),
contentPadding = defaultItemPadding(),
)
}
}

item {
CheckboxInput(
text = stringResource(id = R.string.account_server_settings_incoming_imap_compression_label),
checked = state.imapUseCompression,
onCheckedChange = { onEvent(Event.ImapUseCompressionChanged(it)) },
contentPadding = defaultItemPadding(),
)
}

item {
CheckboxInput(
text = stringResource(R.string.account_server_settings_incoming_imap_send_client_id_label),
checked = state.imapSendClientId,
onCheckedChange = { onEvent(Event.ImapSendClientIdChanged(it)) },
contentPadding = defaultItemPadding(),
)
}
}
incomingFormItems(
mode = mode,
state = state,
onEvent = onEvent,
resources = resources,
)
}
}
}
Expand All @@ -200,6 +61,7 @@ internal fun IncomingServerSettingsContent(
internal fun IncomingServerSettingsContentK9Preview() {
K9Theme {
IncomingServerSettingsContent(
mode = InteractionMode.Create,
onEvent = { },
state = State(),
contentPadding = PaddingValues(),
Expand All @@ -212,6 +74,7 @@ internal fun IncomingServerSettingsContentK9Preview() {
internal fun IncomingServerSettingsContentThunderbirdPreview() {
ThunderbirdTheme {
IncomingServerSettingsContent(
mode = InteractionMode.Create,
onEvent = { },
state = State(),
contentPadding = PaddingValues(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import app.k9mail.feature.account.common.domain.entity.IncomingProtocolType
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

interface IncomingServerSettingsContract {

interface ViewModel : UnidirectionalViewModel<State, Event, Effect>
interface ViewModel : UnidirectionalViewModel<State, Event, Effect>, WithInteractionMode

data class State(
val protocolType: IncomingProtocolType = IncomingProtocolType.DEFAULT,
Expand Down
Loading

0 comments on commit 7571469

Please sign in to comment.