Skip to content

Commit ea9a57f

Browse files
empratyushthestinger
authored andcommitted
Improve password UI/UX
1 parent 68fc48d commit ea9a57f

File tree

4 files changed

+80
-13
lines changed

4 files changed

+80
-13
lines changed

app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java

+12-9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import androidx.core.view.WindowCompat;
3535
import androidx.core.view.WindowInsetsCompat;
3636
import androidx.fragment.app.Fragment;
37+
import androidx.lifecycle.ViewModelProvider;
3738
import androidx.loader.app.LoaderManager;
3839
import androidx.loader.content.Loader;
3940

@@ -44,6 +45,7 @@
4445
import app.grapheneos.pdfviewer.fragment.PasswordPromptFragment;
4546
import app.grapheneos.pdfviewer.fragment.JumpToPageFragment;
4647
import app.grapheneos.pdfviewer.loader.DocumentPropertiesLoader;
48+
import app.grapheneos.pdfviewer.viewModel.PasswordStatus;
4749

4850
import java.io.IOException;
4951
import java.io.InputStream;
@@ -126,6 +128,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
126128
private Toast mToast;
127129
private Snackbar snackbar;
128130
private PasswordPromptFragment mPasswordPromptFragment;
131+
public PasswordStatus passwordValidationViewModel;
129132

