From fadcfc0bfcb398d169e7d7c6013501899bd05163 Mon Sep 17 00:00:00 2001 From: Niko Diamadis Date: Tue, 1 Nov 2022 23:10:34 +0100 Subject: [PATCH] Rewrite 'login' to Kotlin --- .../github/gotify/login/AdvancedDialog.java | 75 ----- .../com/github/gotify/login/AdvancedDialog.kt | 67 ++++ .../github/gotify/login/LoginActivity.java | 313 ------------------ .../com/github/gotify/login/LoginActivity.kt | 293 ++++++++++++++++ 4 files changed, 360 insertions(+), 388 deletions(-) delete mode 100644 app/src/main/java/com/github/gotify/login/AdvancedDialog.java create mode 100644 app/src/main/java/com/github/gotify/login/AdvancedDialog.kt delete mode 100644 app/src/main/java/com/github/gotify/login/LoginActivity.java create mode 100644 app/src/main/java/com/github/gotify/login/LoginActivity.kt diff --git a/app/src/main/java/com/github/gotify/login/AdvancedDialog.java b/app/src/main/java/com/github/gotify/login/AdvancedDialog.java deleted file mode 100644 index d031f59..0000000 --- a/app/src/main/java/com/github/gotify/login/AdvancedDialog.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.github.gotify.login; - -import android.app.AlertDialog; -import android.content.Context; -import android.view.LayoutInflater; -import android.widget.CompoundButton; -import androidx.annotation.Nullable; -import com.github.gotify.R; -import com.github.gotify.databinding.AdvancedSettingsDialogBinding; - -class AdvancedDialog { - - private Context context; - private LayoutInflater layoutInflater; - private AdvancedSettingsDialogBinding binding; - private CompoundButton.OnCheckedChangeListener onCheckedChangeListener; - private Runnable onClickSelectCaCertificate; - private Runnable onClickRemoveCaCertificate; - - AdvancedDialog(Context context, LayoutInflater layoutInflater) { - this.context = context; - this.layoutInflater = layoutInflater; - } - - AdvancedDialog onDisableSSLChanged( - CompoundButton.OnCheckedChangeListener onCheckedChangeListener) { - this.onCheckedChangeListener = onCheckedChangeListener; - return this; - } - - AdvancedDialog onClickSelectCaCertificate(Runnable onClickSelectCaCertificate) { - this.onClickSelectCaCertificate = onClickSelectCaCertificate; - return this; - } - - AdvancedDialog onClickRemoveCaCertificate(Runnable onClickRemoveCaCertificate) { - this.onClickRemoveCaCertificate = onClickRemoveCaCertificate; - return this; - } - - AdvancedDialog show(boolean disableSSL, @Nullable String selectedCertificate) { - binding = AdvancedSettingsDialogBinding.inflate(layoutInflater); - binding.disableSSL.setChecked(disableSSL); - binding.disableSSL.setOnCheckedChangeListener(onCheckedChangeListener); - - if (selectedCertificate == null) { - showSelectCACertificate(); - } else { - showRemoveCACertificate(selectedCertificate); - } - - new AlertDialog.Builder(context) - .setView(binding.getRoot()) - .setTitle(R.string.advanced_settings) - .setPositiveButton(context.getString(R.string.done), (ignored, ignored2) -> {}) - .show(); - return this; - } - - private void showSelectCACertificate() { - binding.toggleCaCert.setText(R.string.select_ca_certificate); - binding.toggleCaCert.setOnClickListener((a) -> onClickSelectCaCertificate.run()); - binding.selecetedCaCert.setText(R.string.no_certificate_selected); - } - - void showRemoveCACertificate(String certificate) { - binding.toggleCaCert.setText(R.string.remove_ca_certificate); - binding.toggleCaCert.setOnClickListener( - (a) -> { - showSelectCACertificate(); - onClickRemoveCaCertificate.run(); - }); - binding.selecetedCaCert.setText(certificate); - } -} diff --git a/app/src/main/java/com/github/gotify/login/AdvancedDialog.kt b/app/src/main/java/com/github/gotify/login/AdvancedDialog.kt new file mode 100644 index 0000000..6a1910d --- /dev/null +++ b/app/src/main/java/com/github/gotify/login/AdvancedDialog.kt @@ -0,0 +1,67 @@ +package com.github.gotify.login + +import android.app.AlertDialog +import android.content.Context +import android.view.LayoutInflater +import android.widget.CompoundButton +import com.github.gotify.R +import com.github.gotify.databinding.AdvancedSettingsDialogBinding + +internal class AdvancedDialog( + private val context: Context, + private val layoutInflater: LayoutInflater +) { + private lateinit var binding: AdvancedSettingsDialogBinding + private var onCheckedChangeListener: CompoundButton.OnCheckedChangeListener? = null + private lateinit var onClickSelectCaCertificate: Runnable + private lateinit var onClickRemoveCaCertificate: Runnable + + fun onDisableSSLChanged( + onCheckedChangeListener: CompoundButton.OnCheckedChangeListener? + ): AdvancedDialog { + this.onCheckedChangeListener = onCheckedChangeListener + return this + } + + fun onClickSelectCaCertificate(onClickSelectCaCertificate: Runnable): AdvancedDialog { + this.onClickSelectCaCertificate = onClickSelectCaCertificate + return this + } + + fun onClickRemoveCaCertificate(onClickRemoveCaCertificate: Runnable): AdvancedDialog { + this.onClickRemoveCaCertificate = onClickRemoveCaCertificate + return this + } + + fun show(disableSSL: Boolean, selectedCertificate: String?): AdvancedDialog { + binding = AdvancedSettingsDialogBinding.inflate(layoutInflater) + binding.disableSSL.isChecked = disableSSL + binding.disableSSL.setOnCheckedChangeListener(onCheckedChangeListener) + if (selectedCertificate == null) { + showSelectCACertificate() + } else { + showRemoveCACertificate(selectedCertificate) + } + AlertDialog.Builder(context) + .setView(binding.root) + .setTitle(R.string.advanced_settings) + .setPositiveButton(context.getString(R.string.done), null) + .show() + return this + } + + private fun showSelectCACertificate() { + binding.toggleCaCert.setText(R.string.select_ca_certificate) + binding.toggleCaCert.setOnClickListener { onClickSelectCaCertificate.run() } + binding.selecetedCaCert.setText(R.string.no_certificate_selected) + } + + fun showRemoveCACertificate(certificate: String) { + binding.toggleCaCert.setText(R.string.remove_ca_certificate) + binding.toggleCaCert.setOnClickListener { + showSelectCACertificate() + onClickRemoveCaCertificate.run() + } + binding.selecetedCaCert.text = certificate + } +} diff --git a/app/src/main/java/com/github/gotify/login/LoginActivity.java b/app/src/main/java/com/github/gotify/login/LoginActivity.java deleted file mode 100644 index 292994e..0000000 --- a/app/src/main/java/com/github/gotify/login/LoginActivity.java +++ /dev/null @@ -1,313 +0,0 @@ -package com.github.gotify.login; - -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.View; -import android.widget.EditText; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.view.ContextThemeWrapper; -import com.github.gotify.R; -import com.github.gotify.SSLSettings; -import com.github.gotify.Settings; -import com.github.gotify.Utils; -import com.github.gotify.api.ApiException; -import com.github.gotify.api.Callback; -import com.github.gotify.api.CertUtils; -import com.github.gotify.api.ClientFactory; -import com.github.gotify.client.ApiClient; -import com.github.gotify.client.api.ClientApi; -import com.github.gotify.client.api.UserApi; -import com.github.gotify.client.model.Client; -import com.github.gotify.client.model.VersionInfo; -import com.github.gotify.databinding.ActivityLoginBinding; -import com.github.gotify.init.InitializationActivity; -import com.github.gotify.log.Log; -import com.github.gotify.log.LogsActivity; -import com.github.gotify.log.UncaughtExceptionHandler; -import java.io.InputStream; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import okhttp3.HttpUrl; - -import static com.github.gotify.api.Callback.callInUI; - -public class LoginActivity extends AppCompatActivity { - - // return value from startActivityForResult when choosing a certificate - private final int FILE_SELECT_CODE = 1; - - private ActivityLoginBinding binding; - private Settings settings; - - private boolean disableSSLValidation; - private String caCertContents; - private AdvancedDialog advancedDialog; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - UncaughtExceptionHandler.registerCurrentThread(); - binding = ActivityLoginBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); - Log.i("Entering " + getClass().getSimpleName()); - settings = new Settings(this); - } - - @Override - protected void onPostCreate(@Nullable Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - - binding.gotifyUrl.addTextChangedListener( - new TextWatcher() { - @Override - public void beforeTextChanged( - CharSequence charSequence, int i, int i1, int i2) {} - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - invalidateUrl(); - } - - @Override - public void afterTextChanged(Editable editable) {} - }); - - binding.checkurl.setOnClickListener(ignored -> doCheckUrl()); - binding.openLogs.setOnClickListener(ignored -> openLogs()); - binding.advancedSettings.setOnClickListener(ignored -> toggleShowAdvanced()); - binding.login.setOnClickListener(ignored -> doLogin()); - } - - private void invalidateUrl() { - binding.username.setVisibility(View.GONE); - binding.password.setVisibility(View.GONE); - binding.login.setVisibility(View.GONE); - binding.checkurl.setText(getString(R.string.check_url)); - } - - public void doCheckUrl() { - String url = binding.gotifyUrl.getText().toString(); - HttpUrl parsedUrl = HttpUrl.parse(url); - if (parsedUrl == null) { - Utils.showSnackBar(LoginActivity.this, "Invalid URL (include http:// or https://)"); - return; - } - - if ("http".equals(parsedUrl.scheme())) { - showHttpWarning(); - } - - binding.checkurlProgress.setVisibility(View.VISIBLE); - binding.checkurl.setVisibility(View.GONE); - - final String trimmedUrl = url.trim(); - final String fixedUrl = - trimmedUrl.endsWith("/") - ? trimmedUrl.substring(0, trimmedUrl.length() - 1) - : trimmedUrl; - - try { - ClientFactory.versionApi(fixedUrl, tempSSLSettings()) - .getVersion() - .enqueue(callInUI(this, onValidUrl(fixedUrl), onInvalidUrl(fixedUrl))); - } catch (Exception e) { - binding.checkurlProgress.setVisibility(View.GONE); - binding.checkurl.setVisibility(View.VISIBLE); - String errorMsg = - getString(R.string.version_failed, fixedUrl + "/version", e.getMessage()); - Utils.showSnackBar(LoginActivity.this, errorMsg); - } - } - - public void showHttpWarning() { - new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AppTheme_Dialog)) - .setTitle(R.string.warning) - .setCancelable(true) - .setMessage(R.string.http_warning) - .setPositiveButton(R.string.i_understand, (a, b) -> {}) - .show(); - } - - public void openLogs() { - startActivity(new Intent(this, LogsActivity.class)); - } - - void toggleShowAdvanced() { - String selectedCertName = - caCertContents != null ? getNameOfCertContent(caCertContents) : null; - - advancedDialog = - new AdvancedDialog(this, getLayoutInflater()) - .onDisableSSLChanged( - (ignored, disable) -> { - invalidateUrl(); - disableSSLValidation = disable; - }) - .onClickSelectCaCertificate( - () -> { - invalidateUrl(); - doSelectCACertificate(); - }) - .onClickRemoveCaCertificate( - () -> { - invalidateUrl(); - caCertContents = null; - }) - .show(disableSSLValidation, selectedCertName); - } - - private void doSelectCACertificate() { - Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); - // we don't really care what kind of file it is as long as we can parse it - intent.setType("*/*"); - intent.addCategory(Intent.CATEGORY_OPENABLE); - - try { - startActivityForResult( - Intent.createChooser(intent, getString(R.string.select_ca_file)), - FILE_SELECT_CODE); - } catch (ActivityNotFoundException e) { - // case for user not having a file browser installed - Utils.showSnackBar(this, getString(R.string.please_install_file_browser)); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - super.onActivityResult(requestCode, resultCode, data); - try { - if (requestCode == FILE_SELECT_CODE) { - if (resultCode != RESULT_OK) { - throw new IllegalArgumentException(String.format("result was %d", resultCode)); - } else if (data == null) { - throw new IllegalArgumentException("file path was null"); - } - - Uri uri = data.getData(); - if (uri == null) { - throw new IllegalArgumentException("file path was null"); - } - - InputStream fileStream = getContentResolver().openInputStream(uri); - if (fileStream == null) { - throw new IllegalArgumentException("file path was invalid"); - } - - String content = Utils.readFileFromStream(fileStream); - String name = getNameOfCertContent(content); - - // temporarily set the contents (don't store to settings until they decide to login) - caCertContents = content; - advancedDialog.showRemoveCACertificate(name); - } - } catch (Exception e) { - Utils.showSnackBar(this, getString(R.string.select_ca_failed, e.getMessage())); - } - } - - private String getNameOfCertContent(String content) { - Certificate ca = CertUtils.parseCertificate(content); - return ((X509Certificate) ca).getSubjectDN().getName(); - } - - private Callback.SuccessCallback onValidUrl(String url) { - return (version) -> { - settings.url(url); - binding.checkurlProgress.setVisibility(View.GONE); - binding.checkurl.setVisibility(View.VISIBLE); - binding.checkurl.setText( - getString(R.string.found_gotify_version, version.getVersion())); - binding.username.setVisibility(View.VISIBLE); - binding.username.requestFocus(); - binding.password.setVisibility(View.VISIBLE); - binding.login.setVisibility(View.VISIBLE); - }; - } - - private Callback.ErrorCallback onInvalidUrl(String url) { - return (exception) -> { - binding.checkurlProgress.setVisibility(View.GONE); - binding.checkurl.setVisibility(View.VISIBLE); - Utils.showSnackBar(LoginActivity.this, versionError(url, exception)); - }; - } - - public void doLogin() { - String username = binding.username.getText().toString(); - String password = binding.password.getText().toString(); - - binding.login.setVisibility(View.GONE); - binding.loginProgress.setVisibility(View.VISIBLE); - - ApiClient client = - ClientFactory.basicAuth(settings.url(), tempSSLSettings(), username, password); - client.createService(UserApi.class) - .currentUser() - .enqueue(callInUI(this, (user) -> newClientDialog(client), this::onInvalidLogin)); - } - - private void onInvalidLogin(ApiException e) { - binding.login.setVisibility(View.VISIBLE); - binding.loginProgress.setVisibility(View.GONE); - Utils.showSnackBar(this, getString(R.string.wronguserpw)); - } - - private void newClientDialog(ApiClient client) { - EditText clientName = new EditText(this); - clientName.setText(Build.MODEL); - - new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.AppTheme_Dialog)) - .setTitle(R.string.create_client_title) - .setMessage(R.string.create_client_message) - .setView(clientName) - .setPositiveButton(R.string.create, doCreateClient(client, clientName)) - .setNegativeButton(R.string.cancel, this::onCancelClientDialog) - .show(); - } - - public DialogInterface.OnClickListener doCreateClient(ApiClient client, EditText nameProvider) { - return (a, b) -> { - Client newClient = new Client().name(nameProvider.getText().toString()); - client.createService(ClientApi.class) - .createClient(newClient) - .enqueue(callInUI(this, this::onCreatedClient, this::onFailedToCreateClient)); - }; - } - - private void onCreatedClient(Client client) { - settings.token(client.getToken()); - settings.validateSSL(!disableSSLValidation); - settings.cert(caCertContents); - - Utils.showSnackBar(this, getString(R.string.created_client)); - startActivity(new Intent(this, InitializationActivity.class)); - finish(); - } - - private void onFailedToCreateClient(ApiException e) { - Utils.showSnackBar(this, getString(R.string.create_client_failed)); - binding.loginProgress.setVisibility(View.GONE); - binding.login.setVisibility(View.VISIBLE); - } - - private void onCancelClientDialog(DialogInterface dialog, int which) { - binding.loginProgress.setVisibility(View.GONE); - binding.login.setVisibility(View.VISIBLE); - } - - private String versionError(String url, ApiException exception) { - return getString(R.string.version_failed_status_code, url + "/version", exception.code()); - } - - private SSLSettings tempSSLSettings() { - return new SSLSettings(!disableSSLValidation, caCertContents); - } -} diff --git a/app/src/main/java/com/github/gotify/login/LoginActivity.kt b/app/src/main/java/com/github/gotify/login/LoginActivity.kt new file mode 100644 index 0000000..b618e2f --- /dev/null +++ b/app/src/main/java/com/github/gotify/login/LoginActivity.kt @@ -0,0 +1,293 @@ +package com.github.gotify.login + +import android.content.ActivityNotFoundException +import android.content.DialogInterface +import android.content.Intent +import android.os.Build +import android.os.Bundle +import android.text.Editable +import android.text.TextWatcher +import android.view.View +import android.widget.EditText +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.view.ContextThemeWrapper +import com.github.gotify.R +import com.github.gotify.SSLSettings +import com.github.gotify.Settings +import com.github.gotify.Utils +import com.github.gotify.api.ApiException +import com.github.gotify.api.Callback +import com.github.gotify.api.Callback.SuccessCallback +import com.github.gotify.api.CertUtils +import com.github.gotify.api.ClientFactory +import com.github.gotify.client.ApiClient +import com.github.gotify.client.api.ClientApi +import com.github.gotify.client.api.UserApi +import com.github.gotify.client.model.Client +import com.github.gotify.client.model.VersionInfo +import com.github.gotify.databinding.ActivityLoginBinding +import com.github.gotify.init.InitializationActivity +import com.github.gotify.log.Log +import com.github.gotify.log.LogsActivity +import com.github.gotify.log.UncaughtExceptionHandler +import java.security.cert.X509Certificate +import okhttp3.HttpUrl + +class LoginActivity : AppCompatActivity() { + companion object { + // return value from startActivityForResult when choosing a certificate + private const val FILE_SELECT_CODE = 1 + } + + private lateinit var binding: ActivityLoginBinding + private lateinit var settings: Settings + + private var disableSslValidation = false + private var caCertContents: String? = null + private lateinit var advancedDialog: AdvancedDialog + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + UncaughtExceptionHandler.registerCurrentThread() + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding.root) + Log.i("Entering ${javaClass.simpleName}") + settings = Settings(this) + } + + override fun onPostCreate(savedInstanceState: Bundle?) { + super.onPostCreate(savedInstanceState) + + binding.gotifyUrl.addTextChangedListener(object : TextWatcher { + override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {} + + override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) { + invalidateUrl() + } + + override fun afterTextChanged(editable: Editable) {} + }) + + binding.checkurl.setOnClickListener { doCheckUrl() } + binding.openLogs.setOnClickListener { openLogs() } + binding.advancedSettings.setOnClickListener { toggleShowAdvanced() } + binding.login.setOnClickListener { doLogin() } + } + + private fun invalidateUrl() { + binding.username.visibility = View.GONE + binding.password.visibility = View.GONE + binding.login.visibility = View.GONE + binding.checkurl.text = getString(R.string.check_url) + } + + fun doCheckUrl() { + val url = binding.gotifyUrl.text.toString() + val parsedUrl = HttpUrl.parse(url) + if (parsedUrl == null) { + Utils.showSnackBar(this, "Invalid URL (include http:// or https://)") + return + } + + if ("http" == parsedUrl.scheme()) { + showHttpWarning() + } + + binding.checkurlProgress.visibility = View.VISIBLE + binding.checkurl.visibility = View.GONE + + val trimmedUrl = url.trim() + val fixedUrl = if (trimmedUrl.endsWith("/")) { + trimmedUrl.substring(0, trimmedUrl.length - 1) + } else trimmedUrl + + try { + ClientFactory.versionApi(fixedUrl, tempSslSettings()) + .version + .enqueue(Callback.callInUI(this, onValidUrl(fixedUrl), onInvalidUrl(fixedUrl))) + } catch (e: Exception) { + binding.checkurlProgress.visibility = View.GONE + binding.checkurl.visibility = View.VISIBLE + val errorMsg = getString(R.string.version_failed, "$fixedUrl/version", e.message) + Utils.showSnackBar(this, errorMsg) + } + } + + fun showHttpWarning() { + AlertDialog.Builder(ContextThemeWrapper(this, R.style.AppTheme_Dialog)) + .setTitle(R.string.warning) + .setCancelable(true) + .setMessage(R.string.http_warning) + .setPositiveButton(R.string.i_understand, null) + .show() + } + + fun openLogs() { + startActivity(Intent(this, LogsActivity::class.java)) + } + + fun toggleShowAdvanced() { + val selectedCertName = if (caCertContents != null) { + getNameOfCertContent(caCertContents!!) + } else null + + advancedDialog = AdvancedDialog(this, layoutInflater) + .onDisableSSLChanged { _, disable -> + invalidateUrl() + disableSslValidation = disable + } + .onClickSelectCaCertificate { + invalidateUrl() + doSelectCACertificate() + } + .onClickRemoveCaCertificate { + invalidateUrl() + caCertContents = null + } + .show(disableSslValidation, selectedCertName) + } + + private fun doSelectCACertificate() { + val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) + // we don't really care what kind of file it is as long as we can parse it + intent.type = "*/*" + intent.addCategory(Intent.CATEGORY_OPENABLE) + + try { + startActivityForResult( + Intent.createChooser(intent, getString(R.string.select_ca_file)), + FILE_SELECT_CODE + ) + } catch (e: ActivityNotFoundException) { + // case for user not having a file browser installed + Utils.showSnackBar(this, getString(R.string.please_install_file_browser)) + } + } + + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + super.onActivityResult(requestCode, resultCode, data) + try { + if (requestCode == FILE_SELECT_CODE) { + require(resultCode == RESULT_OK) { String.format("result was %d", resultCode) } + requireNotNull(data) { "file path was null" } + + val uri = data.data ?: throw IllegalArgumentException("file path was null") + + val fileStream = contentResolver.openInputStream(uri) + ?: throw IllegalArgumentException("file path was invalid") + + val content = Utils.readFileFromStream(fileStream) + val name = getNameOfCertContent(content) + + // temporarily set the contents (don't store to settings until they decide to login) + caCertContents = content + advancedDialog.showRemoveCACertificate(name) + } + } catch (e: Exception) { + Utils.showSnackBar(this, getString(R.string.select_ca_failed, e.message)) + } + } + + private fun getNameOfCertContent(content: String): String { + val ca = CertUtils.parseCertificate(content) + return (ca as X509Certificate).subjectDN.name + } + + private fun onValidUrl(url: String): SuccessCallback { + return SuccessCallback { version -> + settings.url(url) + binding.checkurlProgress.visibility = View.GONE + binding.checkurl.visibility = View.VISIBLE + binding.checkurl.text = getString(R.string.found_gotify_version, version.version) + binding.username.visibility = View.VISIBLE + binding.username.requestFocus() + binding.password.visibility = View.VISIBLE + binding.login.visibility = View.VISIBLE + } + } + + private fun onInvalidUrl(url: String): Callback.ErrorCallback { + return Callback.ErrorCallback { exception -> + binding.checkurlProgress.visibility = View.GONE + binding.checkurl.visibility = View.VISIBLE + Utils.showSnackBar(this, versionError(url, exception)) + } + } + + fun doLogin() { + val username = binding.username.text.toString() + val password = binding.password.text.toString() + + binding.login.visibility = View.GONE + binding.loginProgress.visibility = View.VISIBLE + + val client = ClientFactory.basicAuth(settings.url(), tempSslSettings(), username, password) + client.createService(UserApi::class.java) + .currentUser() + .enqueue(Callback.callInUI(this, { newClientDialog(client) }) { + onInvalidLogin() + }) + } + + private fun onInvalidLogin() { + binding.login.visibility = View.VISIBLE + binding.loginProgress.visibility = View.GONE + Utils.showSnackBar(this, getString(R.string.wronguserpw)) + } + + private fun newClientDialog(client: ApiClient) { + val clientName = EditText(this) + clientName.setText(Build.MODEL) + + AlertDialog.Builder(ContextThemeWrapper(this, R.style.AppTheme_Dialog)) + .setTitle(R.string.create_client_title) + .setMessage(R.string.create_client_message) + .setView(clientName) + .setPositiveButton(R.string.create, doCreateClient(client, clientName)) + .setNegativeButton(R.string.cancel) { _, _ -> + onCancelClientDialog() + } + .show() + } + + fun doCreateClient(client: ApiClient, nameProvider: EditText): DialogInterface.OnClickListener { + return DialogInterface.OnClickListener { _, _ -> + val newClient = Client().name(nameProvider.text.toString()) + client.createService(ClientApi::class.java) + .createClient(newClient) + .enqueue(Callback.callInUI(this, { onCreatedClient(it) }) { + onFailedToCreateClient() + }) + } + } + + private fun onCreatedClient(client: Client) { + settings.token(client.token) + settings.validateSSL(!disableSslValidation) + settings.cert(caCertContents) + + Utils.showSnackBar(this, getString(R.string.created_client)) + startActivity(Intent(this, InitializationActivity::class.java)) + finish() + } + + private fun onFailedToCreateClient() { + Utils.showSnackBar(this, getString(R.string.create_client_failed)) + binding.loginProgress.visibility = View.GONE + binding.login.visibility = View.VISIBLE + } + + private fun onCancelClientDialog() { + binding.loginProgress.visibility = View.GONE + binding.login.visibility = View.VISIBLE + } + + private fun versionError(url: String, exception: ApiException): String { + return getString(R.string.version_failed_status_code, "$url/version", exception.code()) + } + + private fun tempSslSettings(): SSLSettings { + return SSLSettings(!disableSslValidation, caCertContents) + } +}