From fa803526d2410e1615c49f4761168c8f73c171da Mon Sep 17 00:00:00 2001 From: cketti Date: Wed, 18 May 2022 17:46:21 +0200 Subject: [PATCH] Convert `AccountSetupBasics` to Kotlin --- .../k9/activity/setup/AccountSetupBasics.kt | 532 ++++++++---------- 1 file changed, 237 insertions(+), 295 deletions(-) diff --git a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt index aa1ca7f46..2913871e6 100644 --- a/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt +++ b/app/ui/legacy/src/main/java/com/fsck/k9/activity/setup/AccountSetupBasics.kt @@ -1,359 +1,301 @@ -package com.fsck.k9.activity.setup; +package com.fsck.k9.activity.setup - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; - -import com.fsck.k9.Account; -import com.fsck.k9.Core; -import com.fsck.k9.DI; -import com.fsck.k9.EmailAddressValidator; -import com.fsck.k9.Preferences; -import com.fsck.k9.account.AccountCreator; -import com.fsck.k9.ui.base.K9Activity; -import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection; -import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings; -import com.fsck.k9.autodiscovery.api.DiscoveryResults; -import com.fsck.k9.autodiscovery.api.DiscoveryTarget; -import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery; -import com.fsck.k9.helper.Utility; -import com.fsck.k9.mail.AuthType; -import com.fsck.k9.mail.ServerSettings; -import com.fsck.k9.mailstore.SpecialLocalFoldersCreator; -import com.fsck.k9.ui.R; -import com.fsck.k9.ui.ConnectionSettings; -import com.fsck.k9.ui.settings.ExtraAccountDiscovery; -import com.fsck.k9.view.ClientCertificateSpinner; -import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener; -import com.google.android.material.textfield.TextInputEditText; -import timber.log.Timber; +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.text.Editable +import android.view.ViewGroup +import android.widget.Button +import android.widget.CheckBox +import androidx.core.view.isVisible +import com.fsck.k9.Account +import com.fsck.k9.Core +import com.fsck.k9.EmailAddressValidator +import com.fsck.k9.Preferences +import com.fsck.k9.account.AccountCreator +import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection +import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings +import com.fsck.k9.autodiscovery.api.DiscoveryTarget +import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery +import com.fsck.k9.helper.SimpleTextWatcher +import com.fsck.k9.helper.Utility.requiredFieldValid +import com.fsck.k9.mail.AuthType +import com.fsck.k9.mail.ServerSettings +import com.fsck.k9.mailstore.SpecialLocalFoldersCreator +import com.fsck.k9.ui.ConnectionSettings +import com.fsck.k9.ui.R +import com.fsck.k9.ui.base.K9Activity +import com.fsck.k9.ui.settings.ExtraAccountDiscovery +import com.fsck.k9.view.ClientCertificateSpinner +import com.google.android.material.textfield.TextInputEditText +import org.koin.android.ext.android.inject /** * Prompts the user for the email address and password. - * Attempts to lookup default settings for the domain the user specified. If the - * domain is known the settings are handed off to the AccountSetupCheckSettings - * activity. If no settings are found the settings are handed off to the - * AccountSetupAccountType activity. + * + * Attempts to lookup default settings for the domain the user specified. If the domain is known, the settings are + * handed off to the [AccountSetupCheckSettings] activity. If no settings are found, the settings are handed off to the + * [AccountSetupAccountType] activity. */ -public class AccountSetupBasics extends K9Activity - implements OnClickListener, TextWatcher, OnCheckedChangeListener, OnClientCertificateChangedListener { - private final static String EXTRA_ACCOUNT = "com.fsck.k9.AccountSetupBasics.account"; - private final static String STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming"; +class AccountSetupBasics : K9Activity() { + private val providersXmlDiscovery: ProvidersXmlDiscovery by inject() + private val accountCreator: AccountCreator by inject() + private val localFoldersCreator: SpecialLocalFoldersCreator by inject() + private val preferences: Preferences by inject() + private val emailValidator: EmailAddressValidator by inject() + private lateinit var emailView: TextInputEditText + private lateinit var passwordView: TextInputEditText + private lateinit var clientCertificateCheckBox: CheckBox + private lateinit var clientCertificateSpinner: ClientCertificateSpinner + private lateinit var nextButton: Button + private lateinit var manualSetupButton: Button + private lateinit var allowClientCertificateView: ViewGroup - private final ProvidersXmlDiscovery providersXmlDiscovery = DI.get(ProvidersXmlDiscovery.class); - private final AccountCreator accountCreator = DI.get(AccountCreator.class); - private final SpecialLocalFoldersCreator localFoldersCreator = DI.get(SpecialLocalFoldersCreator.class); + private var account: Account? = null + private var checkedIncoming = false - private TextInputEditText mEmailView; - private TextInputEditText mPasswordView; - private CheckBox mClientCertificateCheckBox; - private ClientCertificateSpinner mClientCertificateSpinner; - private Button mNextButton; - private Button mManualSetupButton; - private Account mAccount; - private ViewGroup mAllowClientCertificateView; + public override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setLayout(R.layout.account_setup_basics) + setTitle(R.string.account_setup_basics_title) - private EmailAddressValidator mEmailValidator = new EmailAddressValidator(); - private boolean mCheckedIncoming = false; + emailView = findViewById(R.id.account_email) + passwordView = findViewById(R.id.account_password) + clientCertificateCheckBox = findViewById(R.id.account_client_certificate) + clientCertificateSpinner = findViewById(R.id.account_client_certificate_spinner) + allowClientCertificateView = findViewById(R.id.account_allow_client_certificate) + nextButton = findViewById(R.id.next) + manualSetupButton = findViewById(R.id.manual_setup) - public static void actionNewAccount(Context context) { - Intent i = new Intent(context, AccountSetupBasics.class); - context.startActivity(i); + manualSetupButton.setOnClickListener { onManualSetup() } + nextButton.setOnClickListener { onNext() } } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setLayout(R.layout.account_setup_basics); - setTitle(R.string.account_setup_basics_title); - mEmailView = findViewById(R.id.account_email); - mPasswordView = findViewById(R.id.account_password); - mClientCertificateCheckBox = findViewById(R.id.account_client_certificate); - mClientCertificateSpinner = findViewById(R.id.account_client_certificate_spinner); - mAllowClientCertificateView = findViewById(R.id.account_allow_client_certificate); - - mNextButton = findViewById(R.id.next); - mManualSetupButton = findViewById(R.id.manual_setup); - mNextButton.setOnClickListener(this); - mManualSetupButton.setOnClickListener(this); - } - - private void initializeViewListeners() { - mEmailView.addTextChangedListener(this); - mPasswordView.addTextChangedListener(this); - mClientCertificateCheckBox.setOnCheckedChangeListener(this); - mClientCertificateSpinner.setOnClientCertificateChangedListener(this); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mAccount != null) { - outState.putString(EXTRA_ACCOUNT, mAccount.getUuid()); - } - outState.putBoolean(STATE_KEY_CHECKED_INCOMING, mCheckedIncoming); - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - - if (savedInstanceState.containsKey(EXTRA_ACCOUNT)) { - String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT); - mAccount = Preferences.getPreferences(this).getAccount(accountUuid); - } - - mCheckedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING); - - updateViewVisibility(mClientCertificateCheckBox.isChecked()); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) /* - * We wait until now to initialize the listeners because we didn't want - * the OnCheckedChangeListener active while the - * mClientCertificateCheckBox state was being restored because it could - * trigger the pop-up of a ClientCertificateSpinner.chooseCertificate() - * dialog. + * We wait until now to initialize the listeners because we didn't want the OnCheckedChangeListener active + * while the clientCertificateCheckBox state was being restored because it could trigger the pop-up of a + * ClientCertificateSpinner.chooseCertificate() dialog. */ - initializeViewListeners(); - validateFields(); + initializeViewListeners() + validateFields() } - public void afterTextChanged(Editable s) { - validateFields(); - } + private fun initializeViewListeners() { + val textWatcher = object : SimpleTextWatcher() { + override fun afterTextChanged(s: Editable) { + validateFields() + } + } - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - } + emailView.addTextChangedListener(textWatcher) + passwordView.addTextChangedListener(textWatcher) - public void onTextChanged(CharSequence s, int start, int before, int count) { - } + clientCertificateCheckBox.setOnCheckedChangeListener { _, isChecked -> + updateViewVisibility(isChecked) + validateFields() - @Override - public void onClientCertificateChanged(String alias) { - validateFields(); - } + // Have the user select the client certificate if not already selected + if (isChecked && clientCertificateSpinner.alias == null) { + clientCertificateSpinner.chooseCertificate() + } + } - /** - * Called when checking the client certificate CheckBox - */ - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - updateViewVisibility(isChecked); - validateFields(); - - // Have the user select the client certificate if not already selected - if ((isChecked) && (mClientCertificateSpinner.getAlias() == null)) { - mClientCertificateSpinner.chooseCertificate(); + clientCertificateSpinner.setOnClientCertificateChangedListener { + validateFields() } } - private void updateViewVisibility(boolean usingCertificates) { - if (usingCertificates) { - // show client certificate spinner - mAllowClientCertificateView.setVisibility(View.VISIBLE); - } else { - // hide client certificate spinner - mAllowClientCertificateView.setVisibility(View.GONE); - } + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + + outState.putString(EXTRA_ACCOUNT, account?.uuid) + outState.putBoolean(STATE_KEY_CHECKED_INCOMING, checkedIncoming) } - private void validateFields() { - boolean clientCertificateChecked = mClientCertificateCheckBox.isChecked(); - String clientCertificateAlias = mClientCertificateSpinner.getAlias(); - String email = mEmailView.getText().toString(); + override fun onRestoreInstanceState(savedInstanceState: Bundle) { + super.onRestoreInstanceState(savedInstanceState) - boolean valid = Utility.requiredFieldValid(mEmailView) - && ((!clientCertificateChecked && Utility.requiredFieldValid(mPasswordView)) - || (clientCertificateChecked && clientCertificateAlias != null)) - && mEmailValidator.isValidAddressOnly(email); - - mNextButton.setEnabled(valid); - mNextButton.setFocusable(valid); - mManualSetupButton.setEnabled(valid); - /* - * Dim the next button's icon to 50% if the button is disabled. - * TODO this can probably be done with a stateful drawable. Check into it. - * android:state_enabled - */ - Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128); - } - - private String getOwnerName() { - String name = null; - try { - name = getDefaultSenderName(); - } catch (Exception e) { - Timber.e(e, "Could not get default account name"); + val accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT) + if (accountUuid != null) { + account = preferences.getAccount(accountUuid) } - if (name == null) { - name = ""; - } - return name; + checkedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING) + updateViewVisibility(clientCertificateCheckBox.isChecked) } - private String getDefaultSenderName() { - String name = null; - Account account = Preferences.getPreferences(this).getDefaultAccount(); - if (account != null) { - name = account.getSenderName(); - } - return name; + private fun updateViewVisibility(usingCertificates: Boolean) { + allowClientCertificateView.isVisible = usingCertificates } - private void finishAutoSetup(ConnectionSettings connectionSettings) { - String email = mEmailView.getText().toString(); - String password = mPasswordView.getText().toString(); + private fun validateFields() { + val email = emailView.text?.toString().orEmpty() + val valid = requiredFieldValid(emailView) && emailValidator.isValidAddressOnly(email) && isPasswordFieldValid() - if (mAccount == null) { - mAccount = Preferences.getPreferences(this).newAccount(); - mAccount.setChipColor(accountCreator.pickColor()); - } - - mAccount.setSenderName(getOwnerName()); - mAccount.setEmail(email); - - ServerSettings incomingServerSettings = connectionSettings.getIncoming().newPassword(password); - mAccount.setIncomingServerSettings(incomingServerSettings); - - ServerSettings outgoingServerSettings = connectionSettings.getOutgoing().newPassword(password); - mAccount.setOutgoingServerSettings(outgoingServerSettings); - - mAccount.setDeletePolicy(accountCreator.getDefaultDeletePolicy(incomingServerSettings.type)); - - localFoldersCreator.createSpecialLocalFolders(mAccount); - - // Check incoming here. Then check outgoing in onActivityResult() - AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING); + nextButton.isEnabled = valid + nextButton.isFocusable = valid + manualSetupButton.isEnabled = valid } - private ConnectionSettings providersXmlDiscoveryDiscover(String email, DiscoveryTarget discoveryTarget) { - DiscoveryResults discoveryResults = providersXmlDiscovery.discover(email, DiscoveryTarget.INCOMING_AND_OUTGOING); - if (discoveryResults == null || (discoveryResults.getIncoming().size() < 1 || discoveryResults.getOutgoing().size() < 1)) { - return null; - } - DiscoveredServerSettings incoming = discoveryResults.getIncoming().get(0); - DiscoveredServerSettings outgoing = discoveryResults.getOutgoing().get(0); - return new ConnectionSettings(new ServerSettings( - incoming.getProtocol(), - incoming.getHost(), - incoming.getPort(), - incoming.getSecurity(), - incoming.getAuthType(), - incoming.getUsername(), - null, - null - ), new ServerSettings( - outgoing.getProtocol(), - outgoing.getHost(), - outgoing.getPort(), - outgoing.getSecurity(), - outgoing.getAuthType(), - outgoing.getUsername(), - null, - null - )); + private fun isPasswordFieldValid(): Boolean { + val clientCertificateChecked = clientCertificateCheckBox.isChecked + val clientCertificateAlias = clientCertificateSpinner.alias + + return !clientCertificateChecked && requiredFieldValid(passwordView) || + clientCertificateChecked && clientCertificateAlias != null } - private void onNext() { - if (mClientCertificateCheckBox.isChecked()) { - + private fun onNext() { + if (clientCertificateCheckBox.isChecked) { // Auto-setup doesn't support client certificates. - onManualSetup(); - return; + onManualSetup() + return } - String email = mEmailView.getText().toString(); + val email = emailView.text?.toString() ?: error("Email missing") - ConnectionSettings extraConnectionSettings = ExtraAccountDiscovery.discover(email); + val extraConnectionSettings = ExtraAccountDiscovery.discover(email) if (extraConnectionSettings != null) { - finishAutoSetup(extraConnectionSettings); - return; + finishAutoSetup(extraConnectionSettings) + return } - ConnectionSettings connectionSettings = providersXmlDiscoveryDiscover(email, DiscoveryTarget.INCOMING_AND_OUTGOING); + val connectionSettings = providersXmlDiscoveryDiscover(email) if (connectionSettings != null) { - finishAutoSetup(connectionSettings); + finishAutoSetup(connectionSettings) } else { // We don't have default settings for this account, start the manual setup process. - onManualSetup(); + onManualSetup() } } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { + private fun finishAutoSetup(connectionSettings: ConnectionSettings) { + val email = emailView.text?.toString() ?: error("Email missing") + val password = passwordView.text?.toString() + + val account = initAccount(email) + + val incomingServerSettings = connectionSettings.incoming.newPassword(password) + account.incomingServerSettings = incomingServerSettings + + val outgoingServerSettings = connectionSettings.outgoing.newPassword(password) + account.outgoingServerSettings = outgoingServerSettings + + account.deletePolicy = accountCreator.getDefaultDeletePolicy(incomingServerSettings.type) + + localFoldersCreator.createSpecialLocalFolders(account) + + // Check incoming here. Then check outgoing in onActivityResult() + AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.INCOMING) + } + + private fun onManualSetup() { + val email = emailView.text?.toString() ?: error("Email missing") + var password: String? = passwordView.text?.toString() + var clientCertificateAlias: String? = null + var authenticationType: AuthType = AuthType.PLAIN + + if (clientCertificateCheckBox.isChecked) { + clientCertificateAlias = clientCertificateSpinner.alias + if (password.isNullOrEmpty()) { + authenticationType = AuthType.EXTERNAL + password = null + } + } + + val account = initAccount(email) + + val initialAccountSettings = InitialAccountSettings( + authenticationType = authenticationType, + email = email, + password = password, + clientCertificateAlias = clientCertificateAlias + ) + + AccountSetupAccountType.actionSelectAccountType(this, account, makeDefault = false, initialAccountSettings) + } + + private fun initAccount(email: String): Account { + val account = this.account ?: createAccount().also { this.account = it } + + account.senderName = getOwnerName() + account.email = email + return account + } + + private fun createAccount(): Account { + return preferences.newAccount().apply { + chipColor = accountCreator.pickColor() + } + } + + private fun getOwnerName(): String { + return preferences.defaultAccount?.senderName ?: "" + } + + private fun providersXmlDiscoveryDiscover(email: String): ConnectionSettings? { + val discoveryResults = providersXmlDiscovery.discover(email, DiscoveryTarget.INCOMING_AND_OUTGOING) + if (discoveryResults == null || discoveryResults.incoming.isEmpty() || discoveryResults.outgoing.isEmpty()) { + return null + } + + val incomingServerSettings = discoveryResults.incoming.first().toServerSettings() ?: return null + val outgoingServerSettings = discoveryResults.outgoing.first().toServerSettings() ?: return null + + return ConnectionSettings(incomingServerSettings, outgoingServerSettings) + } + + public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode != AccountSetupCheckSettings.ACTIVITY_REQUEST_CODE) { - super.onActivityResult(requestCode, resultCode, data); - return; + super.onActivityResult(requestCode, resultCode, data) + return } if (resultCode == RESULT_OK) { - if (!mCheckedIncoming) { - //We've successfully checked incoming. Now check outgoing. - mCheckedIncoming = true; - AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING); + if (!checkedIncoming) { + // We've successfully checked incoming. Now check outgoing. + checkedIncoming = true + AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.OUTGOING) } else { - //We've successfully checked outgoing as well. - mAccount.setName(mAccount.getEmail()); - Preferences.getPreferences(this).saveAccount(mAccount); - Core.setServicesEnabled(this); - AccountSetupNames.actionSetNames(this, mAccount); + // We've successfully checked outgoing as well. + val account = this.account ?: error("Account instance missing") + + preferences.saveAccount(account) + Core.setServicesEnabled(applicationContext) + + AccountSetupNames.actionSetNames(this, account) } } } - private void onManualSetup() { - String email = mEmailView.getText().toString(); + companion object { + private const val EXTRA_ACCOUNT = "com.fsck.k9.AccountSetupBasics.account" + private const val STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming" - String password = null; - String clientCertificateAlias = null; - AuthType authenticationType; - - authenticationType = AuthType.PLAIN; - password = mPasswordView.getText().toString(); - if (mClientCertificateCheckBox.isChecked()) { - clientCertificateAlias = mClientCertificateSpinner.getAlias(); - if (mPasswordView.getText().toString().equals("")) { - authenticationType = AuthType.EXTERNAL; - password = null; - } - } - - if (mAccount == null) { - mAccount = Preferences.getPreferences(this).newAccount(); - mAccount.setChipColor(accountCreator.pickColor()); - } - mAccount.setSenderName(getOwnerName()); - mAccount.setEmail(email); - - InitialAccountSettings initialAccountSettings = new InitialAccountSettings(authenticationType, email, password, - clientCertificateAlias); - - AccountSetupAccountType.actionSelectAccountType(this, mAccount, false, initialAccountSettings); - } - - public void onClick(View v) { - int id = v.getId(); - if (id == R.id.next) { - onNext(); - } else if (id == R.id.manual_setup) { - onManualSetup(); + @JvmStatic + fun actionNewAccount(context: Context) { + val intent = Intent(context, AccountSetupBasics::class.java) + context.startActivity(intent) } } } + +private fun DiscoveredServerSettings.toServerSettings(): ServerSettings? { + val authType = this.authType ?: return null + val username = this.username ?: return null + + return ServerSettings( + type = protocol, + host = host, + port = port, + connectionSecurity = security, + authenticationType = authType, + username = username, + password = null, + clientCertificateAlias = null + ) +}