diff --git a/app/src/main/java/com/cringe_studios/code_guard/MainActivity.java b/app/src/main/java/com/cringe_studios/code_guard/MainActivity.java index c4fd595..2e9120d 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/MainActivity.java +++ b/app/src/main/java/com/cringe_studios/code_guard/MainActivity.java @@ -107,7 +107,7 @@ public class MainActivity extends BaseActivity { InputImage image = InputImage.fromFilePath(this, img); qrScanner.scan(image, code -> { if(code == null) { - DialogUtil.showErrorDialog(this, "No codes were detected in the provided image"); + DialogUtil.showErrorDialog(this, getString(R.string.error_qr_scan_not_detected)); return; } @@ -126,9 +126,9 @@ public class MainActivity extends BaseActivity { for (OTPData dt : code.getOTPs()) frag.addOTP(dt); } } - }, error -> DialogUtil.showErrorDialog(this, "Failed to detect code: " + error)); + }, error -> DialogUtil.showErrorDialog(this, getString(R.string.error_qr_scan_failed), error, null)); } catch (IOException e) { - DialogUtil.showErrorDialog(this, "Failed to read image: " + e); + DialogUtil.showErrorDialog(this, getString(R.string.error_qr_scan_image_failed), e); } }); @@ -172,7 +172,7 @@ public class MainActivity extends BaseActivity { AlertDialog dialog = new StyledDialogBuilder(this) - .setTitle("Icon pack already exists") + .setTitle(R.string.icon_pack_exists_title) .setView(binding.getRoot()) .setNeutralButton(R.string.cancel, (d, which) -> {}) .create(); @@ -184,7 +184,7 @@ public class MainActivity extends BaseActivity { IconUtil.importIconPack(this, doc); Toast.makeText(this, getString(R.string.icon_pack_imported, meta.getIcons().length), Toast.LENGTH_LONG).show(); } catch (IconPackException e) { - DialogUtil.showErrorDialog(this, "Failed to import icon pack", e); + DialogUtil.showErrorDialog(this, getString(R.string.error_import_icon_pack), e); } break; case 1: // Rename existing @@ -193,7 +193,7 @@ public class MainActivity extends BaseActivity { IconUtil.importIconPack(this, doc); Toast.makeText(this, getString(R.string.icon_pack_imported, meta.getIcons().length), Toast.LENGTH_LONG).show(); } catch (IconPackException e) { - DialogUtil.showErrorDialog(this, "Failed to import icon pack", e); + DialogUtil.showErrorDialog(this, getString(R.string.error_import_icon_pack), e); } break; case 2: // Rename imported @@ -201,7 +201,7 @@ public class MainActivity extends BaseActivity { IconUtil.importIconPack(this, doc, meta.getName() + " (" + meta.getVersion() + ")", UUID.randomUUID().toString()); Toast.makeText(this, getString(R.string.icon_pack_imported, meta.getIcons().length), Toast.LENGTH_LONG).show(); } catch (IconPackException e) { - DialogUtil.showErrorDialog(this, "Failed to import icon pack", e); + DialogUtil.showErrorDialog(this, getString(R.string.error_import_icon_pack), e); } break; } @@ -217,7 +217,7 @@ public class MainActivity extends BaseActivity { IconUtil.importIconPack(this, doc); Toast.makeText(this, getString(R.string.icon_pack_imported, meta.getIcons().length), Toast.LENGTH_LONG).show(); } catch (IconPackException e) { - DialogUtil.showErrorDialog(this, "Failed to import icon pack", e); + DialogUtil.showErrorDialog(this, getString(R.string.error_import_icon_pack), e); } }); @@ -323,6 +323,7 @@ public class MainActivity extends BaseActivity { finishAffinity(); }else { backLastPressed = System.currentTimeMillis(); + Toast.makeText(this, R.string.back_pressed, Toast.LENGTH_LONG).show(); } } diff --git a/app/src/main/java/com/cringe_studios/code_guard/fragment/EditOTPFragment.java b/app/src/main/java/com/cringe_studios/code_guard/fragment/EditOTPFragment.java index 0842cfd..adfc1ae 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/fragment/EditOTPFragment.java +++ b/app/src/main/java/com/cringe_studios/code_guard/fragment/EditOTPFragment.java @@ -78,8 +78,8 @@ public class EditOTPFragment extends NamedFragment { binding.inputImage.setVisibility(SettingsUtil.isShowImages(requireContext()) ? View.VISIBLE : View.GONE); binding.inputImage.setOnClickListener(v -> { new StyledDialogBuilder(requireContext()) - .setTitle("Choose Image") - .setItems(new String[]{"Image from icon pack", "Image from gallery", "No image", "Reset to default image"}, (d, which) -> { + .setTitle(R.string.edit_otp_choose_image) + .setItems(R.array.edit_otp_choose_image_options, (d, which) -> { switch(which) { case 0: pickImageFromIconPack(); @@ -231,7 +231,7 @@ public class EditOTPFragment extends NamedFragment { binding.inputImage.setImageBitmap(bm); }catch(IOException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to open image", e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_edit_otp_image), e); } }); } diff --git a/app/src/main/java/com/cringe_studios/code_guard/fragment/GroupFragment.java b/app/src/main/java/com/cringe_studios/code_guard/fragment/GroupFragment.java index 43f9f77..85efb97 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/fragment/GroupFragment.java +++ b/app/src/main/java/com/cringe_studios/code_guard/fragment/GroupFragment.java @@ -100,7 +100,7 @@ public class GroupFragment extends NamedFragment { OTPDatabase.saveDatabase(requireContext(), SettingsUtil.getCryptoParameters(requireContext())); for(OTPData d : data) otpListAdapter.add(d); } catch (OTPDatabaseException | CryptoException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to save database: " + e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_database_save), e); } }, null); } @@ -112,7 +112,7 @@ public class GroupFragment extends NamedFragment { try { vh.refresh(); } catch (Exception e) { - DialogUtil.showErrorDialog(requireContext(), e.getMessage() == null ? "An error occurred while refreshing the code" : e.getMessage()); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_otp_refresh), e); } } } diff --git a/app/src/main/java/com/cringe_studios/code_guard/fragment/SettingsFragment.java b/app/src/main/java/com/cringe_studios/code_guard/fragment/SettingsFragment.java index 9bd0748..6e1a0f8 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cringe_studios/code_guard/fragment/SettingsFragment.java @@ -103,7 +103,7 @@ public class SettingsFragment extends NamedFragment { binding.settingsBiometricLock.setEnabled(true); } } catch (CryptoException | OTPDatabaseException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to enable encryption", e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_enable_encryption), e); } }, () -> view.setChecked(false)); }else { @@ -118,7 +118,7 @@ public class SettingsFragment extends NamedFragment { binding.settingsBiometricLock.setChecked(false); binding.settingsBiometricLock.setEnabled(false); } catch (OTPDatabaseException | CryptoException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to disable encryption", e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_disable_encryption), e); } }, () -> view.setChecked(true)); } @@ -135,7 +135,7 @@ public class SettingsFragment extends NamedFragment { BiometricKey biometricKey = Crypto.createBiometricKey(SettingsUtil.getCryptoParameters(requireContext())); SettingsUtil.enableBiometricEncryption(requireContext(), biometricKey); } catch (CryptoException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to enable: " + e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_biometric_encryption_enable), e); } }, () -> view.setChecked(false)); }, null); @@ -144,7 +144,7 @@ public class SettingsFragment extends NamedFragment { BiometricKey key = SettingsUtil.getBiometricKey(requireContext()); if(key != null) Crypto.deleteBiometricKey(key); } catch (CryptoException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to delete key: " + e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_biometric_encryption_disable), e); } SettingsUtil.disableBiometricEncryption(requireContext()); @@ -231,6 +231,11 @@ public class SettingsFragment extends NamedFragment { .setItems(R.array.backup_create, (d, which) -> { switch(which) { case 0: + if(!SettingsUtil.isDatabaseEncrypted(requireContext())) { + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_backup_database_not_encrypted)); + return; + } + OTPDatabase.promptLoadDatabase(requireActivity(), () -> { SecretKey key = OTPDatabase.getLoadedKey(); CryptoParameters parameters = SettingsUtil.getCryptoParameters(requireContext()); @@ -287,7 +292,7 @@ public class SettingsFragment extends NamedFragment { binding.manageIconPacksList.setAdapter(new IconPackListAdapter(requireContext(), IconUtil.loadAllIconPacks(requireContext()))); new StyledDialogBuilder(requireContext()) - .setTitle("Manage icon packs") + .setTitle(R.string.manage_icon_packs_title) .setView(binding.getRoot()) .setPositiveButton(R.string.ok, (d, which) -> {}) .show(); @@ -319,7 +324,7 @@ public class SettingsFragment extends NamedFragment { return; } catch (CryptoException ignored) { // Load with password } catch (BackupException | OTPDatabaseException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to load backup", e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_backup_load_other), e); return; } } @@ -330,9 +335,9 @@ public class SettingsFragment extends NamedFragment { SecretKey key = Crypto.generateKey(parameters, password); loadBackup(uri, key, parameters); } catch (CryptoException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to load backup. Make sure the password is valid", e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_backup_load_crypto), e); } catch (BackupException | OTPDatabaseException e) { - DialogUtil.showErrorDialog(requireContext(), "Failed to load backup", e); + DialogUtil.showErrorDialog(requireContext(), getString(R.string.error_backup_load_other), e); } }, null); }, null); diff --git a/app/src/main/java/com/cringe_studios/code_guard/icon/IconListAdapter.java b/app/src/main/java/com/cringe_studios/code_guard/icon/IconListAdapter.java index ec77f98..7aa0df0 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/icon/IconListAdapter.java +++ b/app/src/main/java/com/cringe_studios/code_guard/icon/IconListAdapter.java @@ -93,7 +93,7 @@ public class IconListAdapter extends BaseExpandableListAdapter implements Expand @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { IconListCategoryBinding binding = IconListCategoryBinding.inflate(LayoutInflater.from(context)); - binding.getRoot().setText((String) getGroup(groupPosition)); + binding.getRoot().setText(getGroup(groupPosition)); return binding.getRoot(); } diff --git a/app/src/main/java/com/cringe_studios/code_guard/icon/IconUtil.java b/app/src/main/java/com/cringe_studios/code_guard/icon/IconUtil.java index ff4a49c..eab64c5 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/icon/IconUtil.java +++ b/app/src/main/java/com/cringe_studios/code_guard/icon/IconUtil.java @@ -207,10 +207,11 @@ public class IconUtil { for(IconPack pack : packs) { for(Icon i : pack.getIcons()) { String category = i.getMetadata().getCategory(); - if(icons.containsKey(category)) { - icons.get(category).add(i); + List is = icons.get(category); + if(is != null) { + is.add(i); }else { - List is = new ArrayList<>(); + is = new ArrayList<>(); is.add(i); icons.put(category, is); } diff --git a/app/src/main/java/com/cringe_studios/code_guard/otplist/OTPListAdapter.java b/app/src/main/java/com/cringe_studios/code_guard/otplist/OTPListAdapter.java index bfc9cf4..a7f8a6b 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/otplist/OTPListAdapter.java +++ b/app/src/main/java/com/cringe_studios/code_guard/otplist/OTPListAdapter.java @@ -190,7 +190,7 @@ public class OTPListAdapter extends RecyclerView.Adapter { try { h.refresh(); } catch (OTPException e) { - DialogUtil.showErrorDialog(context, e.getMessage() == null ? "An error occurred while refreshing the code" : e.getMessage()); + DialogUtil.showErrorDialog(context, context.getString(R.string.error_otp_refresh), e); } } } diff --git a/app/src/main/java/com/cringe_studios/code_guard/scanner/QRScannerContract.java b/app/src/main/java/com/cringe_studios/code_guard/scanner/QRScannerContract.java index 73cf6f1..bcfd988 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/scanner/QRScannerContract.java +++ b/app/src/main/java/com/cringe_studios/code_guard/scanner/QRScannerContract.java @@ -28,7 +28,10 @@ public class QRScannerContract extends ActivityResultContract { if(binding.unlockPassword.getText().length() == 0) { - DialogUtil.showErrorDialog(this, "You need to enter a password"); + DialogUtil.showErrorDialog(this, getString(R.string.error_unlock_no_password)); return; } @@ -72,9 +73,9 @@ public class UnlockActivity extends BaseActivity { OTPDatabase.loadDatabase(this, key); success(); }catch(CryptoException e) { - DialogUtil.showErrorDialog(this, "Failed to load database: Invalid password or database corrupted", this::failure); + DialogUtil.showErrorDialog(this, getString(R.string.error_unlock_crypto), this::failure); } catch (OTPDatabaseException e) { - DialogUtil.showErrorDialog(this, "Failed to load database: " + e, this::failure); + DialogUtil.showErrorDialog(this, getString(R.string.error_unlock_other), e, this::failure); } }); } diff --git a/app/src/main/java/com/cringe_studios/code_guard/util/DialogUtil.java b/app/src/main/java/com/cringe_studios/code_guard/util/DialogUtil.java index 2a242f3..27c77b2 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/util/DialogUtil.java +++ b/app/src/main/java/com/cringe_studios/code_guard/util/DialogUtil.java @@ -78,13 +78,17 @@ public class DialogUtil { } public static void showErrorDialog(Context context, String errorMessage, Runnable closed) { - showErrorDialog(context, errorMessage, null, closed); + showErrorDialog(context, errorMessage, (String) null, closed); } public static void showErrorDialog(Context context, String errorMessage) { showErrorDialog(context, errorMessage, (Runnable) null); } + public static void showErrorDialog(Context context, String errorMessage, Exception exception, Runnable closed) { + showErrorDialog(context, errorMessage, stackTraceToString(exception), closed); + } + public static void showErrorDialog(Context context, String errorMessage, Exception exception) { showErrorDialog(context, errorMessage, stackTraceToString(exception), null); } diff --git a/app/src/main/java/com/cringe_studios/code_guard/util/NavigationUtil.java b/app/src/main/java/com/cringe_studios/code_guard/util/NavigationUtil.java index df9be39..d31b445 100644 --- a/app/src/main/java/com/cringe_studios/code_guard/util/NavigationUtil.java +++ b/app/src/main/java/com/cringe_studios/code_guard/util/NavigationUtil.java @@ -13,8 +13,6 @@ import com.cringe_studios.code_guard.fragment.NamedFragment; public class NavigationUtil { - // TODO: check if this still works after changes - private static void updateActivity(AppCompatActivity activity, NamedFragment newFragment) { ActionBar bar = activity.getSupportActionBar(); if(newFragment == null) newFragment = (NamedFragment) getCurrentFragment(activity.getSupportFragmentManager()); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02d0fc1..18cab12 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -128,6 +128,33 @@ Icon pack with %d icon(s) imported It is recommended to enable encryption to improve the security of the application.\n\nDo you want to go to the settings now to enable encryption? Enable encryption + Press back again to exit + Database must be encrypted for this option + Manage icon packs + Failed to load backup. Make sure the password is valid + Failed to load backup + Failed to enable biometric encryption + Failed to enable biometric encryption + Choose Image + Failed to open image + Failed to save database + An error occurred while refreshing the code + Failed to enable encryption + Failed to disable encryption + You need to enter a password + Failed to load database: Invalid password or database corrupted + Failed to load database + No codes were detected in the provided image + "Failed to detect code: " + "Failed to read image: " + Icon pack already exists + Failed to import icon pack + + Image from icon pack + Image from gallery + No image + Reset to default image + Override Rename existing