LoginActivity.kt 5.74 KB
Newer Older
1 2 3 4
package fr.chenry.android.freshrss.activities

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
5 6
import android.content.Context
import android.content.Intent
7 8 9 10
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
11 12
import android.widget.*
import android.widget.AdapterView.OnItemSelectedListener
13 14 15 16
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.addTextChangedListener
import fr.chenry.android.freshrss.R
import fr.chenry.android.freshrss.store.Store
Christophe Henry's avatar
Christophe Henry committed
17
import fr.chenry.android.freshrss.utils.*
18 19 20
import kotlinx.android.synthetic.main.activity_login.*
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.successUi
21
import java.util.Properties
22 23 24 25

/**
 * A login screen that offers login via email/password.
 */
26
class LoginActivity: AppCompatActivity() {
27 28
    private lateinit var instanceUrl: InstanceUrl

29 30
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
Christophe Henry's avatar
Christophe Henry committed
31

32 33 34 35 36 37 38 39 40 41 42
        setContentView(R.layout.activity_login)
        // Set up the login form.
        password.setOnEditorActionListener(TextView.OnEditorActionListener {_, id, _ ->
            if(id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
                attemptLogin()
                return@OnEditorActionListener true
            }
            false
        })

        email_sign_in_button.setOnClickListener {attemptLogin()}
43 44 45
        instanceUrl = InstanceUrl(InstanceUrl.authorizedProtocols[0], resources.getString(R.string.instance_exemple))
        activity_login_protocol_selection.adapter =
            ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, InstanceUrl.authorizedProtocols)
46

47
        Try {
48 49
            val properties = Properties()
            properties.load(baseContext.assets.open("config.properties"))
50 51 52 53
            instanceUrl = InstanceUrl.parse(properties.getProperty("instance"))
            instance.setText(instanceUrl.base)
            val protocolIdx = InstanceUrl.authorizedProtocols.indexOf(instanceUrl.protocole)
            activity_login_protocol_selection.setSelection(if(protocolIdx >= 0) protocolIdx else 0)
54 55 56 57
            login.setText(properties.getProperty("login"))
            password.setText(properties.getProperty("password"))
        }

Christophe Henry's avatar
Christophe Henry committed
58 59
        computeInstanceURLHint()
        instance.addTextChangedListener {computeInstanceURLHint()}
60 61 62 63 64
        activity_login_protocol_selection.onItemSelectedListener = object: OnItemSelectedListener {
            override fun onNothingSelected(parent: AdapterView<*>?) = computeInstanceURLHint()
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) =
                computeInstanceURLHint()
        }
65 66 67 68 69 70 71
        resetErrors()
        instance.requestFocus()
    }

    private fun attemptLogin() {
        resetErrors()

72 73 74 75 76 77 78 79 80
        var cancel = false
        var focusView: View? = null

        if(instanceUrl.isMalformed) {
            instance.error = getString(R.string.instance_url_malformed)
            focusView = instance
            cancel = true
        }

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
        // Store values at the time of the login attempt.
        val loginStr = login.text.toString()
        val passwordStr = password.text.toString()

        // Check for a valid password, if the user entered one.
        if(passwordStr.isBlank()) {
            password.error = getString(R.string.error_invalid_password)
            focusView = password
            cancel = true
        }

        // Check for a valid email address.
        if(loginStr.isBlank()) {
            login.error = getString(R.string.error_field_required)
            focusView = login
            cancel = true
        }

        if(cancel) {
            focusView?.requestFocus()
        } else {
            showProgress(true)
103
            Store.login(instanceUrl.toString(), loginStr, passwordStr) successUi {
Christophe Henry's avatar
Christophe Henry committed
104 105
                startActivity(Intent(this, MainActivity::class.java))
                finish()
106 107 108 109 110 111 112 113
            } failUi {
                this.e(it)
                instance.error = getString(R.string.error_instance)
                showProgress(false)
            }
        }
    }

Christophe Henry's avatar
Christophe Henry committed
114
    private fun computeInstanceURLHint() {
115 116 117 118
        val instanceStr = instance.text.toString().let {
            if(it.isBlank()) resources.getString(R.string.instance_exemple) else it
        }

119 120 121
        val protocole = activity_login_protocol_selection.selectedItem.toString()
        val instanceUrl = InstanceUrl(protocole, instanceStr)
        reified_instance_url.text = instanceUrl.toSpanString()
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    }

    private fun resetErrors() {
        listOf(login, password, instance).forEach {
            it.error = null
            it.clearFocus()
        }
        hideKeyboard()
    }

    private fun hideKeyboard() {
        val view = this.currentFocus
        view?.let {
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.hideSoftInputFromWindow(it.windowToken, 0)
        }
    }

    private fun showProgress(show: Boolean) {
141
        login_progress_text.text = resources.getString(R.string.login_progress_text, instanceUrl.toString())
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

        val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime).toLong()

        login_form.visibility = if(show) View.GONE else View.VISIBLE
        login_form.animate()
            .setDuration(shortAnimTime)
            .alpha((if(show) 0 else 1).toFloat())
            .setListener(object: AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    login_form.visibility = if(show) View.GONE else View.VISIBLE
                }
            })

        login_progress.visibility = if(show) View.VISIBLE else View.GONE
    }
}