From e46857a26e54765cc82b270b79d761100e412302 Mon Sep 17 00:00:00 2001 From: Alexander Bakker Date: Sun, 7 Aug 2022 20:18:21 +0200 Subject: [PATCH] Add support for importing multiple QR code images in one go This is also part of the preparation needed for scanning Google Authenticator Export QR codes from images. --- .../aegis/helpers/SafHelper.java | 27 +++++ .../aegis/ui/ImportEntriesActivity.java | 37 +------ .../aegis/ui/MainActivity.java | 104 +++++++++++++----- .../aegis/ui/dialogs/Dialogs.java | 75 +++++++++++++ .../aegis/ui/tasks/QrDecodeTask.java | 60 +++++++--- app/src/main/res/values-ar-rSA/strings.xml | 1 - app/src/main/res/values-bg-rBG/strings.xml | 1 - app/src/main/res/values-cs-rCZ/strings.xml | 1 - app/src/main/res/values-da-rDK/strings.xml | 1 - app/src/main/res/values-de-rDE/strings.xml | 1 - app/src/main/res/values-el-rGR/strings.xml | 1 - app/src/main/res/values-es-rES/strings.xml | 1 - app/src/main/res/values-eu-rES/strings.xml | 1 - app/src/main/res/values-fa-rIR/strings.xml | 1 - app/src/main/res/values-fi-rFI/strings.xml | 1 - app/src/main/res/values-fr-rFR/strings.xml | 1 - app/src/main/res/values-hi-rIN/strings.xml | 1 - app/src/main/res/values-hu-rHU/strings.xml | 1 - app/src/main/res/values-in-rID/strings.xml | 1 - app/src/main/res/values-it-rIT/strings.xml | 1 - app/src/main/res/values-ja-rJP/strings.xml | 1 - app/src/main/res/values-kn-rIN/strings.xml | 1 - app/src/main/res/values-lt-rLT/strings.xml | 1 - app/src/main/res/values-lv-rLV/strings.xml | 1 - app/src/main/res/values-nl-rNL/strings.xml | 1 - app/src/main/res/values-pl-rPL/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-pt-rPT/strings.xml | 1 - app/src/main/res/values-ro-rRO/strings.xml | 1 - app/src/main/res/values-ru-rRU/strings.xml | 1 - app/src/main/res/values-tr-rTR/strings.xml | 1 - app/src/main/res/values-uk-rUA/strings.xml | 1 - app/src/main/res/values-vi-rVN/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values-zh-rTW/strings.xml | 1 - app/src/main/res/values/strings.xml | 9 +- 36 files changed, 232 insertions(+), 110 deletions(-) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/helpers/SafHelper.java diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/SafHelper.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/SafHelper.java new file mode 100644 index 00000000..4b6ff8c1 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/SafHelper.java @@ -0,0 +1,27 @@ +package com.beemdevelopment.aegis.helpers; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.provider.OpenableColumns; + +public class SafHelper { + private SafHelper() { + + } + + public static String getFileName(Context context, Uri uri) { + if (uri.getScheme() != null && uri.getScheme().equals("content")) { + try (Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null)) { + if (cursor != null && cursor.moveToFirst()) { + int i = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (i != -1) { + return cursor.getString(i); + } + } + } + } + + return uri.getLastPathSegment(); + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java index f8a1e89e..324652d4 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/ImportEntriesActivity.java @@ -1,11 +1,7 @@ package com.beemdevelopment.aegis.ui; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; import android.content.pm.PackageManager; import android.os.Bundle; -import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; @@ -36,7 +32,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.List; public class ImportEntriesActivity extends AegisActivity { @@ -190,39 +185,11 @@ public class ImportEntriesActivity extends AegisActivity { List errors = result.getErrors(); if (errors.size() > 0) { - showErrorDialog(errors); + String message = getResources().getQuantityString(R.plurals.import_error_dialog, errors.size(), errors.size()); + Dialogs.showMultiErrorDialog(this, R.string.import_error_title, message, errors, null); } } - private void showErrorDialog(List errors) { - Dialogs.showSecureDialog(new AlertDialog.Builder(this) - .setTitle(R.string.import_error_title) - .setMessage(getResources().getQuantityString(R.plurals.import_error_dialog, errors.size(), errors.size())) - .setPositiveButton(android.R.string.ok, null) - .setNeutralButton(getString(R.string.details), (dialog, which) -> showDetailedErrorDialog(errors)) - .create()); - } - - private void showDetailedErrorDialog(List errors) { - List messages = new ArrayList<>(); - for (DatabaseImporterEntryException e : errors) { - messages.add(e.getMessage()); - } - - String message = TextUtils.join("\n\n", messages); - Dialogs.showSecureDialog(new AlertDialog.Builder(this) - .setTitle(R.string.import_error_title) - .setMessage(message) - .setPositiveButton(android.R.string.ok, null) - .setNeutralButton(android.R.string.copy, (dialog2, which2) -> { - ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("text/plain", message); - clipboard.setPrimaryClip(clip); - Toast.makeText(this, R.string.errors_copied, Toast.LENGTH_SHORT).show(); - }) - .create()); - } - private void showWipeEntriesDialog() { Dialogs.showCheckboxDialog(this, R.string.dialog_wipe_entries_title, R.string.dialog_wipe_entries_message, diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java index c03decd2..a860bd5a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -4,10 +4,15 @@ import android.Manifest; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; import android.provider.Settings; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.style.StyleSpan; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; @@ -38,6 +43,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.floatingactionbutton.FloatingActionButton; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeSet; @@ -275,17 +281,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void onScanResult(Intent data) { List entries = (ArrayList) data.getSerializableExtra("entries"); - if (entries.size() == 1) { - startEditEntryActivityForNew(CODE_ADD_ENTRY, entries.get(0)); - } else { - for (VaultEntry entry : entries) { - _vaultManager.getVault().addEntry(entry); - if (_loaded) { - _entryListView.addEntry(entry); - } - } - - saveAndBackupVault(); + if (entries != null) { + importScannedEntries(entries); } } @@ -311,25 +308,78 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene } private void onScanImageResult(Intent intent) { - startDecodeQrCodeImage(intent.getData()); + if (intent.getData() != null) { + startDecodeQrCodeImages(Collections.singletonList(intent.getData())); + return; + } + + if (intent.getClipData() != null) { + ClipData data = intent.getClipData(); + + List uris = new ArrayList<>(); + for (int i = 0; i < data.getItemCount(); i++) { + ClipData.Item item = data.getItemAt(i); + if (item.getUri() != null) { + uris.add(item.getUri()); + } + } + + if (uris.size() > 0) { + startDecodeQrCodeImages(uris); + } + } } - private void startDecodeQrCodeImage(Uri uri) { - QrDecodeTask task = new QrDecodeTask(this, (result) -> { - if (result.getException() != null) { - Dialogs.showErrorDialog(this, R.string.unable_to_read_qrcode, result.getException()); - return; + private static CharSequence buildImportError(String fileName, Throwable e) { + SpannableStringBuilder builder = new SpannableStringBuilder(String.format("%s:\n%s", fileName, e)); + builder.setSpan(new StyleSpan(Typeface.BOLD), 0, fileName.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return builder; + } + + private void startDecodeQrCodeImages(List uris) { + QrDecodeTask task = new QrDecodeTask(this, (results) -> { + List errors = new ArrayList<>(); + List entries = new ArrayList<>(); + for (QrDecodeTask.Result res : results) { + if (res.getException() != null) { + errors.add(buildImportError(res.getFileName(), res.getException())); + continue; + } + + try { + GoogleAuthInfo info = GoogleAuthInfo.parseUri(res.getResult().getText()); + VaultEntry entry = new VaultEntry(info); + entries.add(entry); + } catch (GoogleAuthInfoException e) { + errors.add(buildImportError(res.getFileName(), e)); + } } - try { - GoogleAuthInfo info = GoogleAuthInfo.parseUri(result.getResult().getText()); - VaultEntry entry = new VaultEntry(info); - startEditEntryActivityForNew(CODE_ADD_ENTRY, entry); - } catch (GoogleAuthInfoException e) { - Dialogs.showErrorDialog(this, R.string.unable_to_read_qrcode, e); + final DialogInterface.OnClickListener dialogDismissHandler = (dialog, which) -> importScannedEntries(entries); + if ((errors.size() > 0 && results.size() > 1) || errors.size() > 1) { + Dialogs.showMultiMessageDialog(this, R.string.import_error_title, getString(R.string.unable_to_read_qrcode_files, uris.size() - errors.size(), uris.size()), errors, dialogDismissHandler); + } else if (errors.size() > 0) { + Dialogs.showErrorDialog(this, getString(R.string.unable_to_read_qrcode_file, results.get(0).getFileName()), errors.get(0), dialogDismissHandler); + } else { + importScannedEntries(entries); } }); - task.execute(getLifecycle(), uri); + task.execute(getLifecycle(), uris); + } + + private void importScannedEntries(List entries) { + if (entries.size() == 1) { + startEditEntryActivityForNew(CODE_ADD_ENTRY, entries.get(0)); + } else if (entries.size() > 1) { + for (VaultEntry entry: entries) { + _vaultManager.getVault().addEntry(entry); + _entryListView.addEntry(entry); + } + + if (saveAndBackupVault()) { + Toast.makeText(this, getResources().getQuantityString(R.plurals.added_new_entries, entries.size(), entries.size()), Toast.LENGTH_LONG).show(); + } + } } private void updateSortCategoryMenu() { @@ -368,9 +418,11 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private void startScanImageActivity() { Intent galleryIntent = new Intent(Intent.ACTION_PICK); + galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); galleryIntent.setDataAndType(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*"); Intent fileIntent = new Intent(Intent.ACTION_GET_CONTENT); + fileIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); fileIntent.setType("image/*"); Intent chooserIntent = Intent.createChooser(galleryIntent, getString(R.string.select_picture)); @@ -421,7 +473,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene info = GoogleAuthInfo.parseUri(uri); } catch (GoogleAuthInfoException e) { e.printStackTrace(); - Dialogs.showErrorDialog(this, R.string.unable_to_read_qrcode, e); + Dialogs.showErrorDialog(this, R.string.unable_to_process_deeplink, e); } if (info != null) { @@ -444,7 +496,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene intent.setAction(null); intent.removeExtra(Intent.EXTRA_STREAM); - startDecodeQrCodeImage(uri); + startDecodeQrCodeImages(Collections.singletonList(uri)); } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java index 4171e8da..e7a49f9a 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java @@ -10,6 +10,7 @@ import android.content.res.ColorStateList; import android.graphics.Color; import android.text.Editable; import android.text.InputType; +import android.text.SpannableStringBuilder; import android.text.TextWatcher; import android.text.method.PasswordTransformationMethod; import android.view.LayoutInflater; @@ -24,6 +25,7 @@ import android.widget.ListView; import android.widget.NumberPicker; import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; import androidx.activity.ComponentActivity; import androidx.annotation.StringRes; @@ -44,6 +46,7 @@ import com.google.android.material.textfield.TextInputLayout; import com.nulabinc.zxcvbn.Strength; import com.nulabinc.zxcvbn.Zxcvbn; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -340,6 +343,10 @@ public class Dialogs { showErrorDialog(context, message, e, null); } + public static void showErrorDialog(Context context, String message, Exception e) { + showErrorDialog(context, message, e, null); + } + public static void showErrorDialog(Context context, @StringRes int message, CharSequence error) { showErrorDialog(context, message, error, null); } @@ -348,7 +355,15 @@ public class Dialogs { showErrorDialog(context, message, e.toString(), listener); } + public static void showErrorDialog(Context context, String message, Exception e, DialogInterface.OnClickListener listener) { + showErrorDialog(context, message, e.toString(), listener); + } + public static void showErrorDialog(Context context, @StringRes int message, CharSequence error, DialogInterface.OnClickListener listener) { + showErrorDialog(context, context.getString(message), error, listener); + } + + public static void showErrorDialog(Context context, String message, CharSequence error, DialogInterface.OnClickListener listener) { View view = LayoutInflater.from(context).inflate(R.layout.dialog_error, null); TextView textDetails = view.findViewById(R.id.error_details); textDetails.setText(error); @@ -388,6 +403,66 @@ public class Dialogs { Dialogs.showSecureDialog(dialog); } + public static void showMultiMessageDialog( + Context context, @StringRes int title, String message, List messages, DialogInterface.OnClickListener listener) { + Dialogs.showSecureDialog(new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(message) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, (dialog, which) -> { + if (listener != null) { + listener.onClick(dialog, which); + } + }) + .setNeutralButton(context.getString(R.string.details), (dialog, which) -> { + showDetailedMultiMessageDialog(context, title, messages, listener); + }) + .create()); + } + + public static void showMultiErrorDialog( + Context context, @StringRes int title, String message, List errors, DialogInterface.OnClickListener listener) { + List messages = new ArrayList<>(); + for (Throwable e : errors) { + messages.add(e.toString()); + } + + showMultiMessageDialog(context, title, message, messages, listener); + } + + private static void showDetailedMultiMessageDialog( + Context context, @StringRes int title, List messages, DialogInterface.OnClickListener listener) { + SpannableStringBuilder builder = new SpannableStringBuilder(); + for (CharSequence message : messages) { + builder.append(message); + builder.append("\n\n"); + } + + AlertDialog dialog = new AlertDialog.Builder(context) + .setTitle(title) + .setMessage(builder) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, (dialog1, which) -> { + if (listener != null) { + listener.onClick(dialog1, which); + } + }) + .setNeutralButton(android.R.string.copy, null) + .create(); + + dialog.setOnShowListener(d -> { + Button button = dialog.getButton(AlertDialog.BUTTON_NEUTRAL); + button.setOnClickListener(v -> { + ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("text/plain", builder.toString()); + clipboard.setPrimaryClip(clip); + Toast.makeText(context, R.string.errors_copied, Toast.LENGTH_SHORT).show(); + }); + }); + + Dialogs.showSecureDialog(dialog); + } + public static void showTimeSyncWarningDialog(Context context, Dialog.OnClickListener listener) { Preferences prefs = new Preferences(context); View view = LayoutInflater.from(context).inflate(R.layout.dialog_time_sync, null); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/tasks/QrDecodeTask.java b/app/src/main/java/com/beemdevelopment/aegis/ui/tasks/QrDecodeTask.java index ea23ffa1..61b7af41 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/tasks/QrDecodeTask.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/tasks/QrDecodeTask.java @@ -5,12 +5,14 @@ import android.net.Uri; import com.beemdevelopment.aegis.R; import com.beemdevelopment.aegis.helpers.QrCodeHelper; -import com.google.zxing.Result; +import com.beemdevelopment.aegis.helpers.SafHelper; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; -public class QrDecodeTask extends ProgressDialogTask { +public class QrDecodeTask extends ProgressDialogTask, List> { private final Callback _cb; public QrDecodeTask(Context context, Callback cb) { @@ -19,39 +21,61 @@ public class QrDecodeTask extends ProgressDialogTask } @Override - protected Response doInBackground(Uri... params) { + protected List doInBackground(List... params) { + List res = new ArrayList<>(); Context context = getDialog().getContext(); - Uri uri = params[0]; - try (InputStream inStream = context.getContentResolver().openInputStream(uri)) { - Result result = QrCodeHelper.decodeFromStream(inStream); - return new Response(result, null); - } catch (QrCodeHelper.DecodeError | IOException e) { - e.printStackTrace(); - return new Response(null, e); + List uris = params[0]; + for (Uri uri : uris) { + String fileName = SafHelper.getFileName(context, uri); + if (uris.size() > 1) { + publishProgress(context.getString(R.string.analyzing_qr_multiple, uris.indexOf(uri) + 1, uris.size(), fileName)); + } + + try (InputStream inStream = context.getContentResolver().openInputStream(uri)) { + com.google.zxing.Result result = QrCodeHelper.decodeFromStream(inStream); + res.add(new Result(uri, fileName, result, null)); + } catch (QrCodeHelper.DecodeError | IOException e) { + e.printStackTrace(); + res.add(new Result(uri, fileName, null, e)); + } } + + return res; } @Override - protected void onPostExecute(Response result) { - super.onPostExecute(result); - _cb.onTaskFinished(result); + protected void onPostExecute(List results) { + super.onPostExecute(results); + _cb.onTaskFinished(results); } public interface Callback { - void onTaskFinished(Response result); + void onTaskFinished(List results); } - public static class Response { - private final Result _result; + public static class Result { + private final Uri _uri; + private final String _fileName; + private final com.google.zxing.Result _result; private final Exception _e; - public Response(Result result, Exception e) { + public Result(Uri uri, String fileName, com.google.zxing.Result result, Exception e) { + _uri = uri; + _fileName = fileName; _result = result; _e = e; } - public Result getResult() { + public Uri getUri() { + return _uri; + } + + public String getFileName() { + return _fileName; + } + + public com.google.zxing.Result getResult() { return _result; } diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index 76124ef3..62cbd570 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -201,7 +201,6 @@ صغير مصدِّر غير معروف اسم الحساب غير معروف - تعذّر قراءة ومعالجة كود QR تعذّر توليد كود QR اختر صورة اختر أيقونة diff --git a/app/src/main/res/values-bg-rBG/strings.xml b/app/src/main/res/values-bg-rBG/strings.xml index 6d3bad57..32f3a0d2 100644 --- a/app/src/main/res/values-bg-rBG/strings.xml +++ b/app/src/main/res/values-bg-rBG/strings.xml @@ -226,7 +226,6 @@ Aegis не можа да импортира %d токен. Тези токени ще бъдат пропуснати. Натиснете „подробности“, за да видите повече информация за грешките. Aegis не можа да импортира %d токена. Тези токени ще бъдат пропуснати. Натиснете „подробности“, за да видите повече информация за грешките. - Не може да се прочете и обработи QR код Не може да се генерира QR код Изберете картина Изберете икона diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 65f105f4..e24bf02c 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -231,7 +231,6 @@ Malý Neznámý poskytovatel Neznámý název účtu - QR kód nelze přečíst a zpracovat QR kód nelze vygenerovat Vyberte obrázek Vybrat ikonu diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index b4339460..84849e0c 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -251,7 +251,6 @@ Aegis kunne ikke importere %d token. Disse tokens vil blive sprunget over. Tryk \'detaljer\' for at se mere information om fejlene. Aegis kunne ikke importere %d tokens. Disse tokens vil blive sprunget over. Tryk \'detaljer\' for at se mere information om fejlene. - Kan ikke læse og behandle QR-kode Kan ikke generere QR-kode Vælg billede Vælg ikon diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 9dc096bc..c53fb358 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -251,7 +251,6 @@ Aegis konnte %d Token nicht importieren. Dieser Token wird übersprungen. Klicke auf Details, um weitere Informationen über die Fehler zu erhalten. Aegis konnte %d Token nicht importieren. Diese Token werden übersprungen. Klicke auf Details, um weitere Informationen über die Fehler zu erhalten. - QR-Code kann nicht gelesen und verarbeitet werden QR-Code kann nicht generiert werden Bild auswählen Symbol auswählen diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 4bfa152c..d600f5b9 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -251,7 +251,6 @@ Το Aegis δεν μπόρεσε να εισαγάγει %d αναγνωριστικό. Αυτά θα παραληφθούν. Πατήστε \'Λεπτομέρειες\' για να δείτε περισσότερες πληροφορίες σχετικά με τα σφάλματα. Το Aegis δεν μπόρεσε να εισαγάγει %d αναγνωριστικά. Αυτά θα παραληφθούν. Πατήστε \'Λεπτομέρειες\' για να δείτε περισσότερες πληροφορίες σχετικά με τα σφάλματα. - Αδυναμία ανάγνωσης και επεξεργασίας κωδικού QR Δεν είναι δυνατή η δημιουργία κωδικού QR Επιλέξτε εικόνα Επιλέξτε εικονίδιο diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 5c90f178..88c811ed 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -250,7 +250,6 @@ Aegis no pudo importar %d tokens. Estos tokens se omitirán. Pulse \'detalles\' para ver más información sobre los errores. Aegis no pudo importar %d tokens. Estos tokens se omitirán. Pulse \'detalles\' para ver más información sobre los errores. - No se puede leer y procesar el código QR No se puede generar el código QR Seleccionar imagen Seleccionar icono diff --git a/app/src/main/res/values-eu-rES/strings.xml b/app/src/main/res/values-eu-rES/strings.xml index 8af7a6b1..4bac6a45 100644 --- a/app/src/main/res/values-eu-rES/strings.xml +++ b/app/src/main/res/values-eu-rES/strings.xml @@ -248,7 +248,6 @@ Aegisek ezin izan du %d token inportatu. Token hori kendu egingo da. Sakatu \'Xehetasunak\' akatsei buruzko informazio gehiago ikusteko. Aegisek ezin izan du %d token inportatu. Token horiek kendu egingo dira. Sakatu \'Xehetasunak\' akatsei buruzko informazio gehiago ikusteko. - Ez da gai QR kodea irakurtzeko eta prozesatzeko Ezin da QR kodea sortu Aukeratu irudia Aukeratu ikonoa diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml index 3dbebe97..4148bd11 100644 --- a/app/src/main/res/values-fa-rIR/strings.xml +++ b/app/src/main/res/values-fa-rIR/strings.xml @@ -222,7 +222,6 @@ %d توکن اضافه نشدند. برای اطلاعات بیشتر از دکمه جزییات استفاده نمایید. %d توکن اضافه نشدند. برای اطلاعات بیشتر از دکمه جزییات استفاده نمایید. - عدم توانایی در خواندن و پردازش بارکد دوبعدی عدم توانایی در ساخت بارکد دوبعدی انتخاب تصویر انتخاب آیکون diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 83cb1479..c72d796e 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -239,7 +239,6 @@ Aegis ei voinut tuoda %d tunnusta. Nämä tunnukset ohitetaan. Paina \'tiedot\' nähdäksesi lisätietoa virheistä. Aegis ei voinut tuoda %d tunnusta. Nämä tunnukset ohitetaan. Paina \'tiedot\' nähdäksesi lisätietoa virheistä. - QR-koodia ei voi lukea ja käsitellä QR-koodia ei voitu luoda Valitse kuva Valitse kuvake diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 8434dbbc..fe073bd7 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -251,7 +251,6 @@ Aegis n\'a pas pu importer %d jeton. Ce jeton sera ignoré. Appuyez sur « détails» pour voir plus d\'informations sur les erreurs. Aegis n\'a pas pu importer %d jetons. Ces jetons seront ignorés. Appuyez sur \'details\' pour voir plus d\'informations sur les erreurs. - Impossible de lire et traiter le code QR Impossible de générer le code QR Sélectionner image Sélectionner une icône diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index d46b5e61..104c931d 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -188,7 +188,6 @@ Aegis %d टोकन आयात नहीं कर सका। इन टोकन को छोड़ दिया जाएगा। त्रुटियों के बारे में अधिक जानकारी देखने के लिए \'विवरण\' दबाएँ। Aegis %d टोकनों को आयात नहीं कर सका। इन टोकनों को छोड़ दिया जाएगा। त्रुटियों के बारे में अधिक जानकारी देखने के लिए \'विवरण\' दबाएँ। - क्यूआर कोड को पढ़ने और प्रोसेस करने में असमर्थ क्यूआर कोड उत्पन्न करने में असमर्थ छवि चयन करें आइकन चयन करें diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 7a727b8c..b29a592b 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -147,7 +147,6 @@ Apró Ismeretlen kibocsátó Ismeretlen fióknév - A QR-kód nem olvasható be és dolgozható fel Válasszon képet Jelölőmezők be/ki Keresés diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index 01a398ba..46d4e0f6 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -243,7 +243,6 @@ Aegis tidak dapat mengimpor %d token. Token ini akan dilewati. Tekan \'detail\' untuk melihat informasi lebih lanjut tentang kesalahan tersebut. - Tidak dapat membaca dan memproses kode QR Tidak dapat membuat kode QR Pilih gambar Pilih ikon diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 22976849..a2dc2a44 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -251,7 +251,6 @@ Aegis non può importare %d token. Questi token verranno saltati. Premi \'dettagli\' per vedere ulteriori informazioni sugli errori. Aegis non può importare %d token. Questi token verranno saltati. Premi \'dettagli\' per vedere ulteriori informazioni sugli errori. - Impossibile verificare il codice QR Impossibile generare il codice QR Seleziona immagine Seleziona icona diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 3de4fa6f..2d5ee7ed 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -243,7 +243,6 @@ Aegisは %d 個のトークンをインポートできませんでした。これらのトークンはスキップされます。エラーの詳細を見るには「詳細」を押してください。 - QRコードを読み取りできません QRコードを生成できません 画像を選択 アイコンを選択 diff --git a/app/src/main/res/values-kn-rIN/strings.xml b/app/src/main/res/values-kn-rIN/strings.xml index 6132ffd1..f29218e7 100644 --- a/app/src/main/res/values-kn-rIN/strings.xml +++ b/app/src/main/res/values-kn-rIN/strings.xml @@ -101,7 +101,6 @@ ಸಣ್ಣ ಗೊತ್ತಿಲ್ಲದಿರುವ ನೀಡುವವರು ಗೊತ್ತಿಲ್ಲದಿರುವ ಖಾತೆಯ ಹೆಸರು - ಕ್ಯೂ ಆರ್ ಸಂಕೇತವನ್ನು ಓದವುದಕ್ಕೆ ಹಾಗು ಪ್ರಕ್ರಿಯಿಸುವುದಕ್ಕೆ ಸಾಧ್ಯವಾಗಲಿಲ್ಲ ಚಿತ್ರವನ್ನು ಆಯ್ಕೆ ಮಾಡು ಚೆಕ್ಬಾಕ್ಸ್ಗಳನ್ನು ಟಾಗಲ್ ಮಾಡು ಹುಡುಕು diff --git a/app/src/main/res/values-lt-rLT/strings.xml b/app/src/main/res/values-lt-rLT/strings.xml index 3c041275..70e9ddf3 100644 --- a/app/src/main/res/values-lt-rLT/strings.xml +++ b/app/src/main/res/values-lt-rLT/strings.xml @@ -179,7 +179,6 @@ Kompaktiška Maža Nežinomas leidėjas - Nepavyko perskaityti ir apdoroti QR kodo Nepavyko sukurti QR kodo Slėptuvė atrakinta. Bakstelėkite čia, norėdami užrakinti. Versija diff --git a/app/src/main/res/values-lv-rLV/strings.xml b/app/src/main/res/values-lv-rLV/strings.xml index 485e6498..e6a8546c 100644 --- a/app/src/main/res/values-lv-rLV/strings.xml +++ b/app/src/main/res/values-lv-rLV/strings.xml @@ -256,7 +256,6 @@ Aegis nevarēja ievietot %d kodu. Tas tiks izlaists. Spiest uz \"Izklāsts\", lai redzētu vairāk informācijas par kļūdām. Aegis nevarēja ievietot %d kodus. Tie tiks izlaisti. Spiest uz \"Izklāsts\", lai redzētu vairāk informācijas par kļūdām. - Nav iespējams nolasīt un apstrādāt kvadrātkodu Nav iespējams izveidot kvadrātkodu Atlasīt attēlu Atlasīt ikonu diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index 4d0f325f..493b4074 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -251,7 +251,6 @@ Aegis kon %d token niet importeren. Dit token zal worden overgeslagen. Druk op \'details\' om meer informatie over de fouten te zien. Aegis kon %d tokens niet importeren. Deze tokens zullen worden overgeslagen. Druk op \'details\' om meer informatie over de fouten te zien. - Kan QR-code niet lezen en verwerken Kan de QR-code niet genereren Foto selecteren Icoon selecteren diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 2070fd66..d8f94cb6 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -252,7 +252,6 @@ Aplikacja Aegis nie może zaimportować %d tokenów. Te tokeny zostaną pominięte. Kliknij \'Szczegóły\', aby zobaczyć więcej informacji o błędach. Aplikacja Aegis nie może zaimportować %d tokenów. Te tokeny zostaną pominięte. Kliknij \'Szczegóły\', aby zobaczyć więcej informacji o błędach. - Nie można odczytać i przetworzyć kodu QR Nie udało się wygenerować kodu QR Wybierz obraz Wybierz ikonę diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index f500cf1f..3fbf66e6 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -251,7 +251,6 @@ Aegis não pôde importar %d token. Esse token será ignorado. Pressione \'detalhes\' para ver mais informações sobre o erro. Aegis não pôde importar %d tokens. Esses tokens serão pulados. Pressione \'detalhes\' para ver mais informações sobre os erros. - Não foi possível ler e processar o QR code Não foi possível gerar o QR code Selecionar imagem Selecionar ícone diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 984aa9da..a67f1230 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -197,7 +197,6 @@ Aegis não pôde importar %d token. Esse token será ignorado. Pressione \'detalhes\' para ver mais informações sobre o erro. Aegis não pôde importar %d tokens. Esses tokens serão pulados. Pressione \'detalhes\' para ver mais informações sobre os erros. - Incapaz de ler e processar o código QR Não foi possível gerar o código QR Selecionar imagem Selecionar ícone diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index 350bb950..dfa3be78 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -256,7 +256,6 @@ Aegis nu a putut importa %d token. Aceste token-uri vor fi sărite. Apăsați \'detalii\' pentru a vedea mai multe informații despre erori. Aegis nu a putut importa %d token-rui. Aceste token-uri vor fi sărite. Apăsați \'detalii\' pentru a vedea mai multe informații despre erori. - Nu se poate citi și prelucra codul QR Nu se poate genera codul QR Selectare imagine Selectare pictogramă diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 84da67d1..7881c75e 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -261,7 +261,6 @@ Aegis не удалось импортировать %d ключей. Эти ключи будут пропущены. Нажмите «Подробнее», чтобы увидеть дополнительную информацию об ошибках. Aegis не удалось импортировать %d ключей. Эти ключи будут пропущены. Нажмите «Подробнее», чтобы увидеть дополнительную информацию об ошибках. - Не удалось прочитать и обработать QR-код Не удаётся сгенерировать QR-код Выберите изображение Выберите значок diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index e7af6443..21f1d7c7 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -249,7 +249,6 @@ Aegis %d kodunu içe aktaramadı. Bu kodlar atlanacaktır. Hatalar hakkında daha detaylı bilgi için lütfen \'ayrıntılar\'a basınız. Aegis %d kodunu içe aktaramadı. Bu kodlar atlanacaktır. Hatalar hakkında daha detaylı bilgi için lütfen \'ayrıntılar\'a basınız. - QR kod okunamadı ve işlenemedi QR Kodu oluşturulamadı Resim seç Simge seç diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index 5bb6a56c..4252cac2 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -234,7 +234,6 @@ Aegis не вдалося імпортувати %d токенів. Ці токени буде пропущено. Натисніть \'деталі\', щоб побачити більше інформації про помилки. Aegis не вдалося імпортувати %d токенів. Ці токени буде пропущено. Натисніть \'деталі\', щоб побачити більше інформації про помилки. - Не вдається прочитати і обробити QR-код Не вдається згенерувати QR-код Виберіть зображення Виберіть іконку diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index 05efc404..a82e3852 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -246,7 +246,6 @@ Aegis không thể nhập %d token. Các token đó sẽ bị bỏ qua. Hãy nhấn \'Chi tiết\' để xem thêm thông tin về các lỗi. - Không thể đọc và xử lý mã QR Không thể tạo mã QR Chọn ảnh Chọn biểu tượng diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 7ae7ec7b..7bd609f1 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -246,7 +246,6 @@ Aegis 无法导入 %d 个令牌。这些令牌将被忽略。点击“详细信息”查看更多关于错误的信息。 - 无法读取和处理二维码 无法生成二维码 选择图片 选择图标 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index c5f5c1c1..ad8e8d81 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -211,7 +211,6 @@ Aegis 已忽略無法匯入的 %d 個憑證。如欲了解更詳細的錯誤訊息,請按「詳細內容」。 - 無法讀取和處理QR碼 無法生成QR碼 選擇圖片 選擇圖示 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 90a77022..b8be0cea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -158,6 +158,11 @@ Exporting the vault Reading file Analyzing QR code + Analyzing QR code %d/%d (%s) + + Added %d new entry to the vault + Added %d new entries to the vault + Importing icon pack Delete entry Are you sure you want to delete this entry? @@ -282,7 +287,9 @@ Aegis could not import %d token. These tokens will be skipped. Press \'details\' to see more information about the errors. Aegis could not import %d tokens. These tokens will be skipped. Press \'details\' to see more information about the errors. - Unable to read and process QR code + Unable to process deep link + Unable to read and process QR code from file: %s. + Unable to read and process some of the QR codes. Only %d/%d entries will be imported. Unable to generate QR code Select picture Select icon