mirror of
https://codeberg.org/timelimit/opentimelimit-android.git
synced 2025-10-05 10:49:29 +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.coroutines.runAsync
|
||||||
import io.timelimit.android.crypto.PasswordHashing
|
import io.timelimit.android.crypto.PasswordHashing
|
||||||
import io.timelimit.android.livedata.castDown
|
import io.timelimit.android.livedata.castDown
|
||||||
|
import io.timelimit.android.livedata.waitForNonNullValue
|
||||||
import io.timelimit.android.livedata.waitForNullableValue
|
import io.timelimit.android.livedata.waitForNullableValue
|
||||||
import io.timelimit.android.logic.AppLogic
|
import io.timelimit.android.logic.AppLogic
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
@ -40,6 +41,25 @@ class LoginPasswordDialogFragmentModel(application: Application): AndroidViewMod
|
||||||
|
|
||||||
val status = statusInternal.castDown()
|
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) {
|
fun tryLogin(userId: String, password: String, model: ActivityViewModel) {
|
||||||
runAsync {
|
runAsync {
|
||||||
loginLock.withLock {
|
loginLock.withLock {
|
||||||
|
|
|
@ -56,6 +56,10 @@ class NewLoginFragment: DialogFragment() {
|
||||||
if (savedInstanceState?.containsKey(SELECTED_USER_ID) == true) {
|
if (savedInstanceState?.containsKey(SELECTED_USER_ID) == true) {
|
||||||
selectedUserId.value = savedInstanceState.getString(SELECTED_USER_ID)
|
selectedUserId.value = savedInstanceState.getString(SELECTED_USER_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
model.tryDefaultLogin(getActivityViewModel(activity!!))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?) = object: BottomSheetDialog(context!!, theme) {
|
override fun onCreateDialog(savedInstanceState: Bundle?) = object: BottomSheetDialog(context!!, theme) {
|
||||||
|
|
|
@ -67,7 +67,7 @@ class ChangeParentPasswordFragment : Fragment(), FragmentWithCustomTitle {
|
||||||
model.changePassword(
|
model.changePassword(
|
||||||
parentUserId = params.parentUserId,
|
parentUserId = params.parentUserId,
|
||||||
oldPassword = binding.oldPassword.text.toString(),
|
oldPassword = binding.oldPassword.text.toString(),
|
||||||
newPassword = binding.newPassword.password.value!!
|
newPassword = binding.newPassword.readPassword()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,8 @@ class ChangeParentPasswordFragment : Fragment(), FragmentWithCustomTitle {
|
||||||
}.let { }
|
}.let { }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
binding.newPassword.allowNoPassword.value = true
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,10 +61,12 @@ class SetupLocalModeFragment : Fragment() {
|
||||||
|
|
||||||
binding.nextBtn.setOnClickListener {
|
binding.nextBtn.setOnClickListener {
|
||||||
model.trySetupWithPassword(
|
model.trySetupWithPassword(
|
||||||
set_password_view.password.value!!
|
binding.setPasswordView.readPassword()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.setPasswordView.allowNoPassword.value = true
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,8 @@ class AddUserFragment : Fragment() {
|
||||||
|
|
||||||
val isPasswordOk = binding.password.passwordOk.or(isPasswordRequired.invert())
|
val isPasswordOk = binding.password.passwordOk.or(isPasswordRequired.invert())
|
||||||
|
|
||||||
|
binding.password.allowNoPassword.value = true
|
||||||
|
|
||||||
// username
|
// username
|
||||||
|
|
||||||
val username = binding.name.getTextLive()
|
val username = binding.name.getTextLive()
|
||||||
|
@ -94,7 +96,7 @@ class AddUserFragment : Fragment() {
|
||||||
name = binding.name.text.toString(),
|
name = binding.name.text.toString(),
|
||||||
type = userType.value!!,
|
type = userType.value!!,
|
||||||
password = when (userType.value!!) {
|
password = when (userType.value!!) {
|
||||||
UserType.Parent -> binding.password.password.value!!
|
UserType.Parent -> binding.password.readPassword()
|
||||||
UserType.Child -> ""
|
UserType.Child -> ""
|
||||||
},
|
},
|
||||||
model = auth
|
model = auth
|
||||||
|
|
|
@ -25,6 +25,8 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.Transformations
|
import androidx.lifecycle.Transformations
|
||||||
import io.timelimit.android.databinding.ViewSetPasswordBinding
|
import io.timelimit.android.databinding.ViewSetPasswordBinding
|
||||||
|
import io.timelimit.android.livedata.and
|
||||||
|
import io.timelimit.android.livedata.or
|
||||||
import io.timelimit.android.util.PasswordValidator
|
import io.timelimit.android.util.PasswordValidator
|
||||||
|
|
||||||
class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout(context, attributeSet) {
|
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 password = MutableLiveData<String>()
|
||||||
val passwordRepeat = 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 {
|
init {
|
||||||
password.value = ""
|
password.value = ""
|
||||||
|
@ -71,6 +81,20 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout
|
||||||
|
|
||||||
password.observeForever { binding.password = it!! }
|
password.observeForever { binding.password = it!! }
|
||||||
passwordRepeat.observeForever() { binding.passwordRepeat = 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) {
|
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
|
(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
|
val password1 = it
|
||||||
|
|
||||||
Transformations.map(passwordRepeat) {
|
Transformations.map(passwordRepeat) {
|
||||||
|
@ -96,7 +120,7 @@ class SetPasswordView(context: Context, attributeSet: AttributeSet): FrameLayout
|
||||||
password1.isNotEmpty() && password2.isNotEmpty() && (password1 == password2) &&
|
password1.isNotEmpty() && password2.isNotEmpty() && (password1 == password2) &&
|
||||||
(PasswordValidator.validate(password1, context) == null)
|
(PasswordValidator.validate(password1, context) == null)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
init {
|
init {
|
||||||
passwordQualityProblem .observeForever { binding.passwordProblem = it }
|
passwordQualityProblem .observeForever { binding.passwordProblem = it }
|
||||||
|
|
|
@ -32,13 +32,28 @@
|
||||||
<variable
|
<variable
|
||||||
name="passwordsNotEqualProblem"
|
name="passwordsNotEqualProblem"
|
||||||
type="Boolean" />
|
type="Boolean" />
|
||||||
|
<variable
|
||||||
|
name="allowNoPassword"
|
||||||
|
type="boolean" />
|
||||||
|
<variable
|
||||||
|
name="noPasswordChecked"
|
||||||
|
type="boolean" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:visibility="@{allowNoPassword ? View.VISIBLE : View.GONE}"
|
||||||
|
android:text="@string/set_password_view_checkbox_no_password"
|
||||||
|
android:id="@+id/no_password_checkbox"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:visibility="@{allowNoPassword && noPasswordChecked ? View.GONE : View.VISIBLE}"
|
||||||
android:id="@+id/field_password"
|
android:id="@+id/field_password"
|
||||||
android:text="@{password}"
|
android:text="@{password}"
|
||||||
android:hint="@string/set_password_view_label_password"
|
android:hint="@string/set_password_view_label_password"
|
||||||
|
@ -52,11 +67,12 @@
|
||||||
android:textAppearance="?android:textAppearanceMedium"
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
tools:text="@string/password_validator_too_short"
|
tools:text="@string/password_validator_too_short"
|
||||||
android:text="@{passwordProblem}"
|
android:text="@{passwordProblem}"
|
||||||
android:visibility="@{TextUtils.isEmpty(passwordProblem) ? View.GONE : View.VISIBLE}"
|
android:visibility="@{TextUtils.isEmpty(passwordProblem) || (allowNoPassword && noPasswordChecked) ? View.GONE : View.VISIBLE}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:visibility="@{allowNoPassword && noPasswordChecked ? View.GONE : View.VISIBLE}"
|
||||||
android:id="@+id/field_password_repeat"
|
android:id="@+id/field_password_repeat"
|
||||||
android:text="@{passwordRepeat}"
|
android:text="@{passwordRepeat}"
|
||||||
android:hint="@string/set_password_view_label_password_repeat"
|
android:hint="@string/set_password_view_label_password_repeat"
|
||||||
|
@ -65,7 +81,7 @@
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:visibility="@{safeUnbox(passwordsNotEqualProblem) ? View.VISIBLE : View.GONE}"
|
android:visibility="@{safeUnbox(passwordsNotEqualProblem) && !(allowNoPassword && noPasswordChecked) ? View.VISIBLE : View.GONE}"
|
||||||
android:textColor="?colorAccent"
|
android:textColor="?colorAccent"
|
||||||
android:gravity="center_horizontal"
|
android:gravity="center_horizontal"
|
||||||
android:textAppearance="?android:textAppearanceMedium"
|
android:textAppearance="?android:textAppearanceMedium"
|
||||||
|
|
|
@ -18,4 +18,5 @@
|
||||||
<string name="set_password_view_not_identical">Die Passwörter sind nicht identisch</string>
|
<string name="set_password_view_not_identical">Die Passwörter sind nicht identisch</string>
|
||||||
<string name="set_password_view_label_password">Neues Passwort</string>
|
<string name="set_password_view_label_password">Neues Passwort</string>
|
||||||
<string name="set_password_view_label_password_repeat">Neues Passwort wiederholen</string>
|
<string name="set_password_view_label_password_repeat">Neues Passwort wiederholen</string>
|
||||||
|
<string name="set_password_view_checkbox_no_password">Passwortschutz nicht verwenden</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -18,4 +18,5 @@
|
||||||
<string name="set_password_view_not_identical">The passwords are not equal</string>
|
<string name="set_password_view_not_identical">The passwords are not equal</string>
|
||||||
<string name="set_password_view_label_password">New password</string>
|
<string name="set_password_view_label_password">New password</string>
|
||||||
<string name="set_password_view_label_password_repeat">Repeat new password</string>
|
<string name="set_password_view_label_password_repeat">Repeat new password</string>
|
||||||
|
<string name="set_password_view_checkbox_no_password">Disable password protection</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue