Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 3581a023 authored by cketti's avatar cketti Committed by GitHub
Browse files

Merge pull request #6096 from k9mail/sign_in_with_google

Add "Sign in with Google" button
parents 5065afef d4883d19
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -302,6 +302,10 @@
            </intent-filter>
        </activity>

        <activity
            android:name=".activity.setup.OAuthFlowActivity"
            android:label="@string/account_setup_basics_title" />

        <receiver
            android:name=".provider.UnreadWidgetProvider"
            android:icon="@drawable/ic_launcher"
+45 −18
Original line number Diff line number Diff line
package com.fsck.k9.activity.setup

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
@@ -193,12 +194,19 @@ class AccountSetupBasics : K9Activity() {
            connectionSettings.incoming.authenticationType == AuthType.XOAUTH2 &&
            connectionSettings.outgoing.authenticationType == AuthType.XOAUTH2
        ) {
            finishAutoSetup(connectionSettings)
            startOAuthFlow(connectionSettings)
        } else {
            startPasswordFlow()
        }
    }

    private fun startOAuthFlow(connectionSettings: ConnectionSettings) {
        val account = createAccount(connectionSettings)

        val intent = OAuthFlowActivity.buildLaunchIntent(this, account.uuid)
        startActivityForResult(intent, REQUEST_CODE_OAUTH)
    }

    private fun startPasswordFlow() {
        uiState = UiState.PASSWORD_FLOW

@@ -233,6 +241,13 @@ class AccountSetupBasics : K9Activity() {
    }

    private fun finishAutoSetup(connectionSettings: ConnectionSettings) {
        val account = createAccount(connectionSettings)

        // Check incoming here. Then check outgoing in onActivityResult()
        AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.INCOMING)
    }

    private fun createAccount(connectionSettings: ConnectionSettings): Account {
        val email = emailView.text?.toString() ?: error("Email missing")
        val password = passwordView.text?.toString()

@@ -248,8 +263,7 @@ class AccountSetupBasics : K9Activity() {

        localFoldersCreator.createSpecialLocalFolders(account)

        // Check incoming here. Then check outgoing in onActivityResult()
        AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.INCOMING)
        return account
    }

    private fun onManualSetup() {
@@ -309,12 +323,16 @@ class AccountSetupBasics : K9Activity() {
    }

    public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode != AccountSetupCheckSettings.ACTIVITY_REQUEST_CODE) {
            super.onActivityResult(requestCode, resultCode, data)
            return
        when (requestCode) {
            REQUEST_CODE_CHECK_SETTINGS -> handleCheckSettingsResult(resultCode)
            REQUEST_CODE_OAUTH -> handleSignInResult(resultCode)
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }

    private fun handleCheckSettingsResult(resultCode: Int) {
        if (resultCode != RESULT_OK) return

        if (resultCode == RESULT_OK) {
        val account = this.account ?: error("Account instance missing")

        if (!checkedIncoming) {
@@ -329,6 +347,13 @@ class AccountSetupBasics : K9Activity() {
            AccountSetupNames.actionSetNames(this, account)
        }
    }

    private fun handleSignInResult(resultCode: Int) {
        if (resultCode != RESULT_OK) return

        val account = this.account ?: error("Account instance missing")

        AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.INCOMING)
    }

    private enum class UiState {
@@ -340,6 +365,8 @@ class AccountSetupBasics : K9Activity() {
        private const val EXTRA_ACCOUNT = "com.fsck.k9.AccountSetupBasics.account"
        private const val STATE_KEY_UI_STATE = "com.fsck.k9.AccountSetupBasics.uiState"
        private const val STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming"
        private const val REQUEST_CODE_CHECK_SETTINGS = AccountSetupCheckSettings.ACTIVITY_REQUEST_CODE
        private const val REQUEST_CODE_OAUTH = Activity.RESULT_FIRST_USER + 1

        @JvmStatic
        fun actionNewAccount(context: Context) {
+5 −0
Original line number Diff line number Diff line
@@ -69,6 +69,11 @@ class AuthViewModel(
        return authState.isAuthorized
    }

    fun isUsingGoogle(account: Account): Boolean {
        val config = findOAuthConfiguration(account)
        return config?.authorizationEndpoint == "https://accounts.google.com/o/oauth2/v2/auth"
    }

    private fun getOrCreateAuthState(account: Account): AuthState {
        return try {
            account.oAuthState?.let { AuthState.jsonDeserialize(it) } ?: AuthState()
+89 −0
Original line number Diff line number Diff line
package com.fsck.k9.activity.setup

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.core.view.isVisible
import com.fsck.k9.Account
import com.fsck.k9.preferences.AccountManager
import com.fsck.k9.ui.R
import com.fsck.k9.ui.base.K9Activity
import com.fsck.k9.ui.observe
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel

class OAuthFlowActivity : K9Activity() {
    private val authViewModel: AuthViewModel by viewModel()
    private val accountManager: AccountManager by inject()

    private lateinit var errorText: TextView

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setLayout(R.layout.account_setup_oauth)
        setTitle(R.string.account_setup_basics_title)

        val accountUUid = intent.getStringExtra(EXTRA_ACCOUNT_UUID) ?: error("Missing account UUID")
        val account = accountManager.getAccount(accountUUid) ?: error("Account not found")

        errorText = findViewById(R.id.error_text)
        val signInButton: View = if (authViewModel.isUsingGoogle(account)) {
            findViewById(R.id.google_sign_in_button)
        } else {
            findViewById(R.id.oauth_sign_in_button)
        }

        signInButton.isVisible = true
        signInButton.setOnClickListener { startOAuthFlow(account) }

        authViewModel.init(activityResultRegistry, lifecycle)

        authViewModel.uiState.observe(this) { state ->
            handleUiUpdates(state)
        }
    }

    private fun handleUiUpdates(state: AuthFlowState) {
        when (state) {
            AuthFlowState.Idle -> {
                return
            }
            AuthFlowState.Success -> {
                setResult(RESULT_OK)
                finish()
            }
            AuthFlowState.Canceled -> {
                errorText.text = getString(R.string.account_setup_failed_dlg_oauth_flow_canceled)
            }
            is AuthFlowState.Failed -> {
                errorText.text = getString(R.string.account_setup_failed_dlg_oauth_flow_failed, state)
            }
            AuthFlowState.NotSupported -> {
                errorText.text = getString(R.string.account_setup_failed_dlg_oauth_not_supported)
            }
            AuthFlowState.BrowserNotFound -> {
                errorText.text = getString(R.string.account_setup_failed_dlg_browser_not_found)
            }
        }

        authViewModel.authResultConsumed()
    }

    private fun startOAuthFlow(account: Account) {
        errorText.text = ""

        authViewModel.login(account)
    }

    companion object {
        private const val EXTRA_ACCOUNT_UUID = "accountUuid"

        fun buildLaunchIntent(context: Context, accountUuid: String): Intent {
            return Intent(context, OAuthFlowActivity::class.java).apply {
                putExtra(EXTRA_ACCOUNT_UUID, accountUuid)
            }
        }
    }
}
+464 B
Loading image diff...
Loading