diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b1c5a0f1..1d358590 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,58 +3,57 @@ xmlns:tools="http://schemas.android.com/tools" package="com.beemdevelopment.aegis"> - + - - + + + tools:ignore="GoogleAppIndexingWarning" + tools:replace="android:theme"> + - - + + + - + android:theme="@style/AppTheme.Fullscreen" /> - + android:theme="@style/AppTheme.NoActionBar" /> - - - - - + android:name=".ui.IntroActivity" + android:theme="@style/Theme.Intro" /> + + - + android:theme="@style/AppTheme.TransparentActionBar" /> - + android:theme="@style/AppTheme.TransparentActionBar" /> - + + \ No newline at end of file diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/FabScrollHelper.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/FabScrollHelper.java new file mode 100644 index 00000000..b703ba01 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/FabScrollHelper.java @@ -0,0 +1,49 @@ +package com.beemdevelopment.aegis.helpers; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.view.View; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import com.getbase.floatingactionbutton.FloatingActionsMenu; + +public class FabScrollHelper { + private View _fabMenu; + private boolean _isAnimating; + + public FabScrollHelper(View floatingActionsMenu) { + _fabMenu = floatingActionsMenu; + } + + public void onScroll(int dx, int dy) { + if (dy > 0 && _fabMenu.getVisibility() == View.VISIBLE && !_isAnimating) { + _isAnimating = true; + CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) _fabMenu.getLayoutParams(); + int fabBottomMargin = lp.bottomMargin; + _fabMenu.animate() + .translationY(_fabMenu.getHeight() + fabBottomMargin) + .setInterpolator(new AccelerateInterpolator(2)) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + _isAnimating = false; + _fabMenu.setVisibility(View.INVISIBLE); + super.onAnimationEnd(animation); + } + }).start(); + } else if (dy < 0 && _fabMenu.getVisibility() != View.VISIBLE && !_isAnimating) { + _fabMenu.setVisibility(View.VISIBLE); + _fabMenu.animate() + .translationY(0) + .setInterpolator(new DecelerateInterpolator(2)) + .setListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + _isAnimating = false; + super.onAnimationEnd(animation); + } + }).start(); + } + } +} 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 e6957393..23ed1904 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/MainActivity.java @@ -30,6 +30,7 @@ import com.beemdevelopment.aegis.db.DatabaseEntry; import com.beemdevelopment.aegis.db.DatabaseFileCredentials; import com.beemdevelopment.aegis.db.DatabaseManager; import com.beemdevelopment.aegis.db.DatabaseManagerException; +import com.beemdevelopment.aegis.helpers.FabScrollHelper; import com.beemdevelopment.aegis.helpers.PermissionHelper; import com.beemdevelopment.aegis.otp.GoogleAuthInfo; import com.beemdevelopment.aegis.otp.GoogleAuthInfoException; @@ -79,7 +80,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene private FloatingActionsMenu _fabMenu; private EntryListView _entryListView; - private boolean _isAnimating; + private FabScrollHelper _fabScrollHelper; @Override protected void onCreate(Bundle savedInstanceState) { @@ -118,6 +119,8 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene _fabMenu.collapse(); startScanActivity(); }); + + _fabScrollHelper = new FabScrollHelper(_fabMenu); } @Override @@ -622,33 +625,6 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene @Override public void onScroll(int dx, int dy) { - if (dy > 0 && _fabMenu.getVisibility() == View.VISIBLE && !_isAnimating) { - _isAnimating = true; - CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) _fabMenu.getLayoutParams(); - int fabBottomMargin = lp.bottomMargin; - _fabMenu.animate() - .translationY(_fabMenu.getHeight() + fabBottomMargin) - .setInterpolator(new AccelerateInterpolator(2)) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - _isAnimating = false; - _fabMenu.setVisibility(View.INVISIBLE); - super.onAnimationEnd(animation); - } - }).start(); - } else if (dy < 0 && _fabMenu.getVisibility() != View.VISIBLE && !_isAnimating) { - _fabMenu.setVisibility(View.VISIBLE); - _fabMenu.animate() - .translationY(0) - .setInterpolator(new DecelerateInterpolator(2)) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - _isAnimating = false; - super.onAnimationEnd(animation); - } - }).start(); - } + _fabScrollHelper.onScroll(dx, dy); } } diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java index 7eb82b2a..8dba38bb 100644 --- a/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/PreferencesFragment.java @@ -2,15 +2,11 @@ package com.beemdevelopment.aegis.ui; import android.Manifest; import android.app.Activity; -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Bundle; -import android.text.TextUtils; import android.view.Window; import android.view.WindowManager; import android.widget.Toast; @@ -42,7 +38,6 @@ import com.beemdevelopment.aegis.importers.DatabaseImporterException; import com.beemdevelopment.aegis.importers.DatabaseImporterResult; import com.beemdevelopment.aegis.ui.preferences.SwitchPreference; import com.beemdevelopment.aegis.util.ByteInputStream; -import com.google.android.material.snackbar.Snackbar; import com.takisoft.preferencex.PreferenceFragmentCompat; import com.topjohnwu.superuser.Shell; @@ -52,7 +47,6 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; @@ -67,6 +61,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat { private static final int CODE_IMPORT_DECRYPT = 1; private static final int CODE_SLOTS = 2; private static final int CODE_GROUPS = 3; + private static final int CODE_SELECT_ENTRIES = 4; // permission request codes private static final int CODE_PERM_IMPORT = 0; @@ -382,6 +377,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat { break; case CODE_GROUPS: onGroupManagerResult(resultCode, data); + case CODE_SELECT_ENTRIES: + onSelectEntriesResult(resultCode, data); break; } } @@ -524,44 +521,10 @@ public class PreferencesFragment extends PreferenceFragmentCompat { List entries = result.getEntries(); List errors = result.getErrors(); - for (DatabaseEntry entry : entries) { - // temporary: randomize the UUID of duplicate entries and add them anyway - if (_db.getEntryByUUID(entry.getUUID()) != null) { - entry.resetUUID(); - } - - _db.addEntry(entry); - } - - if (!saveDatabase()) { - return; - } - - _result.putExtra("needsRecreate", true); - - Snackbar bar = Snackbar.make(getView(), String.format(Locale.getDefault(), getString(R.string.imported_entries_count), entries.size(), errors.size()), Snackbar.LENGTH_LONG); - if (errors.size() > 0) { - bar.setAction(R.string.details, v -> { - List messages = new ArrayList<>(); - for (DatabaseImporterEntryException e : errors) { - messages.add(e.getMessage()); - } - - String message = TextUtils.join("\n\n", messages); - Dialogs.showSecureDialog(new AlertDialog.Builder(getActivity()) - .setTitle(R.string.import_error_title) - .setMessage(message) - .setPositiveButton(android.R.string.ok, null) - .setNeutralButton(android.R.string.copy, (dialog, which) -> { - ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE); - ClipData clip = ClipData.newPlainText("text/plain", message); - clipboard.setPrimaryClip(clip); - Toast.makeText(getActivity(), getString(R.string.errors_copied), Toast.LENGTH_SHORT).show(); - }) - .create()); - }); - } - bar.show(); + Intent intent = new Intent(getActivity(), SelectEntriesActivity.class); + intent.putExtra("entries", (ArrayList) entries); + intent.putExtra("errors", (ArrayList) errors); + startActivityForResult(intent, CODE_SELECT_ENTRIES); } private void onExport() { @@ -628,6 +591,31 @@ public class PreferencesFragment extends PreferenceFragmentCompat { } } + private void onSelectEntriesResult(int resultCode, Intent data) { + if (resultCode != Activity.RESULT_OK) { + return; + } + + List entries = (ArrayList) data.getSerializableExtra("entries"); + for (DatabaseEntry entry : entries) { + // temporary: randomize the UUID of duplicate entries and add them anyway + if (_db.getEntryByUUID(entry.getUUID()) != null) { + entry.resetUUID(); + } + + _db.addEntry(entry); + } + + if (!saveDatabase()) { + return; + } + + String toastMessage = getResources().getString(R.string.imported_entries_count, entries.size()); + Toast.makeText(getContext(), toastMessage, Toast.LENGTH_SHORT).show(); + + _result.putExtra("needsRecreate", true); + } + private boolean saveDatabase() { try { _db.save(); diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/SelectEntriesActivity.java b/app/src/main/java/com/beemdevelopment/aegis/ui/SelectEntriesActivity.java new file mode 100644 index 00000000..ab285cf2 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/SelectEntriesActivity.java @@ -0,0 +1,138 @@ +package com.beemdevelopment.aegis.ui; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.widget.Toast; + +import com.beemdevelopment.aegis.R; +import com.beemdevelopment.aegis.db.DatabaseEntry; +import com.beemdevelopment.aegis.helpers.FabScrollHelper; +import com.beemdevelopment.aegis.importers.DatabaseImporterEntryException; +import com.beemdevelopment.aegis.ui.models.ImportEntry; +import com.beemdevelopment.aegis.ui.views.ImportEntriesAdapter; +import com.getbase.floatingactionbutton.FloatingActionButton; + +import java.util.ArrayList; +import java.util.List; + +public class SelectEntriesActivity extends AegisActivity { + private ImportEntriesAdapter _adapter; + private FabScrollHelper _fabScrollHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_select_entries); + + ActionBar bar = getSupportActionBar(); + bar.setHomeAsUpIndicator(R.drawable.ic_close); + bar.setDisplayHomeAsUpEnabled(true); + + _adapter = new ImportEntriesAdapter(); + RecyclerView entriesView = findViewById(R.id.list_entries); + entriesView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + onScroll(dx, dy); + } + }); + + LinearLayoutManager layoutManager = new LinearLayoutManager(this); + entriesView.setLayoutManager(layoutManager); + entriesView.setAdapter(_adapter); + entriesView.setNestedScrollingEnabled(false); + + Intent intent = getIntent(); + List entries = (ArrayList) intent.getSerializableExtra("entries"); + List errors = (ArrayList) intent.getSerializableExtra("errors"); + + for (DatabaseEntry entry : entries) { + ImportEntry importEntry = new ImportEntry(entry); + _adapter.addEntry(importEntry); + } + + if (errors.size() > 0) { + showErrorDialog(errors); + } + + FloatingActionButton fabMenu = findViewById(R.id.fab); + fabMenu.setOnClickListener(v -> returnSelectedEntries()); + _fabScrollHelper = new FabScrollHelper(fabMenu); + } + + private void showErrorDialog(List errors) { + Dialogs.showSecureDialog(new AlertDialog.Builder(this) + .setTitle(R.string.import_error_title) + .setMessage(getString(R.string.import_error_dialog, 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) this.getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText("text/plain", message); + clipboard.setPrimaryClip(clip); + Toast.makeText(this, getString(R.string.errors_copied), Toast.LENGTH_SHORT).show(); + }) + .create()); + } + + private void returnSelectedEntries() { + List entries = _adapter.getSelectedEntries(); + Intent intent = new Intent(); + intent.putExtra("entries", (ArrayList) entries); + setResult(RESULT_OK, intent); + finish(); + } + + public void onScroll(int dx, int dy) { + _fabScrollHelper.onScroll(dx, dy); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_select_entries, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + break; + case R.id.toggle_checkboxes: + _adapter.toggleCheckboxes(); + break; + default: + return super.onOptionsItemSelected(item); + } + + return true; + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/models/ImportEntry.java b/app/src/main/java/com/beemdevelopment/aegis/ui/models/ImportEntry.java new file mode 100644 index 00000000..eaa75248 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/models/ImportEntry.java @@ -0,0 +1,37 @@ +package com.beemdevelopment.aegis.ui.models; + +import com.beemdevelopment.aegis.db.DatabaseEntry; + +public class ImportEntry { + private DatabaseEntry _entry; + private boolean _isChecked = true; + private Listener _listener; + + public ImportEntry(DatabaseEntry entry) { + _entry = entry; + } + + public void setOnCheckedChangedListener(Listener listener) { + _listener = listener; + } + + public DatabaseEntry getDatabaseEntry() { + return _entry; + } + + public boolean isChecked() { + return _isChecked; + } + + public void setIsChecked(boolean isChecked) { + _isChecked = isChecked; + + if (_listener != null) { + _listener.onCheckedChanged(_isChecked); + } + } + + public interface Listener { + void onCheckedChanged(boolean value); + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntriesAdapter.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntriesAdapter.java new file mode 100644 index 00000000..f7acff60 --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntriesAdapter.java @@ -0,0 +1,97 @@ +package com.beemdevelopment.aegis.ui.views; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import com.beemdevelopment.aegis.R; +import com.beemdevelopment.aegis.db.DatabaseEntry; +import com.beemdevelopment.aegis.ui.models.ImportEntry; + +import java.util.ArrayList; +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class ImportEntriesAdapter extends RecyclerView.Adapter { + private List _entries; + + public ImportEntriesAdapter() { + _entries = new ArrayList<>(); + } + + public void addEntry(ImportEntry entry) { + _entries.add(entry); + + int position = getItemCount() - 1; + if (position == 0) { + notifyDataSetChanged(); + } else { + notifyItemInserted(position); + } + } + + @NonNull + @Override + public ImportEntryHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_import_entry, parent, false); + return new ImportEntryHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ImportEntryHolder holder, int position) { + ImportEntry entry = _entries.get(position); + entry.setOnCheckedChangedListener(holder); + holder.setData(entry); + } + + @Override + public void onViewRecycled(@NonNull ImportEntryHolder holder) { + holder.getEntry().setOnCheckedChangedListener(null); + } + + @Override + public int getItemCount() { + return _entries.size(); + } + + public List getSelectedEntries() { + List entries = new ArrayList<>(); + + for (ImportEntry entry : getCheckedEntries()) { + entries.add(entry.getDatabaseEntry()); + } + + return entries; + } + + private List getCheckedEntries() { + List entries = new ArrayList<>(); + + for (ImportEntry entry : _entries) { + if (entry.isChecked()) { + entries.add(entry); + } + } + + return entries; + } + + public void toggleCheckboxes() { + int checkedEntries = getCheckedEntries().size(); + if (checkedEntries == 0 || checkedEntries != _entries.size()) { + setCheckboxStates(true); + } else { + setCheckboxStates(false); + } + } + + private void setCheckboxStates(boolean checked) { + for (ImportEntry entry: _entries) { + if (entry.isChecked() != checked) { + entry.setIsChecked(checked); + } + } + } +} diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntryHolder.java b/app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntryHolder.java new file mode 100644 index 00000000..4e8f85cc --- /dev/null +++ b/app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntryHolder.java @@ -0,0 +1,48 @@ +package com.beemdevelopment.aegis.ui.views; + +import android.content.Context; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import com.beemdevelopment.aegis.R; +import com.beemdevelopment.aegis.db.DatabaseEntry; +import com.beemdevelopment.aegis.ui.models.ImportEntry; + +import androidx.recyclerview.widget.RecyclerView; + +public class ImportEntryHolder extends RecyclerView.ViewHolder implements ImportEntry.Listener { + private TextView _issuer; + private TextView _accountName; + private CheckBox _checkbox; + + private ImportEntry _entry; + + public ImportEntryHolder(final View view) { + super(view); + + _issuer = view.findViewById(R.id.profile_issuer); + _accountName = view.findViewById(R.id.profile_account_name); + _checkbox = view.findViewById(R.id.checkbox_import_entry); + view.setOnClickListener(v -> _entry.setIsChecked(!_entry.isChecked())); + } + + public void setData(ImportEntry entry) { + _entry = entry; + + Context context = itemView.getContext(); + DatabaseEntry dbEntry = entry.getDatabaseEntry(); + _issuer.setText(!dbEntry.getIssuer().isEmpty() ? dbEntry.getIssuer() : context.getString(R.string.unknown_issuer)); + _accountName.setText(!dbEntry.getName().isEmpty() ? dbEntry.getName() : context.getString(R.string.unknown_account_name)); + _checkbox.setChecked(entry.isChecked()); + } + + public ImportEntry getEntry() { + return _entry; + } + + @Override + public void onCheckedChanged(boolean value) { + _checkbox.setChecked(value); + } +} diff --git a/app/src/main/res/drawable/ic_check_black_24dp.xml b/app/src/main/res/drawable/ic_check_black_24dp.xml index 3c728c59..d986bb97 100644 --- a/app/src/main/res/drawable/ic_check_black_24dp.xml +++ b/app/src/main/res/drawable/ic_check_black_24dp.xml @@ -1,9 +1,5 @@ - - + + diff --git a/app/src/main/res/drawable/ic_done_all_black_24dp.xml b/app/src/main/res/drawable/ic_done_all_black_24dp.xml new file mode 100644 index 00000000..dfe4814d --- /dev/null +++ b/app/src/main/res/drawable/ic_done_all_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/activity_select_entries.xml b/app/src/main/res/layout/activity_select_entries.xml new file mode 100644 index 00000000..16fa06b9 --- /dev/null +++ b/app/src/main/res/layout/activity_select_entries.xml @@ -0,0 +1,33 @@ + + + + + + + + diff --git a/app/src/main/res/layout/card_import_entry.xml b/app/src/main/res/layout/card_import_entry.xml new file mode 100644 index 00000000..9418380e --- /dev/null +++ b/app/src/main/res/layout/card_import_entry.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/menu_select_entries.xml b/app/src/main/res/menu/menu_select_entries.xml new file mode 100644 index 00000000..fc644310 --- /dev/null +++ b/app/src/main/res/menu/menu_select_entries.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index b6e51389..10af584e 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -109,7 +109,7 @@ Fout: Bestand niet gevonden Er is een fout opgetreden tijdens het lezen van het bestand Fout: Er kon geen root-access verkregen worden - %d items geïmporteerd. %d fouten. + %d items geïmporteerd Er zijn fouten opgetreden tijdens het importeren Er is een fout opgetreden tijdens het exporteren van de database De database is geëxporteerd naar: diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 02c25d90..242cce7e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -108,7 +108,7 @@ Ошибка: файл не найден Произошла ошибка при попытке прочитать файл Ошибка: невозможно получить root-доступ - Импортироаано %d записей. %d ошибки. + Импортироаано %d записей Произошла ошибка при попытке экспорта базы данных База данных была экспортирована в: Это действие экспортирует базу данных из личного хранилища Aegis. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2e836c7a..5c4b946e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -114,7 +114,8 @@ Error: File not found An error occurred while trying to read the file Error: unable to obtain root access - Imported %d entries. %d errors. + Imported %d entries + Read %d entries. %d errors. One or more errors occurred during the import An error occurred while trying to export the database The database has been exported to: @@ -156,6 +157,10 @@ Normal Compact Small + Unknown issuer + Unknown account name + 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 Select picture + Toggle checkboxes