mirror of
https://codeberg.org/timelimit/opentimelimit-android.git
synced 2025-10-05 02:39:34 +02:00
Squashed commit of the following:
commit ff0a46aefcc6a918ec349608f21613c71605eefe Author: Jonas L <jonas@determapp.de> Date: Mon Apr 8 00:00:00 2019 +0000 Skip asking for password if only one parent and password is empty commit c2ca7bd177806f99a3db49528a35de3b8a06782e Author: Jonas L <jonas@determapp.de> Date: Mon Apr 8 00:00:00 2019 +0000 Allow setting password to empty commit 218f0fc94047593ff9cb083ce1eefa48e69c8e6d Author: Jonas L <jonas@determapp.de> Date: Mon Apr 8 00:00:00 2019 +0000 Extend set password view
This commit is contained in:
parent
2dd04796b0
commit
82295de5fa
9 changed files with 79 additions and 7 deletions
|
@ -23,6 +23,7 @@ import io.timelimit.android.coroutines.executeAndWait
|
|||
import io.timelimit.android.coroutines.runAsync
|
||||
import io.timelimit.android.crypto.PasswordHashing
|
||||
import io.timelimit.android.livedata.castDown
|
||||
import io.timelimit.android.livedata.waitForNonNullValue
|
||||
import io.timelimit.android.livedata.waitForNullableValue
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
|
@ -40,6 +41,25 @@ class LoginPasswordDialogFragmentModel(application: Application): AndroidViewMod
|
|||
|
||||
val status = statusInternal.castDown()
|
||||
|
||||
fun tryDefaultLogin(model: ActivityViewModel) {
|
||||
runAsync {
|
||||
loginLock.withLock {
|
||||
logic.database.user().getParentUsersLive().waitForNonNullValue().singleOrNull()?.let { user ->
|
||||
val emptyPasswordValid = Threads.crypto.executeAndWait { PasswordHashing.validateSync("", user.password) }
|
||||
|
||||
if (emptyPasswordValid) {
|
||||
model.setAuthenticatedUser(AuthenticatedUser(
|
||||
userId = user.id,
|
||||
passwordHash = user.password
|
||||
))
|
||||
|
||||
statusInternal.value = LoginPasswordDialogFragmentStatus.Success
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun tryLogin(userId: String, password: String, model: ActivityViewModel) {
|
||||
runAsync {
|
||||
loginLock.withLock {
|
||||
|
|
|
@ -56,6 +56,10 @@ class NewLoginFragment: DialogFragment() {
|
|||
if (savedInstanceState?.containsKey(SELECTED_USER_ID) == true) {
|
||||
selectedUserId.value = savedInstanceState.getString(SELECTED_USER_ID)
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
model.tryDefaultLogin(getActivityViewModel(activity!!))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?) = object: BottomSheetDialog(context!!, theme) {
|
||||
|
|
|
@ -67,7 +67,7 @@ class ChangeParentPasswordFragment : Fragment(), FragmentWithCustomTitle {
|
|||
model.changePassword(
|
||||
parentUserId = params.parentUserId,
|
||||
oldPassword = binding.oldPassword.text.toString(),
|
||||
newPassword = binding.newPassword.password.value!!
|
||||
newPassword = binding.newPassword.readPassword()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,8 @@ class ChangeParentPasswordFragment : Fragment(), FragmentWithCustomTitle {
|
|||
}.let { }
|
||||
})
|
||||
|
||||
binding.newPassword.allowNoPassword.value = true
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
|
|
@ -61,10 +61,12 @@ class SetupLocalModeFragment : Fragment() {
|
|||
|
||||
binding.nextBtn.setOnClickListener {
|
||||
model.trySetupWithPassword(
|
||||
set_password_view.password.value!!
|
||||
binding.setPasswordView.readPassword()
|
||||
)
|
||||
}
|
||||
|
||||
binding.setPasswordView.allowNoPassword.value = true
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ class AddUserFragment : Fragment() {
|
|||
|
||||
val isPasswordOk = binding.password.passwordOk.or(isPasswordRequired.invert())
|
||||
|
||||
binding.password.allowNoPassword.value = true
|
||||
|
||||
// username
|
||||
|
||||
val username = binding.name.getTextLive()
|
||||
|
@ -94,7 +96,7 @@ class AddUserFragment : Fragment() {
|
|||
name = binding.name.text.toString(),
|
||||
type = userType.value!!,
|
||||
password = when (userType.value!!) {
|
||||
UserType.Parent -> binding.password.password.value!!
|
||||
UserType.Parent -> binding.password.readPassword()
|
||||
UserType.Child -> ""
|
||||
},
|
||||
model = auth
|
||||
|
|
|
@ -25,6 +25,8 @@ import androidx.lifecycle.LiveData
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import io.timelimit.android.databinding.ViewSetPasswordBinding
|
||||
import io.timelimit.android.livedata.and
|
||||
import io.timelimit.android.livedata.or
|
||||
import io.timelimit.android.util.PasswordValidator
|
||||
|
||||
class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout(context, attributeSet) {
|
||||
|
@ -36,6 +38,14 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout
|
|||
|
||||
val password = MutableLiveData<String>()
|
||||
val passwordRepeat = MutableLiveData<String>()
|
||||
val allowNoPassword = MutableLiveData<Boolean>().apply { value = false }
|
||||
val noPasswordChecked = MutableLiveData<Boolean>().apply { value = false }
|
||||
val useEmptyPassword = allowNoPassword.and(noPasswordChecked)
|
||||
|
||||
fun readPassword() = if (useEmptyPassword.value!! == true)
|
||||
""
|
||||
else
|
||||
password.value!!
|
||||
|
||||
init {
|
||||
password.value = ""
|
||||
|
@ -71,6 +81,20 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout
|
|||
|
||||
password.observeForever { binding.password = it!! }
|
||||
passwordRepeat.observeForever() { binding.passwordRepeat = it!! }
|
||||
allowNoPassword.observeForever { binding.allowNoPassword = it }
|
||||
noPasswordChecked.observeForever {
|
||||
binding.noPasswordChecked = it
|
||||
|
||||
if (binding.noPasswordCheckbox.isChecked != it) {
|
||||
binding.noPasswordCheckbox.isChecked = it
|
||||
}
|
||||
}
|
||||
|
||||
binding.noPasswordCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked != noPasswordChecked.value) {
|
||||
noPasswordChecked.value = isChecked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val passwordQualityProblem: LiveData<String?> = Transformations.map(password) {
|
||||
|
@ -87,7 +111,7 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout
|
|||
(passwordValue.isNotEmpty() && it.isNotEmpty()) && passwordValue != it
|
||||
}
|
||||
}
|
||||
val passwordOk: LiveData<Boolean> = Transformations.switchMap(password) {
|
||||
val passwordOk: LiveData<Boolean> = useEmptyPassword.or(Transformations.switchMap(password) {
|
||||
val password1 = it
|
||||
|
||||
Transformations.map(passwordRepeat) {
|
||||
|
@ -96,7 +120,7 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout
|
|||
password1.isNotEmpty() && password2.isNotEmpty() && (password1 == password2) &&
|
||||
(PasswordValidator.validate(password1, context) == null)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
init {
|
||||
passwordQualityProblem .observeForever { binding.passwordProblem = it }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue