From 21fd8fdd8d020e0e7d4ae4d39df55ee512eb5cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Sch=C3=A4ttgen?= Date: Sat, 20 Apr 2019 01:25:04 +0200 Subject: [PATCH] Add ability to select entries when importing Move onScroll to seperate class to avoid duplicate code Move importing logic back to the PreferencesFragment Add minor changes Add ImportEntry to properly track checked states Minor layout changes --- app/src/main/AndroidManifest.xml | 59 ++++---- .../aegis/helpers/FabScrollHelper.java | 49 +++++++ .../aegis/ui/MainActivity.java | 34 +---- .../aegis/ui/PreferencesFragment.java | 76 ++++------ .../aegis/ui/SelectEntriesActivity.java | 138 ++++++++++++++++++ .../aegis/ui/models/ImportEntry.java | 37 +++++ .../aegis/ui/views/ImportEntriesAdapter.java | 97 ++++++++++++ .../aegis/ui/views/ImportEntryHolder.java | 48 ++++++ .../main/res/drawable/ic_check_black_24dp.xml | 12 +- .../res/drawable/ic_done_all_black_24dp.xml | 5 + .../res/layout/activity_select_entries.xml | 33 +++++ app/src/main/res/layout/card_import_entry.xml | 76 ++++++++++ app/src/main/res/menu/menu_select_entries.xml | 8 + app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values/strings.xml | 7 +- 16 files changed, 569 insertions(+), 114 deletions(-) create mode 100644 app/src/main/java/com/beemdevelopment/aegis/helpers/FabScrollHelper.java create mode 100644 app/src/main/java/com/beemdevelopment/aegis/ui/SelectEntriesActivity.java create mode 100644 app/src/main/java/com/beemdevelopment/aegis/ui/models/ImportEntry.java create mode 100644 app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntriesAdapter.java create mode 100644 app/src/main/java/com/beemdevelopment/aegis/ui/views/ImportEntryHolder.java create mode 100644 app/src/main/res/drawable/ic_done_all_black_24dp.xml create mode 100644 app/src/main/res/layout/activity_select_entries.xml create mode 100644 app/src/main/res/layout/card_import_entry.xml create mode 100644 app/src/main/res/menu/menu_select_entries.xml 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