Use EditOTPFragment for view and add code

This commit is contained in:
MrLetsplay 2023-10-04 15:31:44 +02:00
parent 89d1486382
commit 87d1c21f50
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
9 changed files with 21 additions and 364 deletions

View File

@ -4,8 +4,6 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Toast; import android.widget.Toast;
@ -20,7 +18,6 @@ import androidx.fragment.app.Fragment;
import com.cringe_studios.code_guard.databinding.ActivityMainBinding; import com.cringe_studios.code_guard.databinding.ActivityMainBinding;
import com.cringe_studios.code_guard.databinding.DialogIconPackExistsBinding; import com.cringe_studios.code_guard.databinding.DialogIconPackExistsBinding;
import com.cringe_studios.code_guard.databinding.DialogInputCodeChoiceBinding;
import com.cringe_studios.code_guard.fragment.AboutFragment; import com.cringe_studios.code_guard.fragment.AboutFragment;
import com.cringe_studios.code_guard.fragment.EditOTPFragment; import com.cringe_studios.code_guard.fragment.EditOTPFragment;
import com.cringe_studios.code_guard.fragment.GroupFragment; import com.cringe_studios.code_guard.fragment.GroupFragment;
@ -39,7 +36,6 @@ import com.cringe_studios.code_guard.util.OTPDatabase;
import com.cringe_studios.code_guard.util.SettingsUtil; import com.cringe_studios.code_guard.util.SettingsUtil;
import com.cringe_studios.code_guard.util.StyledDialogBuilder; import com.cringe_studios.code_guard.util.StyledDialogBuilder;
import com.cringe_studios.code_guard.util.ThemeUtil; import com.cringe_studios.code_guard.util.ThemeUtil;
import com.cringe_studios.cringe_authenticator_library.OTPType;
import com.google.mlkit.vision.common.InputImage; import com.google.mlkit.vision.common.InputImage;
import java.io.IOException; import java.io.IOException;
@ -357,51 +353,14 @@ public class MainActivity extends BaseActivity {
} }
public void inputCode(MenuItem item) { public void inputCode(MenuItem item) {
DialogInputCodeChoiceBinding binding = DialogInputCodeChoiceBinding.inflate(getLayoutInflater());
String[] options = new String[2];
options[0] = OTPType.TOTP.getFriendlyName() + " (TOTP)";
options[1] = OTPType.HOTP.getFriendlyName() + " (HOTP)";
AlertDialog dialog = new StyledDialogBuilder(this)
.setTitle(R.string.create_totp_title)
.setView(binding.getRoot())
.setNegativeButton(R.string.cancel, (view, which) -> {})
.create();
binding.codeTypes.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, options));
binding.codeTypes.setOnItemClickListener((AdapterView<?> parent, View view, int position, long id) -> {
switch(position) {
case 0:
showTOTPDialog();
break;
case 1:
showHOTPDialog();
break;
}
dialog.dismiss();
});
dialog.show();
}
private void showTOTPDialog() {
DialogUtil.showTOTPDialog(getLayoutInflater(), null, data -> {
Fragment fragment = NavigationUtil.getCurrentFragment(this); Fragment fragment = NavigationUtil.getCurrentFragment(this);
if(!(fragment instanceof GroupFragment)) return; if(!(fragment instanceof GroupFragment)) return;
((GroupFragment) fragment).addOTP(data); GroupFragment f = (GroupFragment) fragment;
}, false);
}
private void showHOTPDialog() { NavigationUtil.openOverlay(this, new EditOTPFragment(null, false, data -> {
DialogUtil.showHOTPDialog(getLayoutInflater(), null, data -> { f.addOTP(data);
Fragment fragment = NavigationUtil.getCurrentFragment(this); }));
if(!(fragment instanceof GroupFragment)) return;
((GroupFragment) fragment).addOTP(data);
}, false);
} }
public void addOTP(MenuItem item) { public void addOTP(MenuItem item) {

View File

@ -77,6 +77,8 @@ public class EditOTPFragment extends NamedFragment {
binding.inputImage.setVisibility(SettingsUtil.isShowImages(requireContext()) ? View.VISIBLE : View.GONE); binding.inputImage.setVisibility(SettingsUtil.isShowImages(requireContext()) ? View.VISIBLE : View.GONE);
binding.inputImage.setOnClickListener(v -> { binding.inputImage.setOnClickListener(v -> {
if(view) return;
new StyledDialogBuilder(requireContext()) new StyledDialogBuilder(requireContext())
.setTitle(R.string.edit_otp_choose_image) .setTitle(R.string.edit_otp_choose_image)
.setItems(R.array.edit_otp_choose_image_options, (d, which) -> { .setItems(R.array.edit_otp_choose_image_options, (d, which) -> {

View File

@ -124,7 +124,8 @@ public class GroupFragment extends NamedFragment {
if(items.size() != 1) return; if(items.size() != 1) return;
OTPData data = items.get(0).getOTPData(); OTPData data = items.get(0).getOTPData();
DialogUtil.showViewCodeDialog(getLayoutInflater(), data); //DialogUtil.showViewCodeDialog(getLayoutInflater(), data);
NavigationUtil.openOverlay(this, new EditOTPFragment(data, true, null));
} }
public void editOTP() { public void editOTP() {

View File

@ -3,10 +3,8 @@ package com.cringe_studios.code_guard.util;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes; import androidx.annotation.StringRes;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.util.Consumer; import androidx.core.util.Consumer;
@ -15,15 +13,9 @@ import com.cringe_studios.code_guard.R;
import com.cringe_studios.code_guard.backup.BackupData; import com.cringe_studios.code_guard.backup.BackupData;
import com.cringe_studios.code_guard.databinding.DialogCreateGroupBinding; import com.cringe_studios.code_guard.databinding.DialogCreateGroupBinding;
import com.cringe_studios.code_guard.databinding.DialogErrorBinding; import com.cringe_studios.code_guard.databinding.DialogErrorBinding;
import com.cringe_studios.code_guard.databinding.DialogInputCodeHotpBinding;
import com.cringe_studios.code_guard.databinding.DialogInputCodeTotpBinding;
import com.cringe_studios.code_guard.databinding.DialogInputPasswordBinding; import com.cringe_studios.code_guard.databinding.DialogInputPasswordBinding;
import com.cringe_studios.code_guard.databinding.DialogSetPasswordBinding; import com.cringe_studios.code_guard.databinding.DialogSetPasswordBinding;
import com.cringe_studios.code_guard.model.OTPData;
import com.cringe_studios.cringe_authenticator_library.OTPAlgorithm;
import com.cringe_studios.cringe_authenticator_library.OTPType;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
@ -108,151 +100,6 @@ public class DialogUtil {
return b.toString().trim(); return b.toString().trim();
} }
public static void showTOTPDialog(LayoutInflater inflater, OTPData initialData, Consumer<OTPData> callback, boolean view) {
Context context = inflater.getContext();
DialogInputCodeTotpBinding binding = DialogInputCodeTotpBinding.inflate(inflater);
binding.inputAlgorithm.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, OTPAlgorithm.values()));
binding.inputAlgorithm.setEnabled(!view);
binding.inputDigits.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, DIGITS));
binding.inputDigits.setEnabled(!view);
binding.inputName.setEnabled(!view);
binding.inputIssuer.setEnabled(!view);
binding.inputSecret.setEnabled(!view);
binding.inputPeriod.setEnabled(!view);
binding.inputChecksum.setEnabled(!view);
if(initialData != null) {
binding.inputName.setText(initialData.getName());
binding.inputIssuer.setText(initialData.getIssuer());
binding.inputSecret.setText(initialData.getSecret());
binding.inputAlgorithm.setSelection(initialData.getAlgorithm().ordinal());
int index = Arrays.asList(DIGITS).indexOf(initialData.getDigits());
if(index != -1) binding.inputDigits.setSelection(index);
binding.inputPeriod.setText(String.valueOf(initialData.getPeriod()));
binding.inputChecksum.setChecked(initialData.hasChecksum());
}
showCodeDialog(context, binding.getRoot(), () -> {
try {
String name = binding.inputName.getText().toString();
if(name.trim().isEmpty()) {
showErrorDialog(context, context.getString(R.string.otp_add_missing_name));
return false;
}
String issuer = binding.inputIssuer.getText().toString();
if(issuer.trim().isEmpty()) {
issuer = null;
}
String secret = binding.inputSecret.getText().toString();
OTPAlgorithm algorithm = (OTPAlgorithm) binding.inputAlgorithm.getSelectedItem();
int digits = (int) binding.inputDigits.getSelectedItem();
int period = Integer.parseInt(binding.inputPeriod.getText().toString());
boolean checksum = binding.inputChecksum.isChecked();
OTPData data = new OTPData(name, issuer, OTPType.TOTP, secret, algorithm, digits, period, 0, checksum);
String errorMessage = data.validate();
if(errorMessage != null) {
showErrorDialog(context, errorMessage);
return false;
}
callback.accept(data);
return true;
}catch(NumberFormatException e) {
showErrorDialog(context, context.getString(R.string.input_code_invalid_number));
return false;
}
});
}
public static void showHOTPDialog(LayoutInflater inflater, OTPData initialData, Consumer<OTPData> callback, boolean view) {
Context context = inflater.getContext();
DialogInputCodeHotpBinding binding = DialogInputCodeHotpBinding.inflate(inflater);
binding.inputAlgorithm.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, OTPAlgorithm.values()));
binding.inputAlgorithm.setEnabled(!view);
binding.inputDigits.setAdapter(new ArrayAdapter<>(context, android.R.layout.simple_list_item_1, DIGITS));
binding.inputDigits.setEnabled(!view);
binding.inputName.setEnabled(!view);
binding.inputIssuer.setEnabled(!view);
binding.inputSecret.setEnabled(!view);
binding.inputCounter.setEnabled(!view);
binding.inputChecksum.setEnabled(!view);
if(initialData != null) {
binding.inputName.setText(initialData.getName());
binding.inputIssuer.setText(initialData.getIssuer());
binding.inputSecret.setText(initialData.getSecret());
binding.inputAlgorithm.setSelection(initialData.getAlgorithm().ordinal());
int index = Arrays.asList(DIGITS).indexOf(initialData.getDigits());
if(index != -1) binding.inputDigits.setSelection(index);
binding.inputCounter.setText(String.valueOf(initialData.getCounter()));
binding.inputChecksum.setChecked(initialData.hasChecksum());
}
showCodeDialog(context, binding.getRoot(), () -> {
try {
String name = binding.inputName.getText().toString();
if(name.trim().isEmpty()) {
showErrorDialog(context, context.getString(R.string.otp_add_missing_name));
return false;
}
String issuer = binding.inputIssuer.getText().toString();
if(issuer.trim().isEmpty()) {
issuer = null;
}
String secret = binding.inputSecret.getText().toString();
OTPAlgorithm algorithm = (OTPAlgorithm) binding.inputAlgorithm.getSelectedItem();
int digits = (int) binding.inputDigits.getSelectedItem();
int counter = Integer.parseInt(binding.inputCounter.getText().toString());
boolean checksum = binding.inputChecksum.isChecked();
OTPData data = new OTPData(name, issuer, OTPType.HOTP, secret, algorithm, digits, 0, counter, checksum);
String errorMessage = data.validate();
if(errorMessage != null) {
showErrorDialog(context, errorMessage);
return false;
}
callback.accept(data);
return true;
}catch(NumberFormatException e) {
showErrorDialog(context, context.getString(R.string.input_code_invalid_number));
return false;
}
});
}
public static void showViewCodeDialog(LayoutInflater inflater, @NonNull OTPData initialData) {
// TODO: use better dialogs
switch(initialData.getType()) {
case HOTP: showHOTPDialog(inflater, initialData, d -> {}, true); break;
case TOTP: showTOTPDialog(inflater, initialData, d -> {}, true); break;
}
}
public static void showEditCodeDialog(LayoutInflater inflater, @NonNull OTPData initialData, Consumer<OTPData> callback) {
switch(initialData.getType()) {
case HOTP: showHOTPDialog(inflater, initialData, callback, false); break;
case TOTP: showTOTPDialog(inflater, initialData, callback, false); break;
}
}
public static void showCreateGroupDialog(LayoutInflater inflater, String initialName, Consumer<String> callback, Runnable onDismiss) { public static void showCreateGroupDialog(LayoutInflater inflater, String initialName, Consumer<String> callback, Runnable onDismiss) {
Context context = inflater.getContext(); Context context = inflater.getContext();

View File

@ -42,8 +42,7 @@ public class NavigationUtil {
navigate((AppCompatActivity) currentFragment.requireActivity(), fragmentClass, args); navigate((AppCompatActivity) currentFragment.requireActivity(), fragmentClass, args);
} }
public static void openOverlay(Fragment currentFragment, NamedFragment overlay) { public static void openOverlay(AppCompatActivity activity, NamedFragment overlay) {
AppCompatActivity activity = (AppCompatActivity) currentFragment.requireActivity();
FragmentManager manager = activity.getSupportFragmentManager(); FragmentManager manager = activity.getSupportFragmentManager();
manager.beginTransaction() manager.beginTransaction()
.setReorderingAllowed(true) .setReorderingAllowed(true)
@ -52,6 +51,11 @@ public class NavigationUtil {
.commit(); .commit();
} }
public static void openOverlay(Fragment currentFragment, NamedFragment overlay) {
AppCompatActivity activity = (AppCompatActivity) currentFragment.requireActivity();
openOverlay(activity, overlay);
}
public static void closeOverlay(Fragment currentFragment) { public static void closeOverlay(Fragment currentFragment) {
AppCompatActivity activity = (AppCompatActivity) currentFragment.requireActivity(); AppCompatActivity activity = (AppCompatActivity) currentFragment.requireActivity();
FragmentManager manager = activity.getSupportFragmentManager(); FragmentManager manager = activity.getSupportFragmentManager();

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools">
<ListView
android:id="@+id/code_types"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@android:layout/test_list_item" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<EditText
android:id="@+id/input_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:hint="@string/otp_add_name"
android:autofillHints="" />
<EditText
android:id="@+id/input_issuer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:hint="@string/otp_add_issuer"
android:autofillHints="" />
<EditText
android:id="@+id/input_secret"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:hint="@string/otp_add_secret"
android:autofillHints="" />
<Spinner
android:id="@+id/input_algorithm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
<Spinner
android:id="@+id/input_digits"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
<EditText
android:id="@+id/input_counter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
android:hint="@string/otp_add_counter"
android:autofillHints="" />
<CheckBox
android:id="@+id/input_checksum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/otp_add_checksum" />
</LinearLayout>

View File

@ -1,64 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp">
<EditText
android:id="@+id/input_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:hint="@string/otp_add_name"
android:autofillHints="" />
<EditText
android:id="@+id/input_issuer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:hint="@string/otp_add_issuer"
android:autofillHints="" />
<EditText
android:id="@+id/input_secret"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="text"
android:hint="@string/otp_add_secret"
android:autofillHints="" />
<Spinner
android:id="@+id/input_algorithm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
<Spinner
android:id="@+id/input_digits"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
<EditText
android:id="@+id/input_period"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="number"
android:hint="@string/otp_add_period"
android:autofillHints="" />
<CheckBox
android:id="@+id/input_checksum"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/otp_add_checksum" />
</LinearLayout>

View File

@ -7,12 +7,6 @@
android:padding="16dp" android:padding="16dp"
android:orientation="vertical"> android:orientation="vertical">
<TextView
android:id="@+id/set_password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/set_password" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -28,25 +22,20 @@
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/confirm_password_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/confirm_password"
android:layout_marginTop="10dp" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp"
app:passwordToggleEnabled="true"> app:passwordToggleEnabled="true">
<com.google.android.material.textfield.TextInputEditText <EditText
android:id="@+id/confirm_password" android:id="@+id/confirm_password"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ems="10" android:ems="10"
android:hint="@string/confirm_password" android:hint="@string/confirm_password"
android:inputType="textPassword" /> android:inputType="textPassword"
app:boxStrokeWidth="0dp"/>
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>