diff --git a/app/src/main/java/io/timelimit/android/ui/login/LoginPasswordDialogFragmentModel.kt b/app/src/main/java/io/timelimit/android/ui/login/LoginPasswordDialogFragmentModel.kt index e8f61fb..6d2c489 100644 --- a/app/src/main/java/io/timelimit/android/ui/login/LoginPasswordDialogFragmentModel.kt +++ b/app/src/main/java/io/timelimit/android/ui/login/LoginPasswordDialogFragmentModel.kt @@ -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 { diff --git a/app/src/main/java/io/timelimit/android/ui/login/NewLoginFragment.kt b/app/src/main/java/io/timelimit/android/ui/login/NewLoginFragment.kt index bbe7605..54575c4 100644 --- a/app/src/main/java/io/timelimit/android/ui/login/NewLoginFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/login/NewLoginFragment.kt @@ -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) { diff --git a/app/src/main/java/io/timelimit/android/ui/manage/parent/password/change/ChangeParentPasswordFragment.kt b/app/src/main/java/io/timelimit/android/ui/manage/parent/password/change/ChangeParentPasswordFragment.kt index c05e592..4ce8cd2 100644 --- a/app/src/main/java/io/timelimit/android/ui/manage/parent/password/change/ChangeParentPasswordFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/manage/parent/password/change/ChangeParentPasswordFragment.kt @@ -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 } diff --git a/app/src/main/java/io/timelimit/android/ui/setup/SetupLocalModeFragment.kt b/app/src/main/java/io/timelimit/android/ui/setup/SetupLocalModeFragment.kt index 7a6acaa..8748425 100644 --- a/app/src/main/java/io/timelimit/android/ui/setup/SetupLocalModeFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/setup/SetupLocalModeFragment.kt @@ -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 } } diff --git a/app/src/main/java/io/timelimit/android/ui/user/create/AddUserFragment.kt b/app/src/main/java/io/timelimit/android/ui/user/create/AddUserFragment.kt index eea27f2..9397810 100644 --- a/app/src/main/java/io/timelimit/android/ui/user/create/AddUserFragment.kt +++ b/app/src/main/java/io/timelimit/android/ui/user/create/AddUserFragment.kt @@ -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 diff --git a/app/src/main/java/io/timelimit/android/ui/view/SetPasswordView.kt b/app/src/main/java/io/timelimit/android/ui/view/SetPasswordView.kt index f9670c7..2107dde 100644 --- a/app/src/main/java/io/timelimit/android/ui/view/SetPasswordView.kt +++ b/app/src/main/java/io/timelimit/android/ui/view/SetPasswordView.kt @@ -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() val passwordRepeat = MutableLiveData() + val allowNoPassword = MutableLiveData().apply { value = false } + val noPasswordChecked = MutableLiveData().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 = Transformations.map(password) { @@ -87,7 +111,7 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout (passwordValue.isNotEmpty() && it.isNotEmpty()) && passwordValue != it } } - val passwordOk: LiveData = Transformations.switchMap(password) { + val passwordOk: LiveData = 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 } diff --git a/app/src/main/res/layout/view_set_password.xml b/app/src/main/res/layout/view_set_password.xml index 182e011..3f2c0c3 100644 --- a/app/src/main/res/layout/view_set_password.xml +++ b/app/src/main/res/layout/view_set_password.xml @@ -32,13 +32,28 @@ + + + + + Die Passwörter sind nicht identisch Neues Passwort Neues Passwort wiederholen + Passwortschutz nicht verwenden diff --git a/app/src/main/res/values/strings-set-password-view.xml b/app/src/main/res/values/strings-set-password-view.xml index 1076d7f..4294c79 100644 --- a/app/src/main/res/values/strings-set-password-view.xml +++ b/app/src/main/res/values/strings-set-password-view.xml @@ -18,4 +18,5 @@ The passwords are not equal New password Repeat new password + Disable password protection