Skip to content
Snippets Groups Projects
Commit 6fc4b72a authored by Kamal Bramwell's avatar Kamal Bramwell
Browse files

Created UI for username submission during Crust acct restore

parent 3e1ec219
No related branches found
No related tags found
No related merge requests found
......@@ -99,6 +99,11 @@
</intent-filter>
</activity>
<activity android:name=".backup.cloud.dropbox.DropboxAuthActivity" />
<activity
android:name=".backup.cloud.crust.login.ui.CrustLoginActivity"
android:theme="@style/Theme.AppCompat.Dialog"
android:excludeFromRecents="true"
/>
<meta-data
android:name="QUERY_LOG"
......
package io.xxlabs.messenger.backup.cloud.crust
import android.content.Intent
import io.xxlabs.messenger.R
import io.xxlabs.messenger.backup.bindings.AccountArchive
import io.xxlabs.messenger.backup.bindings.BackupService
import io.xxlabs.messenger.backup.cloud.AuthHandler
import io.xxlabs.messenger.backup.cloud.CloudStorage
import io.xxlabs.messenger.backup.cloud.crust.login.ui.CrustLoginActivity
import io.xxlabs.messenger.backup.cloud.sftp.login.SshCredentials
import io.xxlabs.messenger.backup.cloud.sftp.login.ui.SshLoginActivity
import io.xxlabs.messenger.backup.data.backup.BackupPreferencesRepository
import io.xxlabs.messenger.backup.data.restore.RestoreEnvironment
import io.xxlabs.messenger.backup.model.BackupLocation
import io.xxlabs.messenger.backup.model.BackupSnapshot
import io.xxlabs.messenger.support.appContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
......@@ -22,6 +28,30 @@ class Crust private constructor(
) : CloudStorage(backupService) {
private var cachedBackupData: AccountArchive? = null
private var username: String? = null
private val authHandler: AuthHandler by lazy {
object : AuthHandler {
override val signInIntent: Intent
get() = Intent(appContext(), CrustLoginActivity::class.java).apply {
action = CrustLoginActivity.CRUST_AUTH_INTENT
}
override fun handleSignInResult(data: Intent?) {
data?.getStringExtra(CrustLoginActivity.EXTRA_CRUST_USERNAME)?.run {
username = this
authResultCallback.onSuccess()
} ?: run {
username = null
authResultCallback.onFailure("Crust restore cancelled")
}
}
override fun signOut() {
username = null
}
}
}
override val location: BackupLocation = BackupLocationData(
R.drawable.ic_sftp,
......@@ -31,7 +61,8 @@ class Crust private constructor(
::signOut,
::isEnabled
) {
null
_authResultCallback = it
authHandler
}
private fun signInRequired(): Boolean {
......@@ -57,7 +88,7 @@ class Crust private constructor(
}
private suspend fun fetchData() {
cachedBackupData = crustApi.recoverBackup(preferences.name).getOrNull()?.let {
cachedBackupData = crustApi.recoverBackup(username ?: preferences.name).getOrNull()?.let {
AccountArchive(it)
}?.also {
updateLastBackup(CrustBackupData.from(it))
......
package io.xxlabs.messenger.backup.cloud.crust.login.ui
import android.text.Editable
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
interface CrustLoginListener {
fun onUsernameSubmitted(username: String)
}
class CrustLogin(
private val listener: CrustLoginListener,
) : CrustLoginUi {
private var username: String = ""
override val submitButtonEnabled: LiveData<Boolean> by ::_submitButtonEnabled
private val _submitButtonEnabled = MutableLiveData(false)
override val textInputEnabled: LiveData<Boolean> by ::_textInputEnabled
private val _textInputEnabled = MutableLiveData(true)
override fun onUsernameInput(text: Editable) {
username = text.toString()
maybeEnableSubmitButton()
}
override fun onSubmitClicked() {
listener.onUsernameSubmitted(username)
}
private fun maybeEnableSubmitButton() {
_submitButtonEnabled.value = isFormComplete()
}
private fun isFormComplete(): Boolean {
return username.isNotEmpty()
}
}
\ No newline at end of file
package io.xxlabs.messenger.backup.cloud.crust.login.ui
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import io.xxlabs.messenger.databinding.ActivityCrustLoginBinding
class CrustLoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityCrustLoginBinding
private val crustViewModel: CrustLoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCrustLoginBinding.inflate(layoutInflater)
binding.lifecycleOwner = this
setContentView(binding.root)
}
override fun onStart() {
super.onStart()
observeUi()
}
private fun observeUi() {
crustViewModel.crustLoginUi.observe(this) { ui ->
ui?.let { binding.ui = it }
}
crustViewModel.username.observe(this) { username ->
username?.let { onLoginSuccess(username) }
}
}
private fun onLoginSuccess(username: String) {
val intent = Intent(CRUST_AUTH_INTENT).apply {
putExtra(EXTRA_CRUST_USERNAME, username)
}
setResult(RESULT_OK, intent)
finish()
}
companion object {
const val CRUST_AUTH_INTENT = "crust_auth"
const val EXTRA_CRUST_USERNAME = "crust_credential"
}
}
\ No newline at end of file
package io.xxlabs.messenger.backup.cloud.crust.login.ui
import android.text.Editable
import androidx.lifecycle.LiveData
interface CrustLoginUi {
val submitButtonEnabled: LiveData<Boolean>
val textInputEnabled: LiveData<Boolean>
val maxUsernameLength: Int get() = 256
fun onUsernameInput(text: Editable)
fun onSubmitClicked()
}
\ No newline at end of file
package io.xxlabs.messenger.backup.cloud.crust.login.ui
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class CrustLoginViewModel : ViewModel(), CrustLoginListener {
val crustLoginUi: LiveData<CrustLoginUi> by ::_crustLoginUi
private val _crustLoginUi = MutableLiveData<CrustLoginUi>(CrustLogin(this))
val username: LiveData<String?> by ::_username
private val _username = MutableLiveData<String?>(null)
override fun onUsernameSubmitted(username: String) {
_username.value = username
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="ui"
type="io.xxlabs.messenger.backup.cloud.crust.login.ui.CrustLoginUi" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/spacing_36"
tools:context=".backup.cloud.crust.login.ui.CrustLoginActivity">
<TextView
android:id="@+id/crust_login_title"
style="@style/dialog_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/crust_login_title"
android:layout_marginBottom="24dp"
app:layout_constraintBottom_toTopOf="@id/crust_login_body"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/crust_login_body"
style="@style/dialog_body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/crust_login_body"
android:layout_marginBottom="24dp"
app:layout_constraintBottom_toTopOf="@id/crust_login_username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/crust_login_username"
style="@style/registration_text_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:enabled="@{ui.textInputEnabled}"
android:layout_marginBottom="18dp"
app:layout_constraintBottom_toTopOf="@id/crust_submit_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.textfield.TextInputEditText
style="@style/registration_text_input_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/crust_login_username_hint"
android:imeOptions="actionNext"
android:maxLength="@{ui.maxUsernameLength}"
android:afterTextChanged="@{ui::onUsernameInput}" />
</com.google.android.material.textfield.TextInputLayout>
<io.xxlabs.messenger.support.view.SingleClickButton
android:id="@+id/crust_submit_button"
style="@style/registration_step_next_button"
android:layout_marginBottom="@dimen/spacing_36"
android:enabled="@{ui.submitButtonEnabled}"
android:onClick="@{() -> ui.onSubmitClicked()}"
android:text="@string/registration_flow_next"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="0.0"
tools:enabled="false" />
<ProgressBar
android:id="@+id/crust_progressbar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:progressTint="@color/brand_default"
android:visibility="@{!ui.textInputEnabled}"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</layout>
\ No newline at end of file
......@@ -638,6 +638,10 @@
<string name="sftp_login_port_hint">Port (leave blank for default TCP 22)</string>
<string name="registration_restore_disabled_error">A username has been submitted. Please reinstall to use restore.</string>
<string name="crust_login_title">Crust</string>
<string name="crust_login_body">Enter your xx messenger username. Your account will be found if it was previously backed up using Crust.</string>
<string name="crust_login_username_hint">xx messenger username</string>
<string name="share_profile_label">Share profile</string>
<string name="share_invitation_message">
Hi, I\'m using xx messenger, you can download it here:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment