Commit 529aad8f authored by Filip Wiesner's avatar Filip Wiesner

Glue and TextGlue helper classes + V & VM refinment

parent c3d457c3
......@@ -9,33 +9,20 @@ import com.cvut.blackbird.model.BlackBirdModel
import com.cvut.blackbird.model.Loading
import com.cvut.blackbird.model.Result
import com.cvut.blackbird.model.Success
import com.cvut.blackbird.support.glue.Glue
import kotlinx.coroutines.experimental.Job
import kotlinx.coroutines.experimental.launch
fun View.bindVisibilityTo(owner: LifecycleOwner, liveData: LiveData<Boolean>, invert: Boolean = false) {
liveData.observe(owner , Observer{
visibility = if(it == (!invert)) View.VISIBLE
else View.INVISIBLE
})
}
fun <T> View.bindVisibilityToLoading(owner: LifecycleOwner, liveData: LiveData<Result<T>>) {
liveData.observe(owner , Observer{
visibility = if(it is Loading) View.VISIBLE
else View.INVISIBLE
})
}
fun View.bindEnabledTo(owner: LifecycleOwner, liveData: LiveData<Boolean>, invert: Boolean = false) {
liveData.observe(owner , Observer{
isClickable = it == (!invert)
})
}
fun <T> View.bindEnabledToSuccess(owner: LifecycleOwner, liveData: LiveData<Result<T>>) {
liveData.observe(owner , Observer{
isClickable = it is Success
})
}
infix fun<T> Glue.enabledToSuccessOf(source: LiveData<Result<T>>) {
source.observe(life, Observer { actor.isEnabled = it is Success })
}
public infix fun<T> MutableLiveData<T>.withDefault(init: T) = apply { value = init }
suspend fun MutableLiveData<Boolean>.asBoolProgressStatus(job: suspend () -> Unit) {
......
......@@ -4,12 +4,14 @@ import android.content.Intent
import android.net.Uri
import androidx.lifecycle.ViewModelProviders
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AlphaAnimation
import androidx.lifecycle.Observer
import android.widget.TextView
import androidx.navigation.findNavController
import com.cvut.blackbird.R
......@@ -19,11 +21,12 @@ import com.cvut.blackbird.model.entities.Student
import com.cvut.blackbird.model.services.AuthService
import com.cvut.blackbird.model.services.UserInfo
import com.cvut.blackbird.model.support.AuthResult
import com.cvut.blackbird.support.glue.*
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.auth_fragment.*
class AuthFragment : Fragment() {
var lastValidUser = Student()
private var lastValidUser = Student()
companion object {
fun newInstance() = AuthFragment()
......@@ -50,50 +53,43 @@ class AuthFragment : Fragment() {
.make(view!!, "", Snackbar.LENGTH_INDEFINITE)
.setAction("Try Again") { viewModel.refreshToken() }
acceptBtn.setOnClickListener {
onLogged()
}
send(acceptBtn) clickTo ::onLogged
}
private fun setupBinding() {
usernameInput.onChange {if(it.isNotBlank()) viewModel.fetchStudent(usernameInput.text.toString())}
send(usernameInput).textChangeTo(viewModel::fetchStudent).ignoreBlank()
viewModel.studentResult.observe(this, Observer {
if(it is Success) {
infoMessage.text = "Found user: ${it.value.name} ${it.value.surname}\nStudying: ${it.value.programme}"
lastValidUser = it.value
observe(viewModel.studentResult) { result ->
if(result is Success) {
infoMessage.text = "Found user: ${result.value.name} ${result.value.surname}\nStudying: ${result.value.programme}"
lastValidUser = result.value
usernameInputLayout.isErrorEnabled = false
closeKeyboard()
} else if (usernameInput.text!!.isNotBlank()) {
usernameInputLayout.isErrorEnabled = true
usernameInputLayout.error = "Username not found!"
}
})
viewModel.authStatus.observe(this, Observer { result ->
if (result != null) {
if (result == AuthResult.SUCCESS) {
if(UserInfo.username.isNotBlank()) onLogged()
else secondPhase()
} else if (result != AuthResult.NOT_YET) {
snack?.setText("Error: ${result.name}")
infoMessage.text = result.errorDesc
if (!result.critical) authorize()
else snack!!.show()
}
} else {
snack?.setText("There was some unexpected error, sorry about that :(")
snack?.show()
}
observe(viewModel.authStatus) { result ->
if (result == AuthResult.SUCCESS) {
if(UserInfo.username.isNotBlank()) onLogged()
else secondPhase()
} else if (result != AuthResult.NOT_YET) {
snack?.setText("Error: ${result.name}")
infoMessage.text = result.errorDesc
if (!result.critical) authorize()
else snack!!.show()
}
})
authProgress.bindVisibilityTo(this, viewModel.authLoadingStatus)
usernameStatus.bindVisibilityTo(this, viewModel.userLoadingStatus)
acceptBtn.bindEnabledToSuccess(this, viewModel.studentResult)
viewModel.authLoadingStatus.observe(this, Observer {
if (it == true) snack?.dismiss()
})
}
observe(viewModel.authLoadingStatus) { if (it) snack?.dismiss() }
this bind authProgress visibilityTo viewModel.authLoadingStatus
this bind usernameStatus visibilityTo viewModel.userLoadingStatus
this bind acceptBtn enabledToSuccessOf viewModel.studentResult
}
private fun secondPhase() {
......@@ -107,6 +103,8 @@ class AuthFragment : Fragment() {
usernameInputLayout.visibility = View.VISIBLE
}
/**
* Auth processes handling
*/
......
......@@ -39,12 +39,8 @@ class AuthViewModel : ViewModel() {
var refreshJob: Job? = null
fun refreshToken() {
refreshJob?.cancel()
refreshJob = launch {
_authLoadingStatus.asBoolProgressStatus {
val token = model.refreshToken()
_authStatus.postValue(token)
}
}
refreshJob = launch { _authStatus.postValue(model.refreshToken()) }
.indicateProgressBy(_authLoadingStatus)
}
var studentJob: Job? = null
......
package com.cvut.blackbird.support.glue
import android.view.View
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
class Glue(val life: LifecycleOwner, val actor: View)
infix fun LifecycleOwner.bind(view: View) = Glue(this, view)
inline fun<T> LifecycleOwner.observe(data: LiveData<T>, crossinline stalker: (p: T) -> Unit) =
data.observe(this, Observer { stalker(it) })
infix fun Glue.visibilityTo(source: LiveData<Boolean>) {
source.observe(life, Observer { actor.visibility =
if(it) View.VISIBLE
else View.INVISIBLE
}) }
infix fun Glue.enabledTo(source: LiveData<Boolean>) {
source.observe(life, Observer { actor.isEnabled = it })
}
package com.cvut.blackbird.support.glue
import android.text.Editable
import android.text.TextWatcher
import android.widget.TextView
class TextGlue(val sender: TextView) {
var blankIgnore = false
fun ignoreBlank(ignore: Boolean = true): TextGlue = this.apply { blankIgnore = ignore }
}
fun send(actor: TextView) = TextGlue(actor)
infix fun TextGlue.textChangeTo(receiver: (String) -> Unit): TextGlue {
sender.addTextChangedListener(object: TextWatcher {
override fun afterTextChanged(s: Editable?) = Unit
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
if ((blankIgnore && s?.length ?:0 > 0) ||
!blankIgnore)
receiver(s.toString())
}
})
return this
}
infix fun TextGlue.clickTo(receiver: () -> Unit) = this.apply {
sender.setOnClickListener { receiver.invoke() }
}
fun<T> TextGlue.clickTo(receiver: (T) -> Unit, payload: T) = this.apply {
sender.setOnClickListener { receiver.invoke(payload) }
}
\ No newline at end of file
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