130133
private final ActivityResultLauncher<Intent> openDocumentLauncher = registerForActivityResult(
131134
new ActivityResultContracts.StartActivityForResult(), result -> {
@@ -190,20 +193,23 @@ public void setDocumentProperties(final String properties) {
190193

191194
@JavascriptInterface
192195
public void showPasswordPrompt() {
193-
if (getPasswordPromptFragment().isAdded()) {
194-
getPasswordPromptFragment().dismiss();
196+
if (!getPasswordPromptFragment().isAdded()){
197+
getPasswordPromptFragment().show(getSupportFragmentManager(), PasswordPromptFragment.class.getName());
195198
}
196-
getPasswordPromptFragment().show(getSupportFragmentManager(), PasswordPromptFragment.class.getName());
199+
passwordValidationViewModel.passwordMissing();
197200
}
198201

199202
@JavascriptInterface
200203
public void invalidPassword() {
201-
runOnUiThread(PdfViewer.this::notifyInvalidPassword);
202-
showPasswordPrompt();
204+
runOnUiThread(() -> passwordValidationViewModel.invalid());
203205
}
204206

205207
@JavascriptInterface
206208
public void onLoaded() {
209+
passwordValidationViewModel.validated();
210+
if (getPasswordPromptFragment().isAdded()) {
211+
getPasswordPromptFragment().dismiss();
212+
}
207213
}
208214

209215
@JavascriptInterface
@@ -212,17 +218,14 @@ public String getPassword() {
212218
}
213219
}
214220

215-
private void notifyInvalidPassword() {
216-
snackbar.setText(R.string.password_prompt_invalid_password).show();
217-
}
218-
219221
@Override
220222
@SuppressLint({"SetJavaScriptEnabled", "ClickableViewAccessibility"})
221223
protected void onCreate(Bundle savedInstanceState) {
222224
super.onCreate(savedInstanceState);
223225
binding = PdfviewerBinding.inflate(getLayoutInflater());
224226
setContentView(binding.getRoot());
225227
setSupportActionBar(binding.toolbar);
228+
passwordValidationViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication())).get(PasswordStatus.class);
226229

227230
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
228231

app/src/main/java/app/grapheneos/pdfviewer/fragment/PasswordPromptFragment.kt

+38-3
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,21 @@ import androidx.fragment.app.DialogFragment
1414
import app.grapheneos.pdfviewer.PdfViewer
1515
import app.grapheneos.pdfviewer.R
1616
import app.grapheneos.pdfviewer.databinding.PasswordDialogFragmentBinding
17+
import app.grapheneos.pdfviewer.viewModel.PasswordStatus
18+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
1719
import com.google.android.material.textfield.TextInputEditText
20+
import com.google.android.material.textfield.TextInputLayout
1821

1922
class PasswordPromptFragment : DialogFragment() {
2023

24+
private lateinit var passwordLayout : TextInputLayout
2125
private lateinit var passwordEditText : TextInputEditText
2226

2327
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
24-
val passwordPrompt = AlertDialog.Builder(requireContext())
28+
val passwordPrompt = MaterialAlertDialogBuilder(requireContext())
2529
val passwordDialogFragmentBinding =
2630
PasswordDialogFragmentBinding.inflate(LayoutInflater.from(requireContext()))
31+
passwordLayout = passwordDialogFragmentBinding.pdfPasswordTextInputLayout
2732
passwordEditText = passwordDialogFragmentBinding.pdfPasswordEditText
2833
passwordPrompt.setView(passwordDialogFragmentBinding.root)
2934
passwordEditText.addTextChangedListener(object : TextWatcher {
@@ -38,15 +43,39 @@ class PasswordPromptFragment : DialogFragment() {
3843
sendPassword()
3944
true
4045
}
41-
passwordPrompt.setPositiveButton(R.string.open) { _, _ -> sendPassword() }
46+
passwordPrompt.setPositiveButton(R.string.open, null)
4247
passwordPrompt.setNegativeButton(R.string.cancel, null)
4348
val dialog = passwordPrompt.create()
49+
passwordPrompt.setCancelable(false)
50+
isCancelable = false
4451
dialog.setCanceledOnTouchOutside(false)
4552
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
53+
(requireActivity() as PdfViewer).passwordValidationViewModel.status.observe(
54+
this
55+
) {
56+
when (it) {
57+
PasswordStatus.Status.MissingPassword -> {
58+
passwordEditText.editableText.clear()
59+
passwordDialogFragmentBinding.title.setText(R.string.password_prompt_description)
60+
}
61+
PasswordStatus.Status.InvalidPassword -> {
62+
passwordEditText.editableText.clear()
63+
passwordDialogFragmentBinding.pdfPasswordTextInputLayout.error =
64+
"invalid password"
65+
}
66+
PasswordStatus.Status.Validated -> {
67+
//Activity will dismiss the dialog
68+
}
69+
else -> {
70+
throw NullPointerException("status shouldn't be null")
71+
}
72+
}
73+
}
4674
return dialog
4775
}
4876

4977
private fun updatePositiveButton() {
78+
passwordLayout.error = ""
5079
val btn = (dialog as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)
5180
btn.isEnabled = passwordEditText.text?.isNotEmpty() ?: false
5281
}
@@ -55,7 +84,6 @@ class PasswordPromptFragment : DialogFragment() {
5584
val password = passwordEditText.text.toString()
5685
if (!TextUtils.isEmpty(password)) {
5786
(activity as PdfViewer).loadPdfWithPassword(password)
58-
dialog?.dismiss()
5987
}
6088
}
6189

@@ -64,4 +92,11 @@ class PasswordPromptFragment : DialogFragment() {
6492
updatePositiveButton()
6593
passwordEditText.requestFocus()
6694
}
95+
96+
override fun onResume() {
97+
super.onResume()
98+
(dialog as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
99+
sendPassword()
100+
}
101+
}
67102
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package app.grapheneos.pdfviewer.viewModel
2+
3+
import androidx.lifecycle.MutableLiveData
4+
import androidx.lifecycle.ViewModel
5+
6+
class PasswordStatus : ViewModel() {
7+
8+
enum class Status {
9+
MissingPassword,
10+
InvalidPassword,
11+
Validated
12+
}
13+
14+
val status: MutableLiveData<Status> = MutableLiveData(Status.MissingPassword)
15+
16+
fun passwordMissing() {
17+
status.postValue(Status.MissingPassword)
18+
}
19+
20+
fun invalid() {
21+
status.postValue(Status.InvalidPassword)
22+
}
23+
24+
fun validated() {
25+
status.postValue(Status.Validated)
26+
}
27+
}

app/src/main/res/layout/password_dialog_fragment.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
android:layout_height="wrap_content"
66
android:orientation="vertical">
77

8-
<TextView
8+
<com.google.android.material.textview.MaterialTextView
9+
android:id="@+id/title"
910
android:layout_width="match_parent"
1011
android:layout_height="wrap_content"
1112
android:layout_marginStart="24dp"
@@ -17,6 +18,7 @@
1718
android:textSize="20sp" />
1819

1920
<com.google.android.material.textfield.TextInputLayout
21+
android:id="@+id/pdf_password_text_input_layout"
2022
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
2123
android:layout_width="match_parent"
2224
android:layout_height="wrap_content"

0 commit comments

Comments
 (0)