Commit ed48a065 authored by Thomas Markiewicz's avatar Thomas Markiewicz
Browse files

Added native login screen with option to log in with a web browser as well

parent e5d7836c
Pipeline #50375 passed with stages
in 13 minutes and 46 seconds
......@@ -22,13 +22,10 @@ import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import androidx.browser.customtabs.CustomTabsIntent
import android.text.method.LinkMovementMethod
import android.util.Log
import android.view.MenuItem
import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.AccessToken
import com.keylesspalace.tusky.entity.AppCredentials
......@@ -54,6 +51,8 @@ class LoginActivity : BaseActivity(), Injectable {
private var clientId: String? = null
private var clientSecret: String? = null
private val oauthNoRedirectUri: String = "urn:ietf:wg:oauth:2.0:oob"
private val oauthRedirectUri: String
get() {
val scheme = getString(R.string.oauth_scheme)
......@@ -66,10 +65,12 @@ class LoginActivity : BaseActivity(), Injectable {
setContentView(R.layout.activity_login)
/*
val isLibremSocial = getString(R.string.app_name) == "Librem Social"
if(isLibremSocial) {
domain = "social.librem.one"
}
*/
if (savedInstanceState != null) {
domain = savedInstanceState.getString(DOMAIN)!!
......@@ -77,21 +78,14 @@ class LoginActivity : BaseActivity(), Injectable {
clientSecret = savedInstanceState.getString(CLIENT_SECRET)
}
domainEditText.setText(domain)
/* domainEditText.setText(domain) */
preferences = getSharedPreferences(
getString(R.string.preferences_file_key), Context.MODE_PRIVATE)
loginButton.setOnClickListener { onButtonClick() }
whatsAnInstanceTextView.setOnClickListener {
val dialog = AlertDialog.Builder(this)
.setMessage(R.string.dialog_whats_an_instance)
.setPositiveButton(R.string.action_close, null)
.show()
val textView = dialog.findViewById<TextView>(android.R.id.message)
textView?.movementMethod = LinkMovementMethod.getInstance()
}
loginButton.setOnClickListener { onLoginButtonClick() }
loginWithBrowserButton.setOnClickListener { onLoginWithBrowserButtonClick() }
forgotPassphraseButton.setOnClickListener { onLoginWithBrowserButtonClick() }
if (isAdditionalLogin()) {
setSupportActionBar(toolbar)
......@@ -101,10 +95,12 @@ class LoginActivity : BaseActivity(), Injectable {
toolbar.visibility = View.GONE
}
/*
if(isLibremSocial && isFirstTime()) {
// automatically transition to login screen assuming librem one domain
onButtonClick()
}
*/
}
......@@ -134,12 +130,59 @@ class LoginActivity : BaseActivity(), Injectable {
super.onSaveInstanceState(outState)
}
/**
private fun onLoginButtonClick() {
loginButton.isEnabled = false
domain = canonicalizeDomain(domainEditText.text.toString())
try {
HttpUrl.Builder().host(domain).scheme("https").build()
} catch (e: IllegalArgumentException) {
setLoading(false)
domainTextInputLayout.error = getString(R.string.error_invalid_domain)
return
}
val callback = object : Callback<AppCredentials> {
override fun onResponse(call: Call<AppCredentials>,
response: Response<AppCredentials>) {
if (!response.isSuccessful) {
loginButton.isEnabled = true
domainTextInputLayout.error = getString(R.string.error_failed_app_registration)
setLoading(false)
Log.e(TAG, "App authentication failed. " + response.message())
return
}
val credentials = response.body()
clientId = credentials!!.clientId
clientSecret = credentials.clientSecret
authorizeAndLogin()
}
override fun onFailure(call: Call<AppCredentials>, t: Throwable) {
loginButton.isEnabled = true
domainTextInputLayout.error = getString(R.string.error_failed_app_registration)
setLoading(false)
Log.e(TAG, Log.getStackTraceString(t))
}
}
mastodonApi
.authenticateApp(domain, getString(R.string.app_name), oauthNoRedirectUri,
OAUTH_SCOPES, getString(R.string.app_website))
.enqueue(callback)
setLoading(true)
}
/**
* Obtain the oauth client credentials for this app. This is only necessary the first time the
* app is run on a given server instance. So, after the first authentication, they are
* saved in SharedPreferences and every subsequent run they are simply fetched from there.
*/
private fun onButtonClick() {
private fun onLoginWithBrowserButtonClick() {
loginButton.isEnabled = false
......@@ -191,6 +234,10 @@ class LoginActivity : BaseActivity(), Injectable {
}
private fun authorizeAndLogin() {
Log.d(TAG, "Authorizing user...")
}
private fun redirectUserToAuthorizeAndLogin(editText: EditText) {
/* To authorize this app and log in it's necessary to redirect to the domain given,
* activity_login there, and the server will redirect back to the app with its response. */
......
......@@ -25,21 +25,20 @@
<ImageView
android:layout_width="192dp"
android:layout_height="192dp"
android:layout_marginBottom="50dp"
android:layout_marginBottom="10dp"
android:contentDescription="@null"
app:srcCompat="@drawable/splash_with_name" />
<LinearLayout
android:id="@+id/loginInputLayout"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/domainTextInputLayout"
style="@style/TuskyTextInput"
android:layout_width="250dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_domain"
app:errorEnabled="true">
......@@ -48,26 +47,64 @@
android:id="@+id/domainEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:text="social.librem.one"
android:inputType="textUri" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/usernameLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_username"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/usernameEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/passphraseLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_passphrase"
app:errorEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/passphraseEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/loginButton"
style="@style/TuskyButton"
android:layout_width="250dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="@string/action_login" />
<TextView
android:id="@+id/whatsAnInstanceTextView"
android:layout_width="0dp"
android:layout_height="0dp"
android:paddingTop="8dp"
android:text="@string/link_whats_an_instance"
android:textAlignment="center" />
<com.google.android.material.button.MaterialButton
android:id="@+id/loginWithBrowserButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="@string/action_login_with_browser" />
<com.google.android.material.button.MaterialButton
android:id="@+id/forgotPassphraseButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="@string/action_forgot_passphrase" />
</LinearLayout>
<LinearLayout
......
......@@ -72,8 +72,10 @@
<string name="action_unfavourite">Remove favorite</string>
<string name="action_more">More</string>
<string name="action_compose">Compose</string>
<string name="action_login">LOG IN</string>
<string name="action_logout">Log Out</string>
<string name="action_login">Login</string>
<string name="action_login_with_browser">Login with browser</string>
<string name="action_forgot_passphrase">Forgot passphrase?</string>
<string name="action_logout">Logout</string>
<string name="action_logout_confirm">Are you sure you want to log out of the account %1$s?</string>
<string name="action_follow">Follow</string>
<string name="action_unfollow">Unfollow</string>
......@@ -156,7 +158,9 @@
<string name="status_sent">Sent!</string>
<string name="status_sent_long">Reply sent successfully.</string>
<string name="hint_domain">Which instance?</string>
<string name="hint_domain">Host</string>
<string name="hint_username">Username</string>
<string name="hint_passphrase">Passphrase</string>
<string name="hint_compose">What\'s happening?</string>
<string name="hint_configure_scheduled_toot">Configure scheduled post.</string>
<string name="hint_content_warning">Content warning</string>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